From: Ben Gras Date: Thu, 25 Aug 2005 16:25:19 +0000 (+0000) Subject: LBA step X-Git-Tag: v3.1.0~271 X-Git-Url: http://zhaoyanbai.com/repos/man.isc-hmac-fixup.html?a=commitdiff_plain;h=1732526c507505a7abfdcb922ad23329ac065ed7;p=minix.git LBA step --- diff --git a/drivers/at_wini/at_wini.c b/drivers/at_wini/at_wini.c index f798e0f93..7e2f39989 100644 --- a/drivers/at_wini/at_wini.c +++ b/drivers/at_wini/at_wini.c @@ -26,8 +26,11 @@ /* I/O Ports used by winchester disk controllers. */ /* Read and write registers */ -#define REG_BASE0 0x1F0 /* base register of controller 0 */ -#define REG_BASE1 0x170 /* base register of controller 1 */ +#define REG_CMD_BASE0 0x1F0 /* command base register of controller 0 */ +#define REG_CMD_BASE1 0x170 /* command base register of controller 1 */ +#define REG_CTL_BASE0 0x3F6 /* control base register of controller 0 */ +#define REG_CTL_BASE1 0x376 /* control base register of controller 1 */ + #define REG_DATA 0 /* data register (offset from the base reg.) */ #define REG_PRECOMP 1 /* start of write precompensation */ #define REG_COUNT 2 /* sectors to transfer */ @@ -63,14 +66,17 @@ #define CMD_IDLE 0x00 /* for w_command: drive idle */ #define CMD_RECALIBRATE 0x10 /* recalibrate drive */ #define CMD_READ 0x20 /* read data */ +#define CMD_READ_EXT 0x24 /* read data (LBA48 addressed) */ #define CMD_WRITE 0x30 /* write data */ +#define CMD_WRITE_EXT 0x34 /* write data (LBA48 addressed) */ #define CMD_READVERIFY 0x40 /* read verify */ #define CMD_FORMAT 0x50 /* format track */ #define CMD_SEEK 0x70 /* seek cylinder */ #define CMD_DIAG 0x90 /* execute device diagnostics */ #define CMD_SPECIFY 0x91 /* specify parameters */ #define ATA_IDENTIFY 0xEC /* identify drive */ -#define REG_CTL 0x206 /* control register */ +/* #define REG_CTL 0x206 */ /* control register */ +#define REG_CTL 0 /* control register */ #define CTL_NORETRY 0x80 /* disable access retry */ #define CTL_NOECC 0x40 /* disable ecc retry */ #define CTL_EIGHTHEADS 0x08 /* more than eight heads */ @@ -172,7 +178,7 @@ struct command { /* Timeouts and max retries. */ int timeout_ticks = DEF_TIMEOUT_TICKS, max_errors = MAX_ERRORS; int wakeup_ticks = WAKEUP; -long w_standard_timeouts = 0, w_pci_debug = 0, w_instance = 0; +long w_standard_timeouts = 0, w_pci_debug = 0, w_instance = 0, w_lba48 = 0; int w_testing = 0, w_silent = 0; @@ -187,11 +193,13 @@ int w_next_drive = 0; PRIVATE struct wini { /* main drive struct, one entry per drive */ unsigned state; /* drive state: deaf, initialized, dead */ unsigned w_status; /* device status register */ - unsigned base; /* base register of the register file */ + unsigned base_cmd; /* command base register */ + unsigned base_ctl; /* control base register */ unsigned irq; /* interrupt request line */ unsigned irq_mask; /* 1 << irq */ unsigned irq_need_ack; /* irq needs to be acknowledged */ int irq_hook_id; /* id of irq hook at the kernel */ + int lba48; /* supports lba48 */ unsigned lcylinders; /* logical number of cylinders (BIOS) */ unsigned lheads; /* logical number of heads */ unsigned lsectors; /* logical number of sectors per track */ @@ -219,7 +227,7 @@ PRIVATE int w_controller; /* selected controller */ PRIVATE struct device *w_dv; /* device's base and size */ FORWARD _PROTOTYPE( void init_params, (void) ); -FORWARD _PROTOTYPE( void init_drive, (struct wini *, int, int, int, int, int)); +FORWARD _PROTOTYPE( void init_drive, (struct wini *, int, int, int, int, int, int)); FORWARD _PROTOTYPE( void init_params_pci, (int) ); FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) ); FORWARD _PROTOTYPE( struct device *w_prepare, (int dev) ); @@ -298,6 +306,7 @@ PRIVATE void init_params() env_parse("ata_std_timeout", "d", 0, &w_standard_timeouts, 0, 1); env_parse("ata_pci_debug", "d", 0, &w_pci_debug, 0, 1); env_parse("ata_instance", "d", 0, &w_instance, 0, 8); + env_parse("ata_lba48", "d", 0, &w_lba48, 0, 1); if(w_instance == 0) { /* Get the number of drives from the BIOS data area */ @@ -329,7 +338,10 @@ PRIVATE void init_params() } /* Fill in non-BIOS parameters. */ - init_drive(wn, drive < 2 ? REG_BASE0 : REG_BASE1, NO_IRQ, 0, 0, drive); + init_drive(wn, + drive < 2 ? REG_CMD_BASE0 : REG_CMD_BASE1, + drive < 2 ? REG_CTL_BASE0 : REG_CTL_BASE1, + NO_IRQ, 0, 0, drive); w_next_drive++; } } @@ -350,17 +362,19 @@ PRIVATE void init_params() /*============================================================================* * init_drive * *============================================================================*/ -PRIVATE void init_drive(struct wini *w, int base, int irq, int ack, int hook, int drive) +PRIVATE void init_drive(struct wini *w, int base_cmd, int base_ctl, int irq, int ack, int hook, int drive) { w->state = 0; w->w_status = 0; - w->base = base; + w->base_cmd = base_cmd; + w->base_ctl = base_ctl; w->irq = irq; w->irq_mask = 1 << irq; w->irq_need_ack = ack; w->irq_hook_id = hook; w->ldhpref = ldh_init(drive); w->max_count = MAX_SECS << SECTOR_SHIFT; + w->lba48 = 0; } /*============================================================================* @@ -416,26 +430,32 @@ PRIVATE void init_params_pci(int skip) /* Primary channel not in compatability mode? */ if(interface & ATA_IF_NOTCOMPAT1) { - u32_t base; - base = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0; - if(base != REG_BASE0 && base != REG_BASE1) { - init_drive(&wini[w_next_drive], base, irq, 1, irq_hook, 0); - init_drive(&wini[w_next_drive+1], base, irq, 1, irq_hook, 1); - if(w_pci_debug) - printf("atapci %d: 0x%x irq %d\n", devind, base, irq); - } else printf("atapci: ignored drives on primary channel, base %x\n", base); + u32_t base_cmd, base_ctl; + base_cmd = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0; + base_ctl = pci_attr_r32(devind, PCI_BAR_2) & 0xffffffe0; + if(base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) { + init_drive(&wini[w_next_drive], + base_cmd, base_ctl, irq, 1, irq_hook, 0); + init_drive(&wini[w_next_drive+1], + base_cmd, base_ctl, irq, 1, irq_hook, 1); + if(w_pci_debug || 1) + printf("atapci %d: 0x%x 0x%x irq %d\n", devind, base_cmd, base_ctl, irq); + } else printf("atapci: ignored drives on primary channel, base %x\n", base_cmd); } /* Secondary channel not in compatability mode? */ if(interface & ATA_IF_NOTCOMPAT2) { - u32_t base; - base = pci_attr_r32(devind, PCI_BAR_3) & 0xffffffe0; - if(base != REG_BASE0 && base != REG_BASE1) { - init_drive(&wini[w_next_drive+2], base, irq, 1, irq_hook, 2); - init_drive(&wini[w_next_drive+3], base, irq, 1, irq_hook, 3); - if(w_pci_debug) - printf("atapci %d: 0x%x irq %d\n", devind, base, irq); - } else printf("atapci: ignored drives on secondary channel, base %x\n", base); + u32_t base_cmd, base_ctl; + base_cmd = pci_attr_r32(devind, PCI_BAR_3) & 0xffffffe0; + base_ctl = pci_attr_r32(devind, PCI_BAR_4) & 0xffffffe0; + if(base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) { + init_drive(&wini[w_next_drive+2], + base_cmd, base_ctl, irq, 1, irq_hook, 2); + init_drive(&wini[w_next_drive+3], + base_cmd, base_ctl, irq, 1, irq_hook, 3); + if(w_pci_debug || 1) + printf("atapci %d: 0x%x 0x%x irq %d\n", devind, base_cmd, base_ctl, irq); + } else printf("atapci: ignored drives on secondary channel, base %x\n", base_cmd); } w_next_drive += 4; } @@ -570,7 +590,7 @@ PRIVATE int w_identify() wn->state |= SMART; /* Device information. */ - if ((s=sys_insw(wn->base + REG_DATA, SELF, tmp_buf, SECTOR_SIZE)) != OK) + if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, SECTOR_SIZE)) != OK) panic(w_name(),"Call to sys_insw() failed", s); /* Why are the strings byte swapped??? */ @@ -588,6 +608,23 @@ PRIVATE int w_identify() */ wn->ldhpref |= LDH_LBA; size = id_longword(60); + + if(w_lba48 && ((id_word(83)) & (1L << 10))) { + /* Drive is LBA48 capable (and LBA48 is turned on). */ + if(id_word(102) || id_word(103)) { + /* If no. of sectors doesn't fit in 32 bits, + * trunacte to this. So it's LBA32 for now. + * This can still address devices up to 2TB + * though. + */ + size = ULONG_MAX; + } else { + /* Actual number of sectors fits in 32 bits. */ + size = id_longword(100); + } + + wn->lba48 = 1; + } } if (wn->lcylinders == 0) { @@ -607,7 +644,7 @@ PRIVATE int w_identify() wn->state |= ATAPI; /* Device information. */ - if ((s=sys_insw(wn->base + REG_DATA, SELF, tmp_buf, 512)) != OK) + if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, 512)) != OK) panic(w_name(),"Call to sys_insw() failed", s); /* Why are the strings byte swapped??? */ @@ -764,6 +801,40 @@ PRIVATE int w_specify() return(OK); } +/*===========================================================================* + * do_transfer * + *===========================================================================*/ +PRIVATE int do_transfer(struct wini *wn, unsigned int precomp, unsigned int count, + unsigned int sector, unsigned int opcode) +{ + struct command cmd; + unsigned secspcyl = wn->pheads * wn->psectors; + + cmd.precomp = precomp; + cmd.count = count; + cmd.command = opcode == DEV_SCATTER ? CMD_WRITE : CMD_READ; + /* + if (w_lba48 && wn->lba48) { + } else */ + if (wn->ldhpref & LDH_LBA) { + cmd.sector = (sector >> 0) & 0xFF; + cmd.cyl_lo = (sector >> 8) & 0xFF; + cmd.cyl_hi = (sector >> 16) & 0xFF; + cmd.ldh = wn->ldhpref | ((sector >> 24) & 0xF); + } else { + int cylinder, head, sec; + cylinder = sector / secspcyl; + head = (sector % secspcyl) / wn->psectors; + sec = sector % wn->psectors; + cmd.sector = sec + 1; + cmd.cyl_lo = cylinder & BYTE; + cmd.cyl_hi = (cylinder >> 8) & BYTE; + cmd.ldh = wn->ldhpref | head; + } + + return com_out(&cmd); +} + /*===========================================================================* * w_transfer * *===========================================================================*/ @@ -779,9 +850,7 @@ unsigned nr_req; /* length of request vector */ int r, s, errors; unsigned long block; unsigned long dv_size = cv64ul(w_dv->dv_size); - struct command cmd; unsigned cylinder, head, sector, nbytes; - unsigned secspcyl = wn->pheads * wn->psectors; #if ENABLE_ATAPI if (w_wn->state & ATAPI) { @@ -816,6 +885,10 @@ unsigned nr_req; /* length of request vector */ if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO); /* Tell the controller to transfer nbytes bytes. */ +#if 1 + r = do_transfer(wn, wn->precomp, ((nbytes >> SECTOR_SHIFT) & BYTE), + block, opcode); +#else cmd.precomp = wn->precomp; cmd.count = (nbytes >> SECTOR_SHIFT) & BYTE; if (wn->ldhpref & LDH_LBA) { @@ -835,6 +908,7 @@ unsigned nr_req; /* length of request vector */ cmd.command = opcode == DEV_SCATTER ? CMD_WRITE : CMD_READ; r = com_out(&cmd); +#endif while (r == OK && nbytes > 0) { /* For each sector, wait for an interrupt and fetch the data @@ -847,7 +921,7 @@ unsigned nr_req; /* length of request vector */ if ((r = at_intr_wait()) != OK) { /* An error, send data to the bit bucket. */ if (w_wn->w_status & STATUS_DRQ) { - if ((s=sys_insw(wn->base + REG_DATA, SELF, tmp_buf, SECTOR_SIZE)) != OK) + if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, SECTOR_SIZE)) != OK) panic(w_name(),"Call to sys_insw() failed", s); } break; @@ -859,10 +933,10 @@ unsigned nr_req; /* length of request vector */ /* Copy bytes to or from the device's buffer. */ if (opcode == DEV_GATHER) { - if ((s=sys_insw(wn->base + REG_DATA, proc_nr, (void *) iov->iov_addr, SECTOR_SIZE)) != OK) + if ((s=sys_insw(wn->base_cmd + REG_DATA, proc_nr, (void *) iov->iov_addr, SECTOR_SIZE)) != OK) panic(w_name(),"Call to sys_insw() failed", s); } else { - if ((s=sys_outsw(wn->base + REG_DATA, proc_nr, (void *) iov->iov_addr, SECTOR_SIZE)) != OK) + if ((s=sys_outsw(wn->base_cmd + REG_DATA, proc_nr, (void *) iov->iov_addr, SECTOR_SIZE)) != OK) panic(w_name(),"Call to sys_insw() failed", s); /* Data sent, wait for an interrupt. */ @@ -899,7 +973,8 @@ struct command *cmd; /* Command block */ /* Output the command block to the winchester controller and return status */ struct wini *wn = w_wn; - unsigned base = wn->base; + unsigned base_cmd = wn->base_cmd; + unsigned base_ctl = wn->base_ctl; pvb_pair_t outbyte[7]; /* vector for sys_voutb() */ int s; /* status for sys_(v)outb() */ @@ -911,7 +986,7 @@ struct command *cmd; /* Command block */ } /* Select drive. */ - if ((s=sys_outb(base + REG_LDH, cmd->ldh)) != OK) + if ((s=sys_outb(base_cmd + REG_LDH, cmd->ldh)) != OK) panic(w_name(),"Couldn't write register to select drive",s); if (!w_waitfor(STATUS_BSY, 0)) { @@ -929,13 +1004,13 @@ struct command *cmd; /* Command block */ wn->w_status = STATUS_ADMBSY; w_command = cmd->command; - pv_set(outbyte[0], base + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS : 0); - pv_set(outbyte[1], base + REG_PRECOMP, cmd->precomp); - pv_set(outbyte[2], base + REG_COUNT, cmd->count); - pv_set(outbyte[3], base + REG_SECTOR, cmd->sector); - pv_set(outbyte[4], base + REG_CYL_LO, cmd->cyl_lo); - pv_set(outbyte[5], base + REG_CYL_HI, cmd->cyl_hi); - pv_set(outbyte[6], base + REG_COMMAND, cmd->command); + pv_set(outbyte[0], base_ctl + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS : 0); + pv_set(outbyte[1], base_cmd + REG_PRECOMP, cmd->precomp); + pv_set(outbyte[2], base_cmd + REG_COUNT, cmd->count); + pv_set(outbyte[3], base_cmd + REG_SECTOR, cmd->sector); + pv_set(outbyte[4], base_cmd + REG_CYL_LO, cmd->cyl_lo); + pv_set(outbyte[5], base_cmd + REG_CYL_HI, cmd->cyl_hi); + pv_set(outbyte[6], base_cmd + REG_COMMAND, cmd->command); if ((s=sys_voutb(outbyte,7)) != OK) panic(w_name(),"Couldn't write registers with sys_voutb()",s); return(OK); @@ -951,7 +1026,7 @@ PRIVATE void w_need_reset() int dr = 0; for (wn = wini; wn < &wini[MAX_DRIVES]; wn++, dr++) { - if (wn->base == w_wn->base) { + if (wn->base_cmd == w_wn->base_cmd) { wn->state |= DEAF; wn->state &= ~INITIALIZED; } @@ -1039,10 +1114,10 @@ PRIVATE int w_reset() tickdelay(RECOVERY_TICKS); /* Strobe reset bit */ - if ((s=sys_outb(wn->base + REG_CTL, CTL_RESET)) != OK) + if ((s=sys_outb(wn->base_ctl + REG_CTL, CTL_RESET)) != OK) panic(w_name(),"Couldn't strobe reset bit",s); tickdelay(DELAY_TICKS); - if ((s=sys_outb(wn->base + REG_CTL, 0)) != OK) + if ((s=sys_outb(wn->base_ctl + REG_CTL, 0)) != OK) panic(w_name(),"Couldn't strobe reset bit",s); tickdelay(DELAY_TICKS); @@ -1055,7 +1130,7 @@ PRIVATE int w_reset() /* The error register should be checked now, but some drives mess it up. */ for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) { - if (wn->base == w_wn->base) { + if (wn->base_cmd == w_wn->base_cmd) { wn->state &= ~DEAF; if (w_wn->irq_need_ack) { /* Make sure irq is actually enabled.. */ @@ -1084,7 +1159,7 @@ PRIVATE void w_intr_wait() if (m.m_type == SYN_ALARM) { /* but check for timeout */ w_timeout(); /* a.o. set w_status */ } else if (m.m_type == HARD_INT) { - sys_inb(w_wn->base + REG_STATUS, &w_wn->w_status); + sys_inb(w_wn->base_cmd + REG_STATUS, &w_wn->w_status); ack_irqs(m.NOTIFY_ARG); } else { printf("AT_WINI got unexpected message %d from %d\n", @@ -1110,7 +1185,7 @@ PRIVATE int at_intr_wait() if ((w_wn->w_status & (STATUS_BSY | STATUS_WF | STATUS_ERR)) == 0) { r = OK; } else { - if ((s=sys_inb(w_wn->base + REG_ERROR, &inbval)) != OK) + if ((s=sys_inb(w_wn->base_cmd + REG_ERROR, &inbval)) != OK) panic(w_name(),"Couldn't read register",s); if ((w_wn->w_status & STATUS_ERR) && (inbval & ERROR_BB)) { r = ERR_BAD_SECTOR; /* sector marked bad, retries won't help */ @@ -1138,7 +1213,7 @@ int value; /* required status */ int s; getuptime(&t0); do { - if ((s=sys_inb(w_wn->base + REG_STATUS, &w_wn->w_status)) != OK) + if ((s=sys_inb(w_wn->base_cmd + REG_STATUS, &w_wn->w_status)) != OK) panic(w_name(),"Couldn't read register",s); if ((w_wn->w_status & mask) == value) { return 1; @@ -1276,7 +1351,7 @@ unsigned nr_req; /* length of request vector */ chunk = before; if (chunk > count) chunk = count; if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE; - if ((s=sys_insw(wn->base + REG_DATA, SELF, tmp_buf, chunk)) != OK) + if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, chunk)) != OK) panic(w_name(),"Call to sys_insw() failed", s); before -= chunk; count -= chunk; @@ -1286,7 +1361,7 @@ unsigned nr_req; /* length of request vector */ chunk = nbytes; if (chunk > count) chunk = count; if (chunk > iov->iov_size) chunk = iov->iov_size; - if ((s=sys_insw(wn->base + REG_DATA, proc_nr, (void *) iov->iov_addr, chunk)) != OK) + if ((s=sys_insw(wn->base_cmd + REG_DATA, proc_nr, (void *) iov->iov_addr, chunk)) != OK) panic(w_name(),"Call to sys_insw() failed", s); position += chunk; nbytes -= chunk; @@ -1303,7 +1378,7 @@ unsigned nr_req; /* length of request vector */ while (count > 0) { /* Excess data. */ chunk = count; if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE; - if ((s=sys_insw(wn->base + REG_DATA, SELF, tmp_buf, chunk)) != OK) + if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, chunk)) != OK) panic(w_name(),"Call to sys_insw() failed", s); count -= chunk; } @@ -1337,7 +1412,7 @@ unsigned cnt; if(wn->state & IGNORING) return ERR; /* Select Master/Slave drive */ - if ((s=sys_outb(wn->base + REG_DRIVE, wn->ldhpref)) != OK) + if ((s=sys_outb(wn->base_cmd + REG_DRIVE, wn->ldhpref)) != OK) panic(w_name(),"Couldn't select master/ slave drive",s); if (!w_waitfor(STATUS_BSY | STATUS_DRQ, 0)) { @@ -1358,12 +1433,12 @@ unsigned cnt; #endif w_command = ATAPI_PACKETCMD; - pv_set(outbyte[0], wn->base + REG_FEAT, 0); - pv_set(outbyte[1], wn->base + REG_IRR, 0); - pv_set(outbyte[2], wn->base + REG_SAMTAG, 0); - pv_set(outbyte[3], wn->base + REG_CNT_LO, (cnt >> 0) & 0xFF); - pv_set(outbyte[4], wn->base + REG_CNT_HI, (cnt >> 8) & 0xFF); - pv_set(outbyte[5], wn->base + REG_COMMAND, w_command); + pv_set(outbyte[0], wn->base_cmd + REG_FEAT, 0); + pv_set(outbyte[1], wn->base_cmd + REG_IRR, 0); + pv_set(outbyte[2], wn->base_cmd + REG_SAMTAG, 0); + pv_set(outbyte[3], wn->base_cmd + REG_CNT_LO, (cnt >> 0) & 0xFF); + pv_set(outbyte[4], wn->base_cmd + REG_CNT_HI, (cnt >> 8) & 0xFF); + pv_set(outbyte[5], wn->base_cmd + REG_COMMAND, w_command); if ((s=sys_voutb(outbyte,6)) != OK) panic(w_name(),"Couldn't write registers with sys_voutb()",s); @@ -1374,7 +1449,7 @@ unsigned cnt; wn->w_status |= STATUS_ADMBSY; /* Command not at all done yet. */ /* Send the command packet to the device. */ - if ((s=sys_outsw(wn->base + REG_DATA, SELF, packet, 12)) != OK) + if ((s=sys_outsw(wn->base_cmd + REG_DATA, SELF, packet, 12)) != OK) panic(w_name(),"sys_outsw() failed", s); return(OK); } @@ -1462,7 +1537,7 @@ PRIVATE void ack_irqs(unsigned int irqs) for (drive = 0; drive < MAX_DRIVES && irqs; drive++) { if(!(wini[drive].state & IGNORING) && wini[drive].irq_need_ack && (wini[drive].irq_mask & irqs)) { - if(sys_inb((wini[drive].base + REG_STATUS), &wini[drive].w_status) != OK) + if(sys_inb((wini[drive].base_cmd + REG_STATUS), &wini[drive].w_status) != OK) printf("couldn't ack irq on drive %d\n", drive); if (sys_irqenable(&wini[drive].irq_hook_id) != OK) printf("couldn't re-enable drive %d\n", drive); @@ -1491,10 +1566,10 @@ PRIVATE int atapi_intr_wait() w_intr_wait(); /* Request series of device I/O. */ - inbyte[0].port = wn->base + REG_ERROR; - inbyte[1].port = wn->base + REG_CNT_LO; - inbyte[2].port = wn->base + REG_CNT_HI; - inbyte[3].port = wn->base + REG_IRR; + inbyte[0].port = wn->base_cmd + REG_ERROR; + inbyte[1].port = wn->base_cmd + REG_CNT_LO; + inbyte[2].port = wn->base_cmd + REG_CNT_HI; + inbyte[3].port = wn->base_cmd + REG_IRR; if ((s=sys_vinb(inbyte, 4)) != OK) panic(w_name(),"ATAPI failed sys_vinb()", s); e = inbyte[0].value;