00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "at_wini.h"
00018
00019 #include <minix/sysutil.h>
00020 #include <minix/type.h>
00021 #include <minix/endpoint.h>
00022 #include <sys/ioc_disk.h>
00023 #include <ibm/pci.h>
00024 #include <sys/mman.h>
00025
00026
00027
00028
00029 struct command {
00030 u8_t precomp;
00031 u8_t count;
00032 u8_t sector;
00033 u8_t cyl_lo;
00034 u8_t cyl_hi;
00035 u8_t ldh;
00036 u8_t command;
00037
00038
00039 u8_t count_prev;
00040 u8_t sector_prev;
00041 u8_t cyl_lo_prev;
00042 u8_t cyl_hi_prev;
00043 };
00044
00045
00046 int timeout_ticks = DEF_TIMEOUT_TICKS, max_errors = MAX_ERRORS;
00047 long w_standard_timeouts = 0, w_pci_debug = 0, w_instance = 0,
00048 disable_dma = 0, atapi_debug = 0, w_identify_wakeup_ticks,
00049 wakeup_ticks, w_atapi_dma;
00050
00051 int w_testing = 0, w_silent = 0;
00052
00053 int w_next_drive = 0;
00054
00055 u32_t system_hz;
00056
00057
00058
00059
00060
00061 PRIVATE struct wini {
00062 unsigned state;
00063 unsigned short w_status;
00064 unsigned base_cmd;
00065 unsigned base_ctl;
00066 unsigned base_dma;
00067 int dma_intseen;
00068 unsigned irq;
00069 unsigned irq_need_ack;
00070 int irq_hook_id;
00071 int lba48;
00072 int dma;
00073 unsigned lcylinders;
00074 unsigned lheads;
00075 unsigned lsectors;
00076 unsigned pcylinders;
00077 unsigned pheads;
00078 unsigned psectors;
00079 unsigned ldhpref;
00080 unsigned precomp;
00081 unsigned max_count;
00082 unsigned open_ct;
00083 struct device part[DEV_PER_DRIVE];
00084 struct device subpart[SUB_PER_DRIVE];
00085 } wini[MAX_DRIVES], *w_wn;
00086
00087 PRIVATE int w_device = -1;
00088 PRIVATE int w_controller = -1;
00089 PRIVATE int w_major = -1;
00090
00091 PRIVATE int win_tasknr;
00092 PUBLIC int w_command;
00093 PRIVATE u8_t w_byteval;
00094 PRIVATE int w_drive;
00095 PRIVATE int w_controller;
00096 PRIVATE struct device *w_dv;
00097
00098
00099
00100
00101 #define ATA_DMA_SECTORS 64
00102 #define ATA_DMA_BUF_SIZE (ATA_DMA_SECTORS*SECTOR_SIZE)
00103
00104 PRIVATE char *dma_buf;
00105 PRIVATE phys_bytes dma_buf_phys;
00106
00107 #define N_PRDTE 1024
00108
00109 PRIVATE struct prdte
00110 {
00111 u32_t prdte_base;
00112 u16_t prdte_count;
00113 u8_t prdte_reserved;
00114 u8_t prdte_flags;
00115 };
00116
00117 #define PRDT_BYTES (sizeof(struct prdte) * N_PRDTE)
00118 PRIVATE struct prdte *prdt;
00119 PRIVATE phys_bytes prdt_phys;
00120
00121 #define PRDTE_FL_EOT 0x80
00122
00123
00124 PRIVATE struct
00125 {
00126 u16_t vendor;
00127 u16_t device;
00128 } raid_table[]=
00129 {
00130 { 0x1106, 0x3149 },
00131 { 0x1095, 0x3512 },
00132 { 0, 0 }
00133 };
00134
00135 FORWARD _PROTOTYPE( void init_params, (void) );
00136 FORWARD _PROTOTYPE( void init_drive, (struct wini *w, int base_cmd,
00137 int base_ctl, int base_dma, int irq, int ack, int hook,
00138 int drive) );
00139 FORWARD _PROTOTYPE( void init_params_pci, (int) );
00140 FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) );
00141 FORWARD _PROTOTYPE( struct device *w_prepare, (int dev) );
00142 FORWARD _PROTOTYPE( int w_identify, (void) );
00143 FORWARD _PROTOTYPE( char *w_name, (void) );
00144 FORWARD _PROTOTYPE( int w_specify, (void) );
00145 FORWARD _PROTOTYPE( int w_io_test, (void) );
00146 FORWARD _PROTOTYPE( int w_transfer, (int proc_nr, int opcode, u64_t position,
00147 iovec_t *iov, unsigned nr_req));
00148 FORWARD _PROTOTYPE( int com_out, (struct command *cmd) );
00149 FORWARD _PROTOTYPE( int com_out_ext, (struct command *cmd) );
00150 FORWARD _PROTOTYPE( void setup_dma, (unsigned *sizep, int proc_nr,
00151 iovec_t *iov, size_t addr_offset, int do_write,
00152 int *do_copyoutp) );
00153 FORWARD _PROTOTYPE( void w_need_reset, (void) );
00154 FORWARD _PROTOTYPE( void ack_irqs, (unsigned int) );
00155 FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
00156 FORWARD _PROTOTYPE( int w_other, (struct driver *dp, message *m_ptr) );
00157 FORWARD _PROTOTYPE( int w_hw_int, (struct driver *dp, message *m_ptr) );
00158 FORWARD _PROTOTYPE( int com_simple, (struct command *cmd) );
00159 FORWARD _PROTOTYPE( void w_timeout, (void) );
00160 FORWARD _PROTOTYPE( int w_reset, (void) );
00161 FORWARD _PROTOTYPE( void w_intr_wait, (void) );
00162 FORWARD _PROTOTYPE( int at_intr_wait, (void) );
00163 FORWARD _PROTOTYPE( int w_waitfor, (int mask, int value) );
00164 FORWARD _PROTOTYPE( int w_waitfor_dma, (int mask, int value) );
00165 FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry) );
00166 #if ENABLE_ATAPI
00167 FORWARD _PROTOTYPE( int atapi_sendpacket, (u8_t *packet, unsigned cnt, int do_dma) );
00168 FORWARD _PROTOTYPE( int atapi_intr_wait, (int dma, size_t max) );
00169 FORWARD _PROTOTYPE( int atapi_open, (void) );
00170 FORWARD _PROTOTYPE( void atapi_close, (void) );
00171 FORWARD _PROTOTYPE( int atapi_transfer, (int proc_nr, int opcode,
00172 u64_t position, iovec_t *iov, unsigned nr_req) );
00173 #endif
00174
00175 #define sys_voutb(out, n) at_voutb(__LINE__, (out), (n))
00176 FORWARD _PROTOTYPE( int at_voutb, (int line, pvb_pair_t *, int n));
00177 #define sys_vinb(in, n) at_vinb(__LINE__, (in), (n))
00178 FORWARD _PROTOTYPE( int at_vinb, (int line, pvb_pair_t *, int n));
00179
00180 #undef sys_outb
00181 #undef sys_inb
00182 #undef sys_outw
00183 #undef sys_inw
00184 #undef sys_outl
00185 #undef sys_inl
00186
00187 FORWARD _PROTOTYPE( int at_out, (int line, u32_t port, u32_t value,
00188 char *typename, int type));
00189 FORWARD _PROTOTYPE( int at_in, (int line, u32_t port, u32_t *value,
00190 char *typename, int type));
00191
00192 #define sys_outb(p, v) at_out(__LINE__, (p), (v), "outb", _DIO_BYTE)
00193 #define sys_inb(p, v) at_in(__LINE__, (p), (v), "inb", _DIO_BYTE)
00194 #define sys_outw(p, v) at_out(__LINE__, (p), (v), "outw", _DIO_WORD)
00195 #define sys_inw(p, v) at_in(__LINE__, (p), (v), "inw", _DIO_WORD)
00196 #define sys_outl(p, v) at_out(__LINE__, (p), (v), "outl", _DIO_LONG)
00197 #define sys_inl(p, v) at_in(__LINE__, (p), (v), "inl", _DIO_LONG)
00198
00199
00200 PRIVATE struct driver w_dtab = {
00201 w_name,
00202 w_do_open,
00203 w_do_close,
00204 do_diocntl,
00205 w_prepare,
00206 w_transfer,
00207 nop_cleanup,
00208 w_geometry,
00209 nop_signal,
00210 nop_alarm,
00211 nop_cancel,
00212 nop_select,
00213 w_other,
00214 w_hw_int
00215 };
00216
00217
00218 FORWARD _PROTOTYPE( void sef_local_startup, (void) );
00219 FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
00220 EXTERN _PROTOTYPE( void sef_cb_lu_prepare, (int state) );
00221 EXTERN _PROTOTYPE( int sef_cb_lu_state_isvalid, (int state) );
00222 EXTERN _PROTOTYPE( void sef_cb_lu_state_dump, (int state) );
00223
00224
00225
00226
00227 PUBLIC int main(int argc, char *argv[])
00228 {
00229
00230 env_setargs(argc, argv);
00231 sef_local_startup();
00232
00233
00234 driver_task(&w_dtab, DRIVER_STD);
00235
00236 return(OK);
00237 }
00238
00239
00240
00241
00242 PRIVATE void sef_local_startup()
00243 {
00244
00245 sef_setcb_init_fresh(sef_cb_init_fresh);
00246 sef_setcb_init_lu(sef_cb_init_fresh);
00247 sef_setcb_init_restart(sef_cb_init_fresh);
00248
00249
00250 sef_setcb_lu_prepare(sef_cb_lu_prepare);
00251 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
00252 sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
00253
00254
00255 sef_startup();
00256 }
00257
00258
00259
00260
00261 PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
00262 {
00263
00264 struct sigaction sa;
00265
00266
00267 system_hz = sys_hz();
00268
00269 init_buffer();
00270
00271 w_identify_wakeup_ticks = WAKEUP_TICKS;
00272 wakeup_ticks = WAKEUP_TICKS;
00273
00274 sa.sa_handler = SIG_MESS;
00275 sigemptyset(&sa.sa_mask);
00276 sa.sa_flags = 0;
00277 if (sigaction(SIGTERM,&sa,NULL)<0) panic("AT","sigaction failed", errno);
00278
00279
00280 init_params();
00281 signal(SIGTERM, SIG_IGN);
00282
00283 return(OK);
00284 }
00285
00286
00287
00288
00289 PRIVATE void init_params()
00290 {
00291
00292
00293 u16_t parv[2];
00294 unsigned int vector, size;
00295 int drive, nr_drives;
00296 struct wini *wn;
00297 u8_t params[16];
00298 int s;
00299 long wakeup_secs = WAKEUP_SECS;
00300
00301
00302 env_parse("ata_std_timeout", "d", 0, &w_standard_timeouts, 0, 1);
00303 env_parse("ata_pci_debug", "d", 0, &w_pci_debug, 0, 1);
00304 env_parse("ata_instance", "d", 0, &w_instance, 0, 8);
00305 env_parse(NO_DMA_VAR, "d", 0, &disable_dma, 0, 1);
00306 env_parse("ata_id_timeout", "d", 0, &wakeup_secs, 1, 60);
00307 env_parse("atapi_debug", "d", 0, &atapi_debug, 0, 1);
00308 env_parse("atapi_dma", "d", 0, &w_atapi_dma, 0, 1);
00309
00310 w_identify_wakeup_ticks = wakeup_secs * system_hz;
00311
00312 if(atapi_debug)
00313 panic("at_wini", "atapi_debug", NO_NUM);
00314
00315 if(w_identify_wakeup_ticks <= 0) {
00316 printf("changing wakeup from %d to %d ticks.\n",
00317 w_identify_wakeup_ticks, WAKEUP_TICKS);
00318 w_identify_wakeup_ticks = WAKEUP_TICKS;
00319 }
00320
00321 if (disable_dma) {
00322 printf("at_wini%d: DMA for ATA devices is disabled.\n", w_instance);
00323 } else {
00324
00325 dma_buf = mmap(0, ATA_DMA_BUF_SIZE, PROT_READ|PROT_WRITE,
00326 MAP_PREALLOC | MAP_CONTIG | MAP_ANON, -1, 0);
00327 prdt = mmap(0, PRDT_BYTES,
00328 PROT_READ|PROT_WRITE,
00329 MAP_PREALLOC | MAP_CONTIG | MAP_ANON, -1, 0);
00330 if(dma_buf == MAP_FAILED || prdt == MAP_FAILED) {
00331 disable_dma = 1;
00332 printf("at_wini%d: no dma\n", w_instance);
00333 } else {
00334 s= sys_umap(SELF, VM_D, (vir_bytes)dma_buf,
00335 ATA_DMA_BUF_SIZE, &dma_buf_phys);
00336 if (s != 0)
00337 panic("at_wini", "can't map dma buffer", s);
00338
00339 s= sys_umap(SELF, VM_D, (vir_bytes)prdt,
00340 PRDT_BYTES, &prdt_phys);
00341 if (s != 0)
00342 panic("at_wini", "can't map prd table", s);
00343 #if 0
00344 printf("at_wini%d: physical dma_buf: 0x%lx, "
00345 "prdt tab: 0x%lx\n",
00346 w_instance, dma_buf_phys, prdt_phys);
00347 #endif
00348 }
00349 }
00350
00351 if (w_instance == 0) {
00352
00353 s=sys_readbios(NR_HD_DRIVES_ADDR, params, NR_HD_DRIVES_SIZE);
00354 if (s != OK)
00355 panic(w_name(), "Couldn't read BIOS", s);
00356 if ((nr_drives = params[0]) > 2) nr_drives = 2;
00357
00358 for (drive = 0, wn = wini; drive < COMPAT_DRIVES; drive++, wn++) {
00359 if (drive < nr_drives) {
00360
00361 vector = (drive == 0) ? BIOS_HD0_PARAMS_ADDR :
00362 BIOS_HD1_PARAMS_ADDR;
00363 size = (drive == 0) ? BIOS_HD0_PARAMS_SIZE :
00364 BIOS_HD1_PARAMS_SIZE;
00365 s=sys_readbios(vector, parv, size);
00366 if (s != OK)
00367 panic(w_name(), "Couldn't read BIOS", s);
00368
00369
00370 s=sys_readbios(hclick_to_physb(parv[1]) + parv[0],
00371 params, 16L);
00372 if (s != OK)
00373 panic(w_name(),"Couldn't copy parameters", s);
00374
00375
00376 wn->lcylinders = bp_cylinders(params);
00377 wn->lheads = bp_heads(params);
00378 wn->lsectors = bp_sectors(params);
00379 wn->precomp = bp_precomp(params) >> 2;
00380 }
00381
00382
00383 init_drive(wn,
00384 drive < 2 ? REG_CMD_BASE0 : REG_CMD_BASE1,
00385 drive < 2 ? REG_CTL_BASE0 : REG_CTL_BASE1,
00386 0 , NO_IRQ, 0, 0, drive);
00387 w_next_drive++;
00388 }
00389 }
00390
00391
00392
00393
00394 if (w_instance == 0)
00395 init_params_pci(0);
00396 else
00397 init_params_pci(w_instance*2-1);
00398
00399 }
00400
00401 #define ATA_IF_NOTCOMPAT1 (1L << 0)
00402 #define ATA_IF_NOTCOMPAT2 (1L << 2)
00403
00404
00405
00406
00407 PRIVATE void init_drive(struct wini *w, int base_cmd, int base_ctl,
00408 int base_dma, int irq, int ack, int hook, int drive)
00409 {
00410 w->state = 0;
00411 w->w_status = 0;
00412 w->base_cmd = base_cmd;
00413 w->base_ctl = base_ctl;
00414 w->base_dma = base_dma;
00415 if(w_pci_debug)
00416 printf("at_wini%d: drive %d: base_cmd 0x%x, base_ctl 0x%x, base_dma 0x%x\n",
00417 w_instance, w-wini, w->base_cmd, w->base_ctl, w->base_dma);
00418 w->irq = irq;
00419 w->irq_need_ack = ack;
00420 w->irq_hook_id = hook;
00421 w->ldhpref = ldh_init(drive);
00422 w->max_count = MAX_SECS << SECTOR_SHIFT;
00423 w->lba48 = 0;
00424 w->dma = 0;
00425 }
00426
00427
00428
00429
00430 PRIVATE void init_params_pci(int skip)
00431 {
00432 int i, r, devind, drive, pci_compat = 0;
00433 int irq, irq_hook, raid;
00434 u8_t bcr, scr, interface;
00435 u16_t vid, did;
00436 u32_t base_dma, t3;
00437
00438 pci_init();
00439 for(drive = w_next_drive; drive < MAX_DRIVES; drive++)
00440 wini[drive].state = IGNORING;
00441 for(r = pci_first_dev(&devind, &vid, &did); r != 0;
00442 r = pci_next_dev(&devind, &vid, &did)) {
00443
00444 raid= 0;
00445
00446
00447
00448
00449 bcr= pci_attr_r8(devind, PCI_BCR);
00450 scr= pci_attr_r8(devind, PCI_SCR);
00451 interface= pci_attr_r8(devind, PCI_PIFR);
00452 t3= ((bcr << 16) | (scr << 8) | interface);
00453 if (bcr == PCI_BCR_MASS_STORAGE && scr == PCI_MS_IDE)
00454 ;
00455 else if (t3 == PCI_T3_RAID)
00456 {
00457 for (i= 0; raid_table[i].vendor != 0; i++)
00458 {
00459 if (raid_table[i].vendor == vid &&
00460 raid_table[i].device == did)
00461 {
00462 break;
00463 }
00464 }
00465 if (raid_table[i].vendor == 0)
00466 {
00467 printf(
00468 "atapci skipping unsupported RAID controller 0x%04x / 0x%04x\n",
00469 vid, did);
00470 continue;
00471 }
00472 printf("found supported RAID controller\n");
00473 raid= 1;
00474 }
00475 else
00476 continue;
00477
00478
00479
00480
00481 irq = pci_attr_r8(devind, PCI_ILR);
00482
00483
00484 if (raid || (interface & (ATA_IF_NOTCOMPAT1 | ATA_IF_NOTCOMPAT2))) {
00485 if (w_next_drive >= MAX_DRIVES)
00486 {
00487
00488
00489
00490 continue;
00491 }
00492
00493 irq_hook = irq;
00494 if (skip > 0) {
00495 if (w_pci_debug)
00496 {
00497 printf(
00498 "atapci skipping controller (remain %d)\n",
00499 skip);
00500 }
00501 skip--;
00502 continue;
00503 }
00504 if(pci_reserve_ok(devind) != OK) {
00505 printf("at_wini%d: pci_reserve %d failed - "
00506 "ignoring controller!\n",
00507 w_instance, devind);
00508 continue;
00509 }
00510 if (sys_irqsetpolicy(irq, 0, &irq_hook) != OK) {
00511 printf("atapci: couldn't set IRQ policy %d\n", irq);
00512 continue;
00513 }
00514 if (sys_irqenable(&irq_hook) != OK) {
00515 printf("atapci: couldn't enable IRQ line %d\n", irq);
00516 continue;
00517 }
00518 } else if(w_pci_debug) printf("at_wini%d: dev %d: only compat drives\n", w_instance, devind);
00519
00520 base_dma = pci_attr_r32(devind, PCI_BAR_5) & 0xfffffffc;
00521
00522
00523 if (raid || (interface & ATA_IF_NOTCOMPAT1)) {
00524 u32_t base_cmd, base_ctl;
00525
00526 base_cmd = pci_attr_r32(devind, PCI_BAR) & 0xfffffffc;
00527 base_ctl = pci_attr_r32(devind, PCI_BAR_2) & 0xfffffffc;
00528 if (base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) {
00529 init_drive(&wini[w_next_drive],
00530 base_cmd, base_ctl+PCI_CTL_OFF,
00531 base_dma, irq, 1, irq_hook, 0);
00532 init_drive(&wini[w_next_drive+1],
00533 base_cmd, base_ctl+PCI_CTL_OFF,
00534 base_dma, irq, 1, irq_hook, 1);
00535 if (w_pci_debug)
00536 printf("at_wini%d: atapci %d: 0x%x 0x%x irq %d\n", w_instance, devind, base_cmd, base_ctl, irq);
00537 w_next_drive += 2;
00538 } else printf("at_wini%d: atapci: ignored drives on primary channel, base %x\n", w_instance, base_cmd);
00539 }
00540 else
00541 {
00542
00543 for (i= 0; i<MAX_DRIVES; i++)
00544 {
00545 if (wini[i].base_cmd == REG_CMD_BASE0) {
00546 wini[i].base_dma= base_dma;
00547 if(w_pci_debug)
00548 printf("at_wini%d: drive %d: base_dma 0x%x\n",
00549 w_instance, i, wini[i].base_dma);
00550 pci_compat = 1;
00551 }
00552 }
00553 }
00554
00555
00556 if (raid || (interface & ATA_IF_NOTCOMPAT2)) {
00557 u32_t base_cmd, base_ctl;
00558
00559 base_cmd = pci_attr_r32(devind, PCI_BAR_3) & 0xfffffffc;
00560 base_ctl = pci_attr_r32(devind, PCI_BAR_4) & 0xfffffffc;
00561 if (base_dma != 0)
00562 base_dma += PCI_DMA_2ND_OFF;
00563 if (base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) {
00564 init_drive(&wini[w_next_drive],
00565 base_cmd, base_ctl+PCI_CTL_OFF, base_dma,
00566 irq, 1, irq_hook, 2);
00567 init_drive(&wini[w_next_drive+1],
00568 base_cmd, base_ctl+PCI_CTL_OFF, base_dma,
00569 irq, 1, irq_hook, 3);
00570 if (w_pci_debug)
00571 printf("at_wini%d: atapci %d: 0x%x 0x%x irq %d\n",
00572 w_instance, devind, base_cmd, base_ctl, irq);
00573 w_next_drive += 2;
00574 } else printf("at_wini%d: atapci: ignored drives on "
00575 "secondary channel, base %x\n", w_instance, base_cmd);
00576 }
00577 else
00578 {
00579
00580 for (i= 0; i<MAX_DRIVES; i++)
00581 {
00582 if (wini[i].base_cmd == REG_CMD_BASE1 && base_dma != 0) {
00583 wini[i].base_dma= base_dma+PCI_DMA_2ND_OFF;
00584 if (w_pci_debug)
00585 printf("at_wini%d: drive %d: base_dma 0x%x\n",
00586 w_instance, i, wini[i].base_dma);
00587 pci_compat = 1;
00588 }
00589 }
00590 }
00591
00592 if(pci_compat) {
00593 if(pci_reserve_ok(devind) != OK) {
00594 printf("at_wini%d (compat): pci_reserve %d failed!\n",
00595 w_instance, devind);
00596 }
00597 }
00598 }
00599 }
00600
00601
00602
00603
00604 PRIVATE int w_do_open(dp, m_ptr)
00605 struct driver *dp;
00606 message *m_ptr;
00607 {
00608
00609
00610 struct wini *wn;
00611
00612 if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
00613
00614 wn = w_wn;
00615
00616
00617 if (wn->state & IGNORING) return ENXIO;
00618
00619
00620
00621
00622 if (!(wn->state & IDENTIFIED) || (wn->state & DEAF)) {
00623
00624 if (w_identify() != OK) {
00625 #if VERBOSE
00626 printf("%s: probe failed\n", w_name());
00627 #endif
00628 if (wn->state & DEAF) w_reset();
00629 wn->state = IGNORING;
00630 return(ENXIO);
00631 }
00632
00633
00634
00635
00636
00637 if (!(wn->state & ATAPI) && w_io_test() != OK) {
00638 wn->state |= IGNORING;
00639 return(ENXIO);
00640 }
00641 }
00642
00643 #if ENABLE_ATAPI
00644 if ((wn->state & ATAPI) && (m_ptr->COUNT & W_BIT))
00645 return(EACCES);
00646 #endif
00647
00648
00649
00650
00651 if (wn->open_ct == 0) {
00652 #if ENABLE_ATAPI
00653 if (wn->state & ATAPI) {
00654 int r;
00655 if ((r = atapi_open()) != OK) return(r);
00656 }
00657 #endif
00658
00659
00660 partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY, wn->state & ATAPI);
00661 }
00662 wn->open_ct++;
00663 return(OK);
00664 }
00665
00666
00667
00668
00669 PRIVATE struct device *w_prepare(int device)
00670 {
00671
00672 w_device = device;
00673
00674 if (device < NR_MINORS) {
00675 w_drive = device / DEV_PER_DRIVE;
00676 w_wn = &wini[w_drive];
00677 w_dv = &w_wn->part[device % DEV_PER_DRIVE];
00678 } else
00679 if ((unsigned) (device -= MINOR_d0p0s0) < NR_SUBDEVS) {
00680 w_drive = device / SUB_PER_DRIVE;
00681 w_wn = &wini[w_drive];
00682 w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
00683 } else {
00684 w_device = -1;
00685 return(NIL_DEV);
00686 }
00687 return(w_dv);
00688 }
00689
00690 #define id_byte(n) (&tmp_buf[2 * (n)])
00691 #define id_word(n) (((u16_t) id_byte(n)[0] << 0) \
00692 |((u16_t) id_byte(n)[1] << 8))
00693 #define id_longword(n) (((u32_t) id_byte(n)[0] << 0) \
00694 |((u32_t) id_byte(n)[1] << 8) \
00695 |((u32_t) id_byte(n)[2] << 16) \
00696 |((u32_t) id_byte(n)[3] << 24))
00697
00698
00699
00700
00701 void
00702 check_dma(struct wini *wn)
00703 {
00704 unsigned long dma_status = 0;
00705 u32_t dma_base;
00706 int id_dma, ultra_dma;
00707 u16_t w;
00708
00709 wn->dma= 0;
00710
00711 if (disable_dma)
00712 return;
00713
00714 w= id_word(ID_CAPABILITIES);
00715 id_dma= !!(w & ID_CAP_DMA);
00716 w= id_byte(ID_FIELD_VALIDITY)[0];
00717 ultra_dma= !!(w & ID_FV_88);
00718 dma_base= wn->base_dma;
00719
00720 if (dma_base) {
00721 if (sys_inb(dma_base + DMA_STATUS, &dma_status) != OK) {
00722 panic(w_name(),
00723 "unable to read DMA status register",
00724 NO_NUM);
00725 }
00726 }
00727
00728 if (id_dma && dma_base) {
00729 w= id_word(ID_MULTIWORD_DMA);
00730 if (w_pci_debug &&
00731 (w & (ID_MWDMA_2_SUP|ID_MWDMA_1_SUP|ID_MWDMA_0_SUP))) {
00732 printf(
00733 "%s: multiword DMA modes supported:%s%s%s\n",
00734 w_name(),
00735 (w & ID_MWDMA_0_SUP) ? " 0" : "",
00736 (w & ID_MWDMA_1_SUP) ? " 1" : "",
00737 (w & ID_MWDMA_2_SUP) ? " 2" : "");
00738 }
00739 if (w_pci_debug &&
00740 (w & (ID_MWDMA_0_SEL|ID_MWDMA_1_SEL|ID_MWDMA_2_SEL))) {
00741 printf(
00742 "%s: multiword DMA mode selected:%s%s%s\n",
00743 w_name(),
00744 (w & ID_MWDMA_0_SEL) ? " 0" : "",
00745 (w & ID_MWDMA_1_SEL) ? " 1" : "",
00746 (w & ID_MWDMA_2_SEL) ? " 2" : "");
00747 }
00748 if (w_pci_debug && ultra_dma) {
00749 w= id_word(ID_ULTRA_DMA);
00750 if (w & (ID_UDMA_0_SUP|ID_UDMA_1_SUP|
00751 ID_UDMA_2_SUP|ID_UDMA_3_SUP|
00752 ID_UDMA_4_SUP|ID_UDMA_5_SUP)) {
00753 printf(
00754 "%s: Ultra DMA modes supported:%s%s%s%s%s%s\n",
00755 w_name(),
00756 (w & ID_UDMA_0_SUP) ? " 0" : "",
00757 (w & ID_UDMA_1_SUP) ? " 1" : "",
00758 (w & ID_UDMA_2_SUP) ? " 2" : "",
00759 (w & ID_UDMA_3_SUP) ? " 3" : "",
00760 (w & ID_UDMA_4_SUP) ? " 4" : "",
00761 (w & ID_UDMA_5_SUP) ? " 5" : "");
00762 }
00763 if (w & (ID_UDMA_0_SEL|ID_UDMA_1_SEL|
00764 ID_UDMA_2_SEL|ID_UDMA_3_SEL|
00765 ID_UDMA_4_SEL|ID_UDMA_5_SEL)) {
00766 printf(
00767 "%s: Ultra DMA mode selected:%s%s%s%s%s%s\n",
00768 w_name(),
00769 (w & ID_UDMA_0_SEL) ? " 0" : "",
00770 (w & ID_UDMA_1_SEL) ? " 1" : "",
00771 (w & ID_UDMA_2_SEL) ? " 2" : "",
00772 (w & ID_UDMA_3_SEL) ? " 3" : "",
00773 (w & ID_UDMA_4_SEL) ? " 4" : "",
00774 (w & ID_UDMA_5_SEL) ? " 5" : "");
00775 }
00776 }
00777 wn->dma= 1;
00778 } else if (id_dma || dma_base) {
00779 printf("id_dma %d, dma_base 0x%x\n", id_dma, dma_base);
00780 } else
00781 printf("no DMA support\n");
00782 }
00783
00784
00785
00786
00787 PRIVATE int w_identify()
00788 {
00789
00790
00791
00792
00793 struct wini *wn = w_wn;
00794 struct command cmd;
00795 int s;
00796 u16_t w;
00797 unsigned long size;
00798 int prev_wakeup;
00799 int r;
00800
00801
00802 cmd.ldh = wn->ldhpref;
00803 cmd.command = ATA_IDENTIFY;
00804
00805
00806 w_testing = 1;
00807
00808
00809 prev_wakeup = wakeup_ticks;
00810 wakeup_ticks = w_identify_wakeup_ticks;
00811 r = com_simple(&cmd);
00812
00813 if (r == OK && w_waitfor(STATUS_DRQ, STATUS_DRQ) &&
00814 !(wn->w_status & (STATUS_ERR|STATUS_WF))) {
00815
00816
00817 if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, SECTOR_SIZE)) != OK)
00818 panic(w_name(),"Call to sys_insw() failed", s);
00819
00820 #if 0
00821 if (id_word(0) & ID_GEN_NOT_ATA)
00822 {
00823 printf("%s: not an ATA device?\n", w_name());
00824 wakeup_ticks = prev_wakeup;
00825 w_testing = 0;
00826 return ERR;
00827 }
00828 #endif
00829
00830
00831 wn->state |= SMART;
00832
00833
00834 wn->pcylinders = id_word(1);
00835 wn->pheads = id_word(3);
00836 wn->psectors = id_word(6);
00837 size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
00838
00839 w= id_word(ID_CAPABILITIES);
00840 if ((w & ID_CAP_LBA) && size > 512L*1024*2) {
00841
00842
00843
00844 wn->ldhpref |= LDH_LBA;
00845 size = id_longword(60);
00846
00847 w= id_word(ID_CSS);
00848 if (size < LBA48_CHECK_SIZE)
00849 {
00850
00851 }
00852 else if (w & ID_CSS_LBA48) {
00853
00854 if (id_longword(102)) {
00855
00856
00857
00858
00859
00860 size = ULONG_MAX;
00861 } else {
00862
00863 size = id_longword(100);
00864 }
00865 wn->lba48 = 1;
00866 }
00867
00868 check_dma(wn);
00869 }
00870
00871 if (wn->lcylinders == 0 || wn->lheads == 0 || wn->lsectors == 0) {
00872
00873 wn->lcylinders = wn->pcylinders;
00874 wn->lheads = wn->pheads;
00875 wn->lsectors = wn->psectors;
00876 while (wn->lcylinders > 1024) {
00877 wn->lheads *= 2;
00878 wn->lcylinders /= 2;
00879 }
00880 }
00881 #if ENABLE_ATAPI
00882 } else
00883 if (cmd.command = ATAPI_IDENTIFY,
00884 com_simple(&cmd) == OK && w_waitfor(STATUS_DRQ, STATUS_DRQ) &&
00885 !(wn->w_status & (STATUS_ERR|STATUS_WF))) {
00886
00887 wn->state |= ATAPI;
00888
00889
00890 if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, 512)) != OK)
00891 panic(w_name(),"Call to sys_insw() failed", s);
00892
00893 size = 0;
00894 check_dma(wn);
00895 #endif
00896 } else {
00897
00898
00899
00900 if (wn->lcylinders == 0) {
00901 wakeup_ticks = prev_wakeup;
00902 w_testing = 0;
00903 return(ERR);
00904 }
00905 wn->pcylinders = wn->lcylinders;
00906 wn->pheads = wn->lheads;
00907 wn->psectors = wn->lsectors;
00908 size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
00909 }
00910
00911
00912 wakeup_ticks = prev_wakeup;
00913 w_testing = 0;
00914
00915
00916 wn->part[0].dv_size = mul64u(size, SECTOR_SIZE);
00917
00918
00919 if (w_specify() != OK && w_specify() != OK) {
00920 return(ERR);
00921 }
00922
00923 if (wn->irq == NO_IRQ) {
00924
00925 wn->irq = w_drive < 2 ? AT_WINI_0_IRQ : AT_WINI_1_IRQ;
00926 wn->irq_hook_id = wn->irq;
00927 if ((s=sys_irqsetpolicy(wn->irq, IRQ_REENABLE, &wn->irq_hook_id)) != OK)
00928 panic(w_name(), "couldn't set IRQ policy", s);
00929 if ((s=sys_irqenable(&wn->irq_hook_id)) != OK)
00930 panic(w_name(), "couldn't enable IRQ line", s);
00931 }
00932 wn->state |= IDENTIFIED;
00933 return(OK);
00934 }
00935
00936
00937
00938
00939 PRIVATE char *w_name()
00940 {
00941
00942 static char name[] = "AT0-D0";
00943
00944 name[2] = '0' + w_instance;
00945 name[5] = '0' + w_drive;
00946 return name;
00947 }
00948
00949
00950
00951
00952 PRIVATE int w_io_test(void)
00953 {
00954 int r, save_dev;
00955 int save_timeout, save_errors, save_wakeup;
00956 iovec_t iov;
00957 static char *buf;
00958
00959 #ifdef CD_SECTOR_SIZE
00960 #define BUFSIZE CD_SECTOR_SIZE
00961 #else
00962 #define BUFSIZE SECTOR_SIZE
00963 #endif
00964 STATICINIT(buf, BUFSIZE);
00965
00966 iov.iov_addr = (vir_bytes) buf;
00967 iov.iov_size = BUFSIZE;
00968 save_dev = w_device;
00969
00970
00971 save_timeout = timeout_ticks;
00972 save_errors = max_errors;
00973 save_wakeup = wakeup_ticks;
00974
00975 if (!w_standard_timeouts) {
00976 timeout_ticks = system_hz * 4;
00977 wakeup_ticks = system_hz * 6;
00978 max_errors = 3;
00979 }
00980
00981 w_testing = 1;
00982
00983
00984 if (w_prepare(w_drive * DEV_PER_DRIVE) == NIL_DEV)
00985 panic(w_name(), "Couldn't switch devices", NO_NUM);
00986
00987 r = w_transfer(SELF, DEV_GATHER_S, cvu64(0), &iov, 1);
00988
00989
00990 if (w_prepare(save_dev) == NIL_DEV)
00991 panic(w_name(), "Couldn't switch back devices", NO_NUM);
00992
00993
00994 timeout_ticks = save_timeout;
00995 max_errors = save_errors;
00996 wakeup_ticks = save_wakeup;
00997 w_testing = 0;
00998
00999
01000 if (r != OK || iov.iov_size != 0) {
01001 return ERR;
01002 }
01003
01004
01005
01006 return OK;
01007 }
01008
01009
01010
01011
01012 PRIVATE int w_specify()
01013 {
01014
01015
01016 struct wini *wn = w_wn;
01017 struct command cmd;
01018
01019 if ((wn->state & DEAF) && w_reset() != OK) {
01020 return(ERR);
01021 }
01022
01023 if (!(wn->state & ATAPI)) {
01024
01025 cmd.precomp = wn->precomp;
01026 cmd.count = wn->psectors;
01027 cmd.ldh = w_wn->ldhpref | (wn->pheads - 1);
01028 cmd.command = CMD_SPECIFY;
01029
01030
01031 if (com_simple(&cmd) != OK) return(ERR);
01032
01033 if (!(wn->state & SMART)) {
01034
01035 cmd.sector = 0;
01036 cmd.cyl_lo = 0;
01037 cmd.cyl_hi = 0;
01038 cmd.ldh = w_wn->ldhpref;
01039 cmd.command = CMD_RECALIBRATE;
01040
01041 if (com_simple(&cmd) != OK) return(ERR);
01042 }
01043 }
01044 wn->state |= INITIALIZED;
01045 return(OK);
01046 }
01047
01048
01049
01050
01051 PRIVATE int do_transfer(struct wini *wn, unsigned int precomp,
01052 unsigned int count, unsigned int sector,
01053 unsigned int opcode, int do_dma)
01054 {
01055 struct command cmd;
01056 unsigned int sector_high;
01057 unsigned secspcyl = wn->pheads * wn->psectors;
01058 int do_lba48;
01059
01060 sector_high= 0;
01061
01062 do_lba48= 0;
01063 if (sector >= LBA48_CHECK_SIZE || sector_high != 0)
01064 {
01065 if (wn->lba48)
01066 do_lba48= 1;
01067 else if (sector > LBA_MAX_SIZE || sector_high != 0)
01068 {
01069
01070 return EIO;
01071 }
01072 }
01073
01074 cmd.precomp = precomp;
01075 cmd.count = count;
01076 if (do_dma)
01077 {
01078 cmd.command = opcode == DEV_SCATTER_S ? CMD_WRITE_DMA :
01079 CMD_READ_DMA;
01080 }
01081 else
01082 cmd.command = opcode == DEV_SCATTER_S ? CMD_WRITE : CMD_READ;
01083
01084 if (do_lba48) {
01085 if (do_dma)
01086 {
01087 cmd.command = ((opcode == DEV_SCATTER_S) ?
01088 CMD_WRITE_DMA_EXT : CMD_READ_DMA_EXT);
01089 }
01090 else
01091 {
01092 cmd.command = ((opcode == DEV_SCATTER_S) ?
01093 CMD_WRITE_EXT : CMD_READ_EXT);
01094 }
01095 cmd.count_prev= (count >> 8);
01096 cmd.sector = (sector >> 0) & 0xFF;
01097 cmd.cyl_lo = (sector >> 8) & 0xFF;
01098 cmd.cyl_hi = (sector >> 16) & 0xFF;
01099 cmd.sector_prev= (sector >> 24) & 0xFF;
01100 cmd.cyl_lo_prev= (sector_high) & 0xFF;
01101 cmd.cyl_hi_prev= (sector_high >> 8) & 0xFF;
01102 cmd.ldh = wn->ldhpref;
01103
01104 return com_out_ext(&cmd);
01105 } else if (wn->ldhpref & LDH_LBA) {
01106 cmd.sector = (sector >> 0) & 0xFF;
01107 cmd.cyl_lo = (sector >> 8) & 0xFF;
01108 cmd.cyl_hi = (sector >> 16) & 0xFF;
01109 cmd.ldh = wn->ldhpref | ((sector >> 24) & 0xF);
01110 } else {
01111 int cylinder, head, sec;
01112 cylinder = sector / secspcyl;
01113 head = (sector % secspcyl) / wn->psectors;
01114 sec = sector % wn->psectors;
01115 cmd.sector = sec + 1;
01116 cmd.cyl_lo = cylinder & BYTE;
01117 cmd.cyl_hi = (cylinder >> 8) & BYTE;
01118 cmd.ldh = wn->ldhpref | head;
01119 }
01120
01121 return com_out(&cmd);
01122 }
01123
01124 void stop_dma(struct wini *wn)
01125 {
01126 int r;
01127
01128
01129 r= sys_outb(wn->base_dma + DMA_COMMAND, 0);
01130 if (r != 0) panic("at_wini", "stop_dma: sys_outb failed", r);
01131 }
01132
01133 void start_dma(struct wini *wn, int do_write)
01134 {
01135 u32_t v;
01136 int r;
01137
01138
01139 v= DMA_CMD_START;
01140 if (!do_write)
01141 {
01142
01143 v |= DMA_CMD_WRITE;
01144 }
01145 r= sys_outb(wn->base_dma + DMA_COMMAND, v);
01146 if (r != 0) panic("at_wini", "start_dma: sys_outb failed", r);
01147 }
01148
01149 int error_dma(struct wini *wn)
01150 {
01151 int r;
01152 u32_t v;
01153
01154 #define DMAERR(msg) \
01155 printf("at_wini%d: bad DMA: %s. Disabling DMA for drive %d.\n", \
01156 w_instance, msg, wn - wini); \
01157 printf("at_wini%d: workaround: set %s=1 in boot monitor.\n", \
01158 w_instance, NO_DMA_VAR); \
01159 return 1; \
01160
01161 r= sys_inb(wn->base_dma + DMA_STATUS, &v);
01162 if (r != 0) panic("at_wini", "w_transfer: sys_inb failed", r);
01163
01164 if (!wn->dma_intseen) {
01165
01166 if (v & DMA_ST_BM_ACTIVE) {
01167 DMAERR("DMA did not complete");
01168 } else if (v & DMA_ST_ERROR) {
01169 DMAERR("DMA error");
01170 } else {
01171 DMAERR("DMA buffer too small");
01172 }
01173 } else if ((v & DMA_ST_BM_ACTIVE)) {
01174 DMAERR("DMA buffer too large");
01175 }
01176
01177 return 0;
01178 }
01179
01180
01181
01182
01183
01184 PRIVATE int w_transfer(proc_nr, opcode, position, iov, nr_req)
01185 int proc_nr;
01186 int opcode;
01187 u64_t position;
01188 iovec_t *iov;
01189 unsigned nr_req;
01190 {
01191 struct wini *wn = w_wn;
01192 iovec_t *iop, *iov_end = iov + nr_req;
01193 int n, r, s, errors, do_dma, do_write, do_copyout;
01194 unsigned long block, w_status;
01195 u64_t dv_size = w_dv->dv_size;
01196 unsigned nbytes;
01197 unsigned dma_buf_offset;
01198 size_t addr_offset = 0;
01199
01200 #if ENABLE_ATAPI
01201 if (w_wn->state & ATAPI) {
01202 return atapi_transfer(proc_nr, opcode, position, iov, nr_req);
01203 }
01204 #endif
01205
01206
01207 if (rem64u(position, SECTOR_SIZE) != 0) return(EINVAL);
01208
01209 errors = 0;
01210
01211 while (nr_req > 0) {
01212
01213 nbytes = 0;
01214 for (iop = iov; iop < iov_end; iop++) nbytes += iop->iov_size;
01215 if ((nbytes & SECTOR_MASK) != 0) return(EINVAL);
01216
01217
01218 if (cmp64(position, dv_size) >= 0) return(OK);
01219 if (cmp64(add64ul(position, nbytes), dv_size) > 0)
01220 nbytes = diff64(dv_size, position);
01221 block = div64u(add64(w_dv->dv_base, position), SECTOR_SIZE);
01222
01223 do_write= (opcode == DEV_SCATTER_S);
01224 do_dma= wn->dma;
01225
01226 if (nbytes >= wn->max_count) {
01227
01228 nbytes = wn->max_count;
01229 }
01230
01231
01232 if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO);
01233
01234 if (do_dma) {
01235 stop_dma(wn);
01236 setup_dma(&nbytes, proc_nr, iov, addr_offset, do_write,
01237 &do_copyout);
01238 #if 0
01239 printf("nbytes = %d\n", nbytes);
01240 #endif
01241 }
01242
01243
01244 r = do_transfer(wn, wn->precomp, (nbytes >> SECTOR_SHIFT),
01245 block, opcode, do_dma);
01246
01247 if (do_dma)
01248 start_dma(wn, do_write);
01249
01250 if (opcode == DEV_SCATTER_S) {
01251
01252
01253
01254
01255 if (sys_inb((wn->base_ctl+REG_CTL_ALTSTAT), &w_status) != OK)
01256 panic(w_name(), "couldn't get status", NO_NUM);
01257 }
01258
01259 if (do_dma) {
01260
01261
01262
01263
01264 wn->dma_intseen = 0;
01265 if ((r = at_intr_wait()) != OK)
01266 {
01267
01268
01269
01270 if (r == ERR_BAD_SECTOR || ++errors == max_errors) {
01271 w_command = CMD_IDLE;
01272 return(EIO);
01273 }
01274 continue;
01275 }
01276
01277
01278 if(!wn->dma_intseen) {
01279 if(w_waitfor_dma(DMA_ST_INT, DMA_ST_INT))
01280 wn->dma_intseen = 1;
01281 }
01282
01283 if(error_dma(wn)) {
01284 wn->dma = 0;
01285 continue;
01286 }
01287
01288 stop_dma(wn);
01289
01290 dma_buf_offset= 0;
01291 while (r == OK && nbytes > 0)
01292 {
01293 n= iov->iov_size;
01294 if (n > nbytes)
01295 n= nbytes;
01296
01297 if (do_copyout)
01298 {
01299 if(proc_nr != SELF) {
01300 s= sys_safecopyto(proc_nr, iov->iov_addr,
01301 addr_offset,
01302 (vir_bytes)dma_buf+dma_buf_offset, n, D);
01303 if (s != OK)
01304 {
01305 panic(w_name(),
01306 "w_transfer: sys_vircopy failed",
01307 s);
01308 }
01309 } else {
01310 memcpy((char *) iov->iov_addr + addr_offset,
01311 dma_buf + dma_buf_offset, n);
01312 }
01313 }
01314
01315
01316 nbytes -= n;
01317 position= add64ul(position, n);
01318 addr_offset += n;
01319 if ((iov->iov_size -= n) == 0) {
01320 iov++; nr_req--; addr_offset = 0;
01321 }
01322 dma_buf_offset += n;
01323 }
01324 }
01325
01326 while (r == OK && nbytes > 0) {
01327
01328
01329
01330
01331
01332 if (opcode == DEV_GATHER_S) {
01333
01334 if ((r = at_intr_wait()) != OK) {
01335
01336 if (w_wn->w_status & STATUS_DRQ) {
01337 if ((s=sys_insw(wn->base_cmd+REG_DATA,
01338 SELF, tmp_buf,
01339 SECTOR_SIZE)) != OK)
01340 {
01341 panic(w_name(),
01342 "Call to sys_insw() failed",
01343 s);
01344 }
01345 }
01346 break;
01347 }
01348 }
01349
01350
01351 if (!w_waitfor(STATUS_BSY, 0)) { r = ERR; break; }
01352
01353
01354 if (!w_waitfor(STATUS_DRQ, STATUS_DRQ)) { r = ERR; break; }
01355
01356
01357 if (opcode == DEV_GATHER_S) {
01358 if(proc_nr != SELF) {
01359 s=sys_safe_insw(wn->base_cmd + REG_DATA, proc_nr,
01360 (void *) (iov->iov_addr), addr_offset,
01361 SECTOR_SIZE);
01362 } else {
01363 s=sys_insw(wn->base_cmd + REG_DATA, proc_nr,
01364 (void *) (iov->iov_addr + addr_offset),
01365 SECTOR_SIZE);
01366 }
01367 if(s != OK) {
01368 panic(w_name(),"Call to sys_insw() failed", s);
01369 }
01370 } else {
01371 if(proc_nr != SELF) {
01372 s=sys_safe_outsw(wn->base_cmd + REG_DATA, proc_nr,
01373 (void *) (iov->iov_addr), addr_offset,
01374 SECTOR_SIZE);
01375 } else {
01376 s=sys_outsw(wn->base_cmd + REG_DATA, proc_nr,
01377 (void *) (iov->iov_addr + addr_offset),
01378 SECTOR_SIZE);
01379 }
01380
01381 if(s != OK) {
01382 panic(w_name(),"Call to sys_outsw() failed", s);
01383 }
01384
01385
01386 if ((r = at_intr_wait()) != OK) break;
01387 }
01388
01389
01390 nbytes -= SECTOR_SIZE;
01391 position= add64u(position, SECTOR_SIZE);
01392 addr_offset += SECTOR_SIZE;
01393 if ((iov->iov_size -= SECTOR_SIZE) == 0) {
01394 iov++;
01395 nr_req--;
01396 addr_offset = 0;
01397 }
01398 }
01399
01400
01401 if (r != OK) {
01402
01403 if (r == ERR_BAD_SECTOR || ++errors == max_errors) {
01404 w_command = CMD_IDLE;
01405 return(EIO);
01406 }
01407 }
01408 }
01409
01410 w_command = CMD_IDLE;
01411 return(OK);
01412 }
01413
01414
01415
01416
01417 PRIVATE int com_out(cmd)
01418 struct command *cmd;
01419 {
01420
01421
01422 struct wini *wn = w_wn;
01423 unsigned base_cmd = wn->base_cmd;
01424 unsigned base_ctl = wn->base_ctl;
01425 pvb_pair_t outbyte[7];
01426 int s;
01427
01428 if (w_wn->state & IGNORING) return ERR;
01429
01430 if (!w_waitfor(STATUS_BSY, 0)) {
01431 printf("%s: controller not ready\n", w_name());
01432 return(ERR);
01433 }
01434
01435
01436 if ((s=sys_outb(base_cmd + REG_LDH, cmd->ldh)) != OK)
01437 panic(w_name(),"Couldn't write register to select drive",s);
01438
01439 if (!w_waitfor(STATUS_BSY, 0)) {
01440 printf("%s: com_out: drive not ready\n", w_name());
01441 return(ERR);
01442 }
01443
01444
01445
01446
01447
01448
01449 sys_setalarm(wakeup_ticks, 0);
01450
01451 wn->w_status = STATUS_ADMBSY;
01452 w_command = cmd->command;
01453 pv_set(outbyte[0], base_ctl + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS : 0);
01454 pv_set(outbyte[1], base_cmd + REG_PRECOMP, cmd->precomp);
01455 pv_set(outbyte[2], base_cmd + REG_COUNT, cmd->count);
01456 pv_set(outbyte[3], base_cmd + REG_SECTOR, cmd->sector);
01457 pv_set(outbyte[4], base_cmd + REG_CYL_LO, cmd->cyl_lo);
01458 pv_set(outbyte[5], base_cmd + REG_CYL_HI, cmd->cyl_hi);
01459 pv_set(outbyte[6], base_cmd + REG_COMMAND, cmd->command);
01460 if ((s=sys_voutb(outbyte,7)) != OK)
01461 panic(w_name(),"Couldn't write registers with sys_voutb()",s);
01462 return(OK);
01463 }
01464
01465
01466
01467
01468 PRIVATE int com_out_ext(cmd)
01469 struct command *cmd;
01470 {
01471
01472
01473 struct wini *wn = w_wn;
01474 unsigned base_cmd = wn->base_cmd;
01475 unsigned base_ctl = wn->base_ctl;
01476 pvb_pair_t outbyte[11];
01477 int s;
01478
01479 if (w_wn->state & IGNORING) return ERR;
01480
01481 if (!w_waitfor(STATUS_BSY, 0)) {
01482 printf("%s: controller not ready\n", w_name());
01483 return(ERR);
01484 }
01485
01486
01487 if ((s=sys_outb(base_cmd + REG_LDH, cmd->ldh)) != OK)
01488 panic(w_name(),"Couldn't write register to select drive",s);
01489
01490 if (!w_waitfor(STATUS_BSY, 0)) {
01491 printf("%s: com_out: drive not ready\n", w_name());
01492 return(ERR);
01493 }
01494
01495
01496
01497
01498
01499
01500 sys_setalarm(wakeup_ticks, 0);
01501
01502 wn->w_status = STATUS_ADMBSY;
01503 w_command = cmd->command;
01504 pv_set(outbyte[0], base_ctl + REG_CTL, 0);
01505 pv_set(outbyte[1], base_cmd + REG_COUNT, cmd->count_prev);
01506 pv_set(outbyte[2], base_cmd + REG_SECTOR, cmd->sector_prev);
01507 pv_set(outbyte[3], base_cmd + REG_CYL_LO, cmd->cyl_lo_prev);
01508 pv_set(outbyte[4], base_cmd + REG_CYL_HI, cmd->cyl_hi_prev);
01509 pv_set(outbyte[5], base_cmd + REG_COUNT, cmd->count);
01510 pv_set(outbyte[6], base_cmd + REG_SECTOR, cmd->sector);
01511 pv_set(outbyte[7], base_cmd + REG_CYL_LO, cmd->cyl_lo);
01512 pv_set(outbyte[8], base_cmd + REG_CYL_HI, cmd->cyl_hi);
01513 pv_set(outbyte[9], base_cmd + REG_COMMAND, cmd->command);
01514 if ((s=sys_voutb(outbyte, 10)) != OK)
01515 panic(w_name(),"Couldn't write registers with sys_voutb()",s);
01516
01517 return(OK);
01518 }
01519
01520
01521
01522 PRIVATE void setup_dma(sizep, proc_nr, iov, addr_offset, do_write,
01523 do_copyoutp)
01524 unsigned *sizep;
01525 int proc_nr;
01526 iovec_t *iov;
01527 size_t addr_offset;
01528 int do_write;
01529 int *do_copyoutp;
01530 {
01531 phys_bytes phys, user_phys;
01532 unsigned n, offset, size;
01533 int i, j, r, bad;
01534 unsigned long v;
01535 struct wini *wn = w_wn;
01536 int verbose = 0;
01537
01538
01539 size= *sizep;
01540 i= 0;
01541 j= 0;
01542 bad= 0;
01543 offset= 0;
01544
01545 if(verbose)
01546 printf("at_wini: setup_dma: proc_nr %d\n", proc_nr);
01547
01548 while (size > 0)
01549 {
01550 if(verbose) {
01551 printf(
01552 "at_wini: setup_dma: iov[%d]: addr 0x%x, size %d offset %d, size %d\n",
01553 i, iov[i].iov_addr, iov[i].iov_size, offset, size);
01554 }
01555
01556 n= iov[i].iov_size-offset;
01557 if (n > size)
01558 n= size;
01559 if (n == 0 || (n & 1))
01560 panic("at_wini", "bad size in iov", iov[i].iov_size);
01561 if(proc_nr != SELF) {
01562 r= sys_umap(proc_nr, VM_GRANT, iov[i].iov_addr, n,
01563 &user_phys);
01564 if (r != 0)
01565 panic("at_wini",
01566 "can't map user buffer (VM_GRANT)", r);
01567 user_phys += offset + addr_offset;
01568 } else {
01569 r= sys_umap(proc_nr, VM_D,
01570 iov[i].iov_addr+offset+addr_offset, n,
01571 &user_phys);
01572 if (r != 0)
01573 panic("at_wini",
01574 "can't map user buffer (VM_D)", r);
01575 }
01576 if (user_phys & 1)
01577 {
01578
01579 printf("setup_dma: user buffer is not aligned\n");
01580 bad= 1;
01581 break;
01582 }
01583
01584
01585 if (user_phys/0x10000 != (user_phys+n-1)/0x10000)
01586 n= ((user_phys/0x10000)+1)*0x10000 - user_phys;
01587
01588
01589
01590
01591
01592 if (j >= N_PRDTE)
01593 {
01594
01595
01596 bad= 1;
01597 break;
01598 }
01599
01600 prdt[j].prdte_base= user_phys;
01601 prdt[j].prdte_count= n;
01602 prdt[j].prdte_reserved= 0;
01603 prdt[j].prdte_flags= 0;
01604 j++;
01605
01606 offset += n;
01607 if (offset >= iov[i].iov_size)
01608 {
01609 i++;
01610 offset= 0;
01611 addr_offset= 0;
01612 }
01613
01614 size -= n;
01615 }
01616
01617 if (!bad)
01618 {
01619 if (j <= 0 || j > N_PRDTE)
01620 panic("at_wini", "bad prdt index", j);
01621 prdt[j-1].prdte_flags |= PRDTE_FL_EOT;
01622
01623 if(verbose) {
01624 printf("dma not bad\n");
01625 for (i= 0; i<j; i++) {
01626 printf("prdt[%d]: base 0x%x, size %d, flags 0x%x\n",
01627 i, prdt[i].prdte_base, prdt[i].prdte_count,
01628 prdt[i].prdte_flags);
01629 }
01630 }
01631 }
01632
01633
01634
01635
01636
01637 *do_copyoutp= (!do_write && bad);
01638
01639 if (bad)
01640 {
01641 if(verbose)
01642 printf("partially bad dma\n");
01643
01644 size= *sizep;
01645 if (size > ATA_DMA_BUF_SIZE)
01646 *sizep= size= ATA_DMA_BUF_SIZE;
01647
01648 if (do_write)
01649 {
01650
01651 for (offset= 0; offset < size; offset += n)
01652 {
01653 n= size-offset;
01654 if (n > iov->iov_size)
01655 n= iov->iov_size;
01656
01657 if(proc_nr != SELF) {
01658 r= sys_safecopyfrom(proc_nr, iov->iov_addr,
01659 addr_offset, (vir_bytes)dma_buf+offset,
01660 n, D);
01661 if (r != OK)
01662 {
01663 panic(w_name(),
01664 "setup_dma: sys_vircopy failed", r);
01665 }
01666 } else {
01667 memcpy(dma_buf + offset,
01668 (char *) iov->iov_addr + addr_offset,
01669 n);
01670 }
01671 iov++;
01672 addr_offset= 0;
01673 }
01674 }
01675
01676
01677 phys= dma_buf_phys;
01678 if (phys & 1)
01679 {
01680
01681 panic("at_wini", "bad buffer alignment in setup_dma",
01682 phys);
01683 }
01684 for (j= 0; j<N_PRDTE; i++)
01685 {
01686 if (size == 0)
01687 {
01688 panic("at_wini", "bad size in setup_dma",
01689 size);
01690 }
01691 if (size & 1)
01692 {
01693
01694 panic("at_wini",
01695 "bad size alignment in setup_dma",
01696 size);
01697 }
01698 n= size;
01699
01700
01701 if (phys / 0x10000 != (phys+n-1) / 0x10000)
01702 {
01703 n= ((phys/0x10000)+1)*0x10000 - phys;
01704 }
01705 prdt[j].prdte_base= phys;
01706 prdt[j].prdte_count= n;
01707 prdt[j].prdte_reserved= 0;
01708 prdt[j].prdte_flags= 0;
01709
01710 size -= n;
01711 if (size == 0)
01712 {
01713 prdt[j].prdte_flags |= PRDTE_FL_EOT;
01714 break;
01715 }
01716 }
01717 if (size != 0)
01718 panic("at_wini", "size to large for prdt", NO_NUM);
01719
01720 if(verbose) {
01721 for (i= 0; i<=j; i++)
01722 {
01723 printf("prdt[%d]: base 0x%x, size %d, flags 0x%x\n",
01724 i, prdt[i].prdte_base, prdt[i].prdte_count,
01725 prdt[i].prdte_flags);
01726 }
01727 }
01728 }
01729
01730
01731 r= sys_inb(wn->base_dma + DMA_STATUS, &v);
01732 if (r != 0) panic("at_wini", "setup_dma: sys_inb failed", r);
01733 if (v & DMA_ST_BM_ACTIVE)
01734 panic("at_wini", "Bus master IDE active", NO_NUM);
01735
01736 if (prdt_phys & 3)
01737 panic("at_wini", "prdt not aligned", prdt_phys);
01738 r= sys_outl(wn->base_dma + DMA_PRDTP, prdt_phys);
01739 if (r != 0) panic("at_wini", "setup_dma: sys_outl failed", r);
01740
01741
01742 r= sys_outb(wn->base_dma + DMA_STATUS, DMA_ST_INT | DMA_ST_ERROR);
01743 if (r != 0) panic("at_wini", "setup_dma: sys_outb failed", r);
01744
01745 }
01746
01747
01748
01749
01750
01751 PRIVATE void w_need_reset()
01752 {
01753
01754 struct wini *wn;
01755 int dr = 0;
01756
01757 for (wn = wini; wn < &wini[MAX_DRIVES]; wn++, dr++) {
01758 if (wn->base_cmd == w_wn->base_cmd) {
01759 wn->state |= DEAF;
01760 wn->state &= ~INITIALIZED;
01761 }
01762 }
01763 }
01764
01765
01766
01767
01768 PRIVATE int w_do_close(dp, m_ptr)
01769 struct driver *dp;
01770 message *m_ptr;
01771 {
01772
01773 if (w_prepare(m_ptr->DEVICE) == NIL_DEV)
01774 return(ENXIO);
01775 w_wn->open_ct--;
01776 #if ENABLE_ATAPI
01777 if (w_wn->open_ct == 0 && (w_wn->state & ATAPI)) atapi_close();
01778 #endif
01779 return(OK);
01780 }
01781
01782
01783
01784
01785 PRIVATE int com_simple(cmd)
01786 struct command *cmd;
01787 {
01788
01789 int r;
01790
01791 if (w_wn->state & IGNORING) return ERR;
01792
01793 if ((r = com_out(cmd)) == OK) r = at_intr_wait();
01794 w_command = CMD_IDLE;
01795 return(r);
01796 }
01797
01798
01799
01800
01801 PRIVATE void w_timeout(void)
01802 {
01803 struct wini *wn = w_wn;
01804
01805 switch (w_command) {
01806 case CMD_IDLE:
01807 break;
01808 case CMD_READ:
01809 case CMD_READ_EXT:
01810 case CMD_WRITE:
01811 case CMD_WRITE_EXT:
01812
01813
01814
01815 if (wn->max_count > 8 * SECTOR_SIZE) {
01816 wn->max_count = 8 * SECTOR_SIZE;
01817 } else {
01818 wn->max_count = SECTOR_SIZE;
01819 }
01820
01821 default:
01822
01823 if (w_testing) wn->state |= IGNORING;
01824 else if (!w_silent) printf("%s: timeout on command 0x%02x\n",
01825 w_name(), w_command);
01826 w_need_reset();
01827 wn->w_status = 0;
01828 }
01829 }
01830
01831
01832
01833
01834 PRIVATE int w_reset()
01835 {
01836
01837
01838
01839 int s;
01840 struct wini *wn = w_wn;
01841
01842
01843 if (w_wn->state & IGNORING) return ERR;
01844
01845
01846 tickdelay(RECOVERY_TICKS);
01847
01848
01849 if ((s=sys_outb(wn->base_ctl + REG_CTL, CTL_RESET)) != OK)
01850 panic(w_name(),"Couldn't strobe reset bit",s);
01851 tickdelay(DELAY_TICKS);
01852 if ((s=sys_outb(wn->base_ctl + REG_CTL, 0)) != OK)
01853 panic(w_name(),"Couldn't strobe reset bit",s);
01854 tickdelay(DELAY_TICKS);
01855
01856
01857 if (!w_waitfor(STATUS_BSY, 0)) {
01858 printf("%s: reset failed, drive busy\n", w_name());
01859 return(ERR);
01860 }
01861
01862
01863
01864 for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
01865 if (wn->base_cmd == w_wn->base_cmd) {
01866 wn->state &= ~DEAF;
01867 if (w_wn->irq_need_ack) {
01868
01869 sys_irqenable(&w_wn->irq_hook_id);
01870 }
01871 }
01872 }
01873
01874
01875 return(OK);
01876 }
01877
01878
01879
01880
01881 PRIVATE void w_intr_wait()
01882 {
01883
01884
01885 int r;
01886 unsigned long w_status;
01887 message m;
01888
01889 if (w_wn->irq != NO_IRQ) {
01890
01891
01892
01893 while (w_wn->w_status & (STATUS_ADMBSY|STATUS_BSY)) {
01894 int rr;
01895 if((rr=sef_receive(ANY, &m)) != OK)
01896 panic("at_wini", "sef_receive(ANY) failed", rr);
01897 if (is_notify(m.m_type)) {
01898 switch (_ENDPOINT_P(m.m_source)) {
01899 case CLOCK:
01900
01901 w_timeout();
01902 break;
01903 case HARDWARE:
01904
01905 r= sys_inb(w_wn->base_cmd +
01906 REG_STATUS, &w_status);
01907 if (r != 0)
01908 panic("at_wini",
01909 "sys_inb failed", r);
01910 w_wn->w_status= w_status;
01911 ack_irqs(m.NOTIFY_ARG);
01912 break;
01913 default:
01914
01915
01916
01917
01918 mq_queue(&m);
01919 }
01920 }
01921 else {
01922
01923
01924
01925
01926 mq_queue(&m);
01927 }
01928 }
01929 } else {
01930
01931 (void) w_waitfor(STATUS_BSY, 0);
01932 }
01933 }
01934
01935
01936
01937
01938 PRIVATE int at_intr_wait()
01939 {
01940
01941 int r, s;
01942 unsigned long inbval;
01943
01944 w_intr_wait();
01945 if ((w_wn->w_status & (STATUS_BSY | STATUS_WF | STATUS_ERR)) == 0) {
01946 r = OK;
01947 } else {
01948 if ((s=sys_inb(w_wn->base_cmd + REG_ERROR, &inbval)) != OK)
01949 panic(w_name(),"Couldn't read register",s);
01950 if ((w_wn->w_status & STATUS_ERR) && (inbval & ERROR_BB)) {
01951 r = ERR_BAD_SECTOR;
01952 } else {
01953 r = ERR;
01954 }
01955 }
01956 w_wn->w_status |= STATUS_ADMBSY;
01957 return(r);
01958 }
01959
01960
01961
01962
01963 PRIVATE int w_waitfor(mask, value)
01964 int mask;
01965 int value;
01966 {
01967
01968
01969
01970
01971
01972 unsigned long w_status;
01973 clock_t t0, t1;
01974 int s;
01975
01976 getuptime(&t0);
01977 do {
01978 if ((s=sys_inb(w_wn->base_cmd + REG_STATUS, &w_status)) != OK)
01979 panic(w_name(),"Couldn't read register",s);
01980 w_wn->w_status= w_status;
01981 if ((w_wn->w_status & mask) == value) {
01982 return 1;
01983 }
01984 } while ((s=getuptime(&t1)) == OK && (t1-t0) < timeout_ticks );
01985 if (OK != s) printf("AT_WINI: warning, get_uptime failed: %d\n",s);
01986
01987 w_need_reset();
01988 return(0);
01989 }
01990
01991
01992
01993
01994 PRIVATE int w_waitfor_dma(mask, value)
01995 int mask;
01996 int value;
01997 {
01998
01999
02000
02001
02002
02003 unsigned long w_status;
02004 clock_t t0, t1;
02005 int s;
02006
02007 getuptime(&t0);
02008 do {
02009 if ((s=sys_inb(w_wn->base_dma + DMA_STATUS, &w_status)) != OK)
02010 panic(w_name(),"Couldn't read register",s);
02011 if ((w_status & mask) == value) {
02012 return 1;
02013 }
02014 } while ((s=getuptime(&t1)) == OK && (t1-t0) < timeout_ticks );
02015 if (OK != s) printf("AT_WINI: warning, get_uptime failed: %d\n",s);
02016
02017 return(0);
02018 }
02019
02020
02021
02022
02023 PRIVATE void w_geometry(entry)
02024 struct partition *entry;
02025 {
02026 struct wini *wn = w_wn;
02027
02028 if (wn->state & ATAPI) {
02029 entry->cylinders = div64u(wn->part[0].dv_size, SECTOR_SIZE) / (64*32);
02030 entry->heads = 64;
02031 entry->sectors = 32;
02032 } else {
02033 entry->cylinders = wn->lcylinders;
02034 entry->heads = wn->lheads;
02035 entry->sectors = wn->lsectors;
02036 }
02037 }
02038
02039 #if ENABLE_ATAPI
02040
02041
02042
02043 PRIVATE int atapi_open()
02044 {
02045
02046
02047
02048
02049 w_wn->part[0].dv_size = mul64u(800L*1024, 1024);
02050 return(OK);
02051 }
02052
02053
02054
02055
02056 PRIVATE void atapi_close()
02057 {
02058
02059 }
02060
02061 void sense_request(void)
02062 {
02063 int r, i;
02064 static u8_t sense[100], packet[ATAPI_PACKETSIZE];
02065
02066 packet[0] = SCSI_SENSE;
02067 packet[1] = 0;
02068 packet[2] = 0;
02069 packet[3] = 0;
02070 packet[4] = SENSE_PACKETSIZE;
02071 packet[5] = 0;
02072 packet[7] = 0;
02073 packet[8] = 0;
02074 packet[9] = 0;
02075 packet[10] = 0;
02076 packet[11] = 0;
02077
02078 for(i = 0; i < SENSE_PACKETSIZE; i++) sense[i] = 0xff;
02079 r = atapi_sendpacket(packet, SENSE_PACKETSIZE, 0);
02080 if (r != OK) { printf("request sense command failed\n"); return; }
02081 if (atapi_intr_wait(0, 0) <= 0) { printf("WARNING: request response failed\n"); }
02082
02083 if (sys_insw(w_wn->base_cmd + REG_DATA, SELF, (void *) sense, SENSE_PACKETSIZE) != OK)
02084 printf("WARNING: sense reading failed\n");
02085
02086 printf("sense data:");
02087 for(i = 0; i < SENSE_PACKETSIZE; i++) printf(" %02x", sense[i]);
02088 printf("\n");
02089 }
02090
02091
02092
02093
02094 PRIVATE int atapi_transfer(proc_nr, opcode, position, iov, nr_req)
02095 int proc_nr;
02096 int opcode;
02097 u64_t position;
02098 iovec_t *iov;
02099 unsigned nr_req;
02100 {
02101 struct wini *wn = w_wn;
02102 iovec_t *iop, *iov_end = iov + nr_req;
02103 int r, s, errors, fresh;
02104 u64_t pos;
02105 unsigned long block;
02106 u64_t dv_size = w_dv->dv_size;
02107 unsigned nbytes, nblocks, before, chunk;
02108 static u8_t packet[ATAPI_PACKETSIZE];
02109 size_t addr_offset = 0;
02110 int dmabytes = 0, piobytes = 0;
02111
02112 errors = fresh = 0;
02113
02114 while (nr_req > 0 && !fresh) {
02115 int do_dma = wn->dma && w_atapi_dma;
02116
02117
02118
02119 pos = add64(w_dv->dv_base, position);
02120 block = div64u(pos, CD_SECTOR_SIZE);
02121 before = rem64u(pos, CD_SECTOR_SIZE);
02122
02123 if(before)
02124 do_dma = 0;
02125
02126
02127 nbytes = 0;
02128 for (iop = iov; iop < iov_end; iop++) {
02129 nbytes += iop->iov_size;
02130 if(iop->iov_size % CD_SECTOR_SIZE)
02131 do_dma = 0;
02132 }
02133
02134
02135 if ((before | nbytes) & 1) return(EINVAL);
02136
02137
02138 if (cmp64(position, dv_size) >= 0) return(OK);
02139 if (cmp64(add64ul(position, nbytes), dv_size) > 0)
02140 nbytes = diff64(dv_size, position);
02141
02142 nblocks = (before + nbytes + CD_SECTOR_SIZE - 1) / CD_SECTOR_SIZE;
02143
02144
02145 if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO);
02146
02147
02148 packet[0] = SCSI_READ10;
02149 packet[1] = 0;
02150 packet[2] = (block >> 24) & 0xFF;
02151 packet[3] = (block >> 16) & 0xFF;
02152 packet[4] = (block >> 8) & 0xFF;
02153 packet[5] = (block >> 0) & 0xFF;
02154 packet[6] = 0;
02155 packet[7] = (nblocks >> 8) & 0xFF;
02156 packet[8] = (nblocks >> 0) & 0xFF;
02157 packet[9] = 0;
02158 packet[10] = 0;
02159 packet[11] = 0;
02160
02161 if(do_dma) {
02162 int do_copyout = 0;
02163 stop_dma(wn);
02164 setup_dma(&nbytes, proc_nr, iov, addr_offset, 0,
02165 &do_copyout);
02166 if(do_copyout || (nbytes != nblocks * CD_SECTOR_SIZE)) {
02167 stop_dma(wn);
02168 do_dma = 0;
02169 }
02170 }
02171
02172
02173 r = atapi_sendpacket(packet, nblocks * CD_SECTOR_SIZE, do_dma);
02174 if (r != OK) goto err;
02175
02176 if(do_dma) {
02177 wn->dma_intseen = 0;
02178 start_dma(wn, 0);
02179 w_intr_wait();
02180 if(!wn->dma_intseen) {
02181 if(w_waitfor_dma(DMA_ST_INT, DMA_ST_INT)) {
02182 wn->dma_intseen = 1;
02183 }
02184 }
02185 if(error_dma(wn)) {
02186 printf("Disabling DMA (ATAPI)\n");
02187 wn->dma = 0;
02188 } else {
02189 dmabytes += nbytes;
02190 while (nbytes > 0) {
02191 size_t chunk;
02192 chunk = nbytes;
02193 if (chunk > iov->iov_size)
02194 chunk = iov->iov_size;
02195 position= add64ul(position, chunk);
02196 nbytes -= chunk;
02197 if ((iov->iov_size -= chunk) == 0) {
02198 iov++;
02199 nr_req--;
02200 }
02201 }
02202 }
02203 continue;
02204 }
02205
02206
02207 while ((r = atapi_intr_wait(do_dma, nblocks * CD_SECTOR_SIZE)) > 0) {
02208 size_t count;
02209 count = r;
02210
02211 while (before > 0 && count > 0) {
02212 chunk = before;
02213 if (chunk > count) chunk = count;
02214 if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE;
02215 if ((s=sys_insw(wn->base_cmd + REG_DATA,
02216 SELF, tmp_buf, chunk)) != OK)
02217 panic(w_name(),"Call to sys_insw() failed", s);
02218 before -= chunk;
02219 count -= chunk;
02220 }
02221
02222 while (nbytes > 0 && count > 0) {
02223 chunk = nbytes;
02224 if (chunk > count) chunk = count;
02225 if (chunk > iov->iov_size) chunk = iov->iov_size;
02226 if(proc_nr != SELF) {
02227 s=sys_safe_insw(wn->base_cmd + REG_DATA,
02228 proc_nr, (void *) iov->iov_addr,
02229 addr_offset, chunk);
02230 } else {
02231 s=sys_insw(wn->base_cmd + REG_DATA, proc_nr,
02232 (void *) (iov->iov_addr + addr_offset),
02233 chunk);
02234 }
02235 if (s != OK)
02236 panic(w_name(),"Call to sys_insw() failed", s);
02237 position= add64ul(position, chunk);
02238 nbytes -= chunk;
02239 count -= chunk;
02240 addr_offset += chunk;
02241 piobytes += chunk;
02242 fresh = 0;
02243 if ((iov->iov_size -= chunk) == 0) {
02244 iov++;
02245 nr_req--;
02246 fresh = 1;
02247 addr_offset = 0;
02248 }
02249
02250 }
02251
02252 while (count > 0) {
02253 chunk = count;
02254 if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE;
02255 if ((s=sys_insw(wn->base_cmd + REG_DATA,
02256 SELF, tmp_buf, chunk)) != OK)
02257 panic(w_name(),"Call to sys_insw() failed", s);
02258 count -= chunk;
02259 }
02260 }
02261
02262 if (r < 0) {
02263 err:
02264 if (atapi_debug) sense_request();
02265 if (++errors == max_errors) {
02266 w_command = CMD_IDLE;
02267 if (atapi_debug) printf("giving up (%d)\n", errors);
02268 return(EIO);
02269 }
02270 if (atapi_debug) printf("retry (%d)\n", errors);
02271 }
02272 }
02273
02274 #if 0
02275 if(dmabytes) printf("dmabytes %d ", dmabytes);
02276 if(piobytes) printf("piobytes %d", piobytes);
02277 if(dmabytes || piobytes) printf("\n");
02278 #endif
02279
02280 w_command = CMD_IDLE;
02281 return(OK);
02282 }
02283
02284
02285
02286
02287 PRIVATE int atapi_sendpacket(packet, cnt, do_dma)
02288 u8_t *packet;
02289 unsigned cnt;
02290 int do_dma;
02291 {
02292
02293 struct wini *wn = w_wn;
02294 pvb_pair_t outbyte[6];
02295 int s;
02296
02297 if (wn->state & IGNORING) return ERR;
02298
02299
02300 if ((s=sys_outb(wn->base_cmd + REG_DRIVE, wn->ldhpref)) != OK)
02301 panic(w_name(),"Couldn't select master/ slave drive",s);
02302
02303 if (!w_waitfor(STATUS_BSY | STATUS_DRQ, 0)) {
02304 printf("%s: atapi_sendpacket: drive not ready\n", w_name());
02305 return(ERR);
02306 }
02307
02308
02309
02310
02311
02312
02313
02314 sys_setalarm(wakeup_ticks, 0);
02315
02316 #if _WORD_SIZE > 2
02317 if (cnt > 0xFFFE) cnt = 0xFFFE;
02318 #endif
02319
02320 w_command = ATAPI_PACKETCMD;
02321 pv_set(outbyte[0], wn->base_cmd + REG_FEAT, do_dma ? FEAT_DMA : 0);
02322 pv_set(outbyte[1], wn->base_cmd + REG_IRR, 0);
02323 pv_set(outbyte[2], wn->base_cmd + REG_SAMTAG, 0);
02324 pv_set(outbyte[3], wn->base_cmd + REG_CNT_LO, (cnt >> 0) & 0xFF);
02325 pv_set(outbyte[4], wn->base_cmd + REG_CNT_HI, (cnt >> 8) & 0xFF);
02326 pv_set(outbyte[5], wn->base_cmd + REG_COMMAND, w_command);
02327 if (atapi_debug) printf("cmd: %x ", w_command);
02328 if ((s=sys_voutb(outbyte,6)) != OK)
02329 panic(w_name(),"Couldn't write registers with sys_voutb()",s);
02330
02331 if (!w_waitfor(STATUS_BSY | STATUS_DRQ, STATUS_DRQ)) {
02332 printf("%s: timeout (BSY|DRQ -> DRQ)\n", w_name());
02333 return(ERR);
02334 }
02335 wn->w_status |= STATUS_ADMBSY;
02336
02337
02338 if ((s=sys_outsw(wn->base_cmd + REG_DATA, SELF, packet, ATAPI_PACKETSIZE)) != OK)
02339 panic(w_name(),"sys_outsw() failed", s);
02340
02341 return(OK);
02342 }
02343
02344
02345 #endif
02346
02347
02348
02349
02350 PRIVATE int w_other(dr, m)
02351 struct driver *dr;
02352 message *m;
02353 {
02354 int r, timeout, prev;
02355
02356 if (m->m_type != DEV_IOCTL_S )
02357 return EINVAL;
02358
02359 if (m->REQUEST == DIOCTIMEOUT) {
02360 r= sys_safecopyfrom(m->IO_ENDPT, (vir_bytes) m->IO_GRANT,
02361 0, (vir_bytes)&timeout, sizeof(timeout), D);
02362
02363 if(r != OK)
02364 return r;
02365
02366 if (timeout == 0) {
02367
02368 timeout_ticks = DEF_TIMEOUT_TICKS;
02369 max_errors = MAX_ERRORS;
02370 wakeup_ticks = WAKEUP_TICKS;
02371 w_silent = 0;
02372 } else if (timeout < 0) {
02373 return EINVAL;
02374 } else {
02375 prev = wakeup_ticks;
02376
02377 if (!w_standard_timeouts) {
02378
02379
02380
02381 wakeup_ticks = timeout;
02382 max_errors = 3;
02383 w_silent = 1;
02384
02385 if (timeout_ticks > timeout)
02386 timeout_ticks = timeout;
02387 }
02388
02389 r= sys_safecopyto(m->IO_ENDPT, (vir_bytes) m->IO_GRANT,
02390 0, (vir_bytes)&prev, sizeof(prev), D);
02391
02392 if(r != OK)
02393 return r;
02394 }
02395
02396 return OK;
02397 } else if (m->REQUEST == DIOCOPENCT) {
02398 int count;
02399 if (w_prepare(m->DEVICE) == NIL_DEV) return ENXIO;
02400 count = w_wn->open_ct;
02401 r= sys_safecopyto(m->IO_ENDPT, (vir_bytes) m->IO_GRANT,
02402 0, (vir_bytes)&count, sizeof(count), D);
02403
02404 if(r != OK)
02405 return r;
02406
02407 return OK;
02408 }
02409 return EINVAL;
02410 }
02411
02412
02413
02414
02415 PRIVATE int w_hw_int(dr, m)
02416 struct driver *dr;
02417 message *m;
02418 {
02419
02420 ack_irqs(m->NOTIFY_ARG);
02421
02422 return OK;
02423 }
02424
02425
02426
02427
02428
02429 PRIVATE void ack_irqs(unsigned int irqs)
02430 {
02431 unsigned int drive;
02432 unsigned long w_status;
02433
02434 for (drive = 0; drive < MAX_DRIVES; drive++) {
02435 if (!(wini[drive].state & IGNORING) && wini[drive].irq_need_ack &&
02436 ((1L << wini[drive].irq) & irqs)) {
02437 if (sys_inb((wini[drive].base_cmd + REG_STATUS),
02438 &w_status) != OK)
02439 {
02440 panic(w_name(), "couldn't ack irq on drive %d\n",
02441 drive);
02442 }
02443 wini[drive].w_status= w_status;
02444 sys_inb(wini[drive].base_dma + DMA_STATUS, &w_status);
02445 if(w_status & DMA_ST_INT) {
02446 sys_outb(wini[drive].base_dma + DMA_STATUS, DMA_ST_INT);
02447 wini[drive].dma_intseen = 1;
02448 }
02449 if (sys_irqenable(&wini[drive].irq_hook_id) != OK)
02450 printf("couldn't re-enable drive %d\n", drive);
02451 }
02452 }
02453 }
02454
02455
02456 #define STSTR(a) if (status & STATUS_ ## a) { strcat(str, #a); strcat(str, " "); }
02457 #define ERRSTR(a) if (e & ERROR_ ## a) { strcat(str, #a); strcat(str, " "); }
02458 char *strstatus(int status)
02459 {
02460 static char str[200];
02461 str[0] = '\0';
02462
02463 STSTR(BSY);
02464 STSTR(DRDY);
02465 STSTR(DMADF);
02466 STSTR(SRVCDSC);
02467 STSTR(DRQ);
02468 STSTR(CORR);
02469 STSTR(CHECK);
02470 return str;
02471 }
02472
02473 char *strerr(int e)
02474 {
02475 static char str[200];
02476 str[0] = '\0';
02477
02478 ERRSTR(BB);
02479 ERRSTR(ECC);
02480 ERRSTR(ID);
02481 ERRSTR(AC);
02482 ERRSTR(TK);
02483 ERRSTR(DM);
02484
02485 return str;
02486 }
02487
02488 #if ENABLE_ATAPI
02489
02490
02491
02492
02493 PRIVATE int atapi_intr_wait(int do_dma, size_t max)
02494 {
02495
02496
02497
02498 struct wini *wn = w_wn;
02499 pvb_pair_t inbyte[4];
02500 int s;
02501 int e;
02502 int len;
02503 int irr;
02504 int r;
02505 int phase;
02506
02507 w_intr_wait();
02508
02509
02510 inbyte[0].port = wn->base_cmd + REG_ERROR;
02511 inbyte[1].port = wn->base_cmd + REG_CNT_LO;
02512 inbyte[2].port = wn->base_cmd + REG_CNT_HI;
02513 inbyte[3].port = wn->base_cmd + REG_IRR;
02514 if ((s=sys_vinb(inbyte, 4)) != OK)
02515 panic(w_name(),"ATAPI failed sys_vinb()", s);
02516 e = inbyte[0].value;
02517 len = inbyte[1].value;
02518 len |= inbyte[2].value << 8;
02519 irr = inbyte[3].value;
02520
02521 if (wn->w_status & (STATUS_BSY | STATUS_CHECK)) {
02522 if (atapi_debug) {
02523 printf("atapi fail: S=%x=%s E=%02x=%s L=%04x I=%02x\n", wn->w_status, strstatus(wn->w_status), e, strerr(e), len, irr);
02524 }
02525 return ERR;
02526 }
02527
02528 phase = (wn->w_status & STATUS_DRQ) | (irr & (IRR_COD | IRR_IO));
02529
02530 switch (phase) {
02531 case IRR_COD | IRR_IO:
02532 if (ATAPI_DEBUG) printf("ACD: Phase Command Complete\n");
02533 r = OK;
02534 break;
02535 case 0:
02536 if (ATAPI_DEBUG) printf("ACD: Phase Command Aborted\n");
02537 r = ERR;
02538 break;
02539 case STATUS_DRQ | IRR_COD:
02540 if (ATAPI_DEBUG) printf("ACD: Phase Command Out\n");
02541 r = ERR;
02542 break;
02543 case STATUS_DRQ:
02544 if (ATAPI_DEBUG) printf("ACD: Phase Data Out %d\n", len);
02545 r = len;
02546 break;
02547 case STATUS_DRQ | IRR_IO:
02548 if (ATAPI_DEBUG) printf("ACD: Phase Data In %d\n", len);
02549 r = len;
02550 break;
02551 default:
02552 if (ATAPI_DEBUG) printf("ACD: Phase Unknown\n");
02553 r = ERR;
02554 break;
02555 }
02556
02557 wn->w_status |= STATUS_ADMBSY;
02558 return(r);
02559 }
02560
02561 #endif
02562
02563 #undef sys_voutb
02564 #undef sys_vinb
02565
02566 PRIVATE int at_voutb(int line, pvb_pair_t *pvb, int n)
02567 {
02568 int s, i;
02569 if ((s=sys_voutb(pvb,n)) == OK)
02570 return OK;
02571 printf("at_wini%d: sys_voutb failed: %d pvb (%d):\n", w_instance, s, n);
02572 for(i = 0; i < n; i++)
02573 printf("%2d: %4x -> %4x\n", i, pvb[i].value, pvb[i].port);
02574 panic(w_name(), "sys_voutb failed", NO_NUM);
02575 }
02576
02577 PRIVATE int at_vinb(int line, pvb_pair_t *pvb, int n)
02578 {
02579 int s, i;
02580 if ((s=sys_vinb(pvb,n)) == OK)
02581 return OK;
02582 printf("at_wini%d: sys_vinb failed: %d pvb (%d):\n", w_instance, s, n);
02583 for(i = 0; i < n; i++)
02584 printf("%2d: %4x\n", i, pvb[i].port);
02585 panic(w_name(), "sys_vinb failed", NO_NUM);
02586 }
02587
02588 PRIVATE int at_out(int line, u32_t port, u32_t value,
02589 char *typename, int type)
02590 {
02591 int s;
02592 s = sys_out(port, value, type);
02593 if(s == OK)
02594 return OK;
02595 printf("at_wini%d: line %d: %s failed: %d; %x -> %x\n",
02596 w_instance, line, typename, s, value, port);
02597 panic(w_name(), "sys_out failed", NO_NUM);
02598 }
02599
02600
02601 PRIVATE int at_in(int line, u32_t port, u32_t *value,
02602 char *typename, int type)
02603 {
02604 int s;
02605 s = sys_in(port, value, type);
02606 if(s == OK)
02607 return OK;
02608 printf("at_wini%d: line %d: %s failed: %d; port %x\n",
02609 w_instance, line, typename, s, value, port);
02610 panic(w_name(), "sys_in failed", NO_NUM);
02611 }
02612
02613