1: /* This file contains the device dependent part of a driver for the IBM-AT
   2:  * winchester controller.
   3:  * It was written by Adri Koppes.
   4:  *
   5:  * The file contains one entry point:
   6:  *
   7:  *   at_winchester_task:        main entry when system is brought up
   8:  *
   9:  *
  10:  * Changes:
  11:  *      13 Apr 1992 by Kees J. Bot: device dependent/independent split.
  12:  *      14 May 2000 by Kees J. Bot: d-d/i rewrite.
  13:  *      23 Mar 2000 by Michael Temari: added ATAPI CDROM support.
  14:  */
  15: 
  16: #include "kernel.h"
  17: #include "driver.h"
  18: #include "drvlib.h"
  19: 
  20: #if ENABLE_AT_WINI
  21: 
  22: #define ATAPI_DEBUG         0   /* To debug ATAPI code. */
  23: 
  24: /* I/O Ports used by winchester disk controllers. */
  25: 
  26: /* Read and write registers */
  27: #define REG_BASE0       0x1F0   /* base register of controller 0 */
  28: #define REG_BASE1       0x170   /* base register of controller 1 */
  29: #define REG_DATA            0   /* data register (offset from the base reg.) */
  30: #define REG_PRECOMP         1   /* start of write precompensation */
  31: #define REG_COUNT           2   /* sectors to transfer */
  32: #define REG_SECTOR          3   /* sector number */
  33: #define REG_CYL_LO          4   /* low byte of cylinder number */
  34: #define REG_CYL_HI          5   /* high byte of cylinder number */
  35: #define REG_LDH             6   /* lba, drive and head */
  36: #define   LDH_DEFAULT           0xA0    /* ECC enable, 512 bytes per sector */
  37: #define   LDH_LBA               0x40    /* Use LBA addressing */
  38: #define   ldh_init(drive)       (LDH_DEFAULT | ((drive) << 4))
  39: 
  40: /* Read only registers */
  41: #define REG_STATUS          7   /* status */
  42: #define   STATUS_BSY            0x80    /* controller busy */
  43: #define   STATUS_RDY            0x40    /* drive ready */
  44: #define   STATUS_WF             0x20    /* write fault */
  45: #define   STATUS_SC             0x10    /* seek complete (obsolete) */
  46: #define   STATUS_DRQ            0x08    /* data transfer request */
  47: #define   STATUS_CRD            0x04    /* corrected data */
  48: #define   STATUS_IDX            0x02    /* index pulse */
  49: #define   STATUS_ERR            0x01    /* error */
  50: #define   STATUS_ADMBSY        0x100    /* administratively busy (software) */
  51: #define REG_ERROR           1   /* error code */
  52: #define   ERROR_BB              0x80    /* bad block */
  53: #define   ERROR_ECC             0x40    /* bad ecc bytes */
  54: #define   ERROR_ID              0x10    /* id not found */
  55: #define   ERROR_AC              0x04    /* aborted command */
  56: #define   ERROR_TK              0x02    /* track zero error */
  57: #define   ERROR_DM              0x01    /* no data address mark */
  58: 
  59: /* Write only registers */
  60: #define REG_COMMAND         7   /* command */
  61: #define   CMD_IDLE              0x00    /* for w_command: drive idle */
  62: #define   CMD_RECALIBRATE       0x10    /* recalibrate drive */
  63: #define   CMD_READ              0x20    /* read data */
  64: #define   CMD_WRITE             0x30    /* write data */
  65: #define   CMD_READVERIFY        0x40    /* read verify */
  66: #define   CMD_FORMAT            0x50    /* format track */
  67: #define   CMD_SEEK              0x70    /* seek cylinder */
  68: #define   CMD_DIAG              0x90    /* execute device diagnostics */
  69: #define   CMD_SPECIFY           0x91    /* specify parameters */
  70: #define   ATA_IDENTIFY          0xEC    /* identify drive */
  71: #define REG_CTL         0x206   /* control register */
  72: #define   CTL_NORETRY           0x80    /* disable access retry */
  73: #define   CTL_NOECC             0x40    /* disable ecc retry */
  74: #define   CTL_EIGHTHEADS        0x08    /* more than eight heads */
  75: #define   CTL_RESET             0x04    /* reset controller */
  76: #define   CTL_INTDISABLE        0x02    /* disable interrupts */
  77: 
  78: #if ENABLE_ATAPI
  79: #define   ERROR_SENSE           0xF0    /* sense key mask */
  80: #define     SENSE_NONE          0x00    /* no sense key */
  81: #define     SENSE_RECERR        0x10    /* recovered error */
  82: #define     SENSE_NOTRDY        0x20    /* not ready */
  83: #define     SENSE_MEDERR        0x30    /* medium error */
  84: #define     SENSE_HRDERR        0x40    /* hardware error */
  85: #define     SENSE_ILRQST        0x50    /* illegal request */
  86: #define     SENSE_UATTN         0x60    /* unit attention */
  87: #define     SENSE_DPROT         0x70    /* data protect */
  88: #define     SENSE_ABRT          0xb0    /* aborted command */
  89: #define     SENSE_MISCOM        0xe0    /* miscompare */
  90: #define   ERROR_MCR             0x08    /* media change requested */
  91: #define   ERROR_ABRT            0x04    /* aborted command */
  92: #define   ERROR_EOM             0x02    /* end of media detected */
  93: #define   ERROR_ILI             0x01    /* illegal length indication */
  94: #define REG_FEAT            1   /* features */
  95: #define   FEAT_OVERLAP          0x02    /* overlap */
  96: #define   FEAT_DMA              0x01    /* dma */
  97: #define REG_IRR             2   /* interrupt reason register */
  98: #define   IRR_REL               0x04    /* release */
  99: #define   IRR_IO                0x02    /* direction for xfer */
 100: #define   IRR_COD               0x01    /* command or data */
 101: #define REG_SAMTAG          3
 102: #define REG_CNT_LO          4   /* low byte of cylinder number */
 103: #define REG_CNT_HI          5   /* high byte of cylinder number */
 104: #define REG_DRIVE           6   /* drive select */
 105: #define REG_STATUS          7   /* status */
 106: #define   STATUS_BSY            0x80    /* controller busy */
 107: #define   STATUS_DRDY           0x40    /* drive ready */
 108: #define   STATUS_DMADF          0x20    /* dma ready/drive fault */
 109: #define   STATUS_SRVCDSC        0x10    /* service or dsc */
 110: #define   STATUS_DRQ            0x08    /* data transfer request */
 111: #define   STATUS_CORR           0x04    /* correctable error occurred */
 112: #define   STATUS_CHECK          0x01    /* check error */
 113: 
 114: #define   ATAPI_PACKETCMD       0xA0    /* packet command */
 115: #define   ATAPI_IDENTIFY        0xA1    /* identify drive */
 116: #define   SCSI_READ10           0x28    /* read from disk */
 117: 
 118: #define CD_SECTOR_SIZE          2048    /* sector size of a CD-ROM */
 119: #endif /* ATAPI */
 120: 
 121: /* Interrupt request lines. */
 122: #define NO_IRQ           0      /* no IRQ set yet */
 123: #define AT_IRQ0         14      /* interrupt number for controller 0 */
 124: #define AT_IRQ1         15      /* interrupt number for controller 1 */
 125: 
 126: /* Common command block */
 127: struct command {
 128:   u8_t  precomp;        /* REG_PRECOMP, etc. */
 129:   u8_t  count;
 130:   u8_t  sector;
 131:   u8_t  cyl_lo;
 132:   u8_t  cyl_hi;
 133:   u8_t  ldh;
 134:   u8_t  command;
 135: };
 136: 
 137: 
 138: /* Error codes */
 139: #define ERR              (-1)   /* general error */
 140: #define ERR_BAD_SECTOR   (-2)   /* block marked bad detected */
 141: 
 142: /* Some controllers don't interrupt, the clock will wake us up. */
 143: #define WAKEUP          (32*HZ) /* drive may be out for 31 seconds max */
 144: 
 145: /* Miscellaneous. */
 146: #define MAX_DRIVES         4    /* this driver supports 4 drives (d0 - d3) */
 147: #if _WORD_SIZE > 2
 148: #define MAX_SECS         256    /* controller can transfer this many sectors */
 149: #else
 150: #define MAX_SECS         127    /* but not to a 16 bit process */
 151: #endif
 152: #define MAX_ERRORS         4    /* how often to try rd/wt before quitting */
 153: #define NR_DEVICES      (MAX_DRIVES * DEV_PER_DRIVE)
 154: #define SUB_PER_DRIVE   (NR_PARTITIONS * NR_PARTITIONS)
 155: #define NR_SUBDEVS      (MAX_DRIVES * SUB_PER_DRIVE)
 156: #define TIMEOUT      5000000    /* controller timeout in us */
 157: #define RECOVERYTIME  500000    /* controller recovery time in us */
 158: #define INITIALIZED     0x01    /* drive is initialized */
 159: #define DEAF            0x02    /* controller must be reset */
 160: #define SMART           0x04    /* drive supports ATA commands */
 161: #if ENABLE_ATAPI
 162: #define ATAPI           0x08    /* it is an ATAPI device */
 163: #else
 164: #define ATAPI              0    /* don't bother with ATAPI; optimise out */
 165: #endif
 166: 
 167: 
 168: /* Variables. */
 169: PRIVATE struct wini {           /* main drive struct, one entry per drive */
 170:   unsigned state;               /* drive state: deaf, initialized, dead */
 171:   unsigned base;                /* base register of the register file */
 172:   unsigned irq;                 /* interrupt request line */
 173:   unsigned lcylinders;          /* logical number of cylinders (BIOS) */
 174:   unsigned lheads;              /* logical number of heads */
 175:   unsigned lsectors;            /* logical number of sectors per track */
 176:   unsigned pcylinders;          /* physical number of cylinders (translated) */
 177:   unsigned pheads;              /* physical number of heads */
 178:   unsigned psectors;            /* physical number of sectors per track */
 179:   unsigned ldhpref;             /* top four bytes of the LDH (head) register */
 180:   unsigned precomp;             /* write precompensation cylinder / 4 */
 181:   unsigned max_count;           /* max request for this drive */
 182:   unsigned open_ct;             /* in-use count */
 183:   irq_hook_t hook;              /* interrupt hook */
 184:   struct device part[DEV_PER_DRIVE];    /* disks and partitions */
 185:   struct device subpart[SUB_PER_DRIVE]; /* subpartitions */
 186: } wini[MAX_DRIVES], *w_wn;
 187: 
 188: PRIVATE int win_tasknr;                 /* my task number */
 189: PRIVATE int w_command;                  /* current command in execution */
 190: PRIVATE int w_status;                   /* status after interrupt */
 191: PRIVATE int w_drive;                    /* selected drive */
 192: PRIVATE struct device *w_dv;            /* device's base and size */
 193: PRIVATE timer_t w_tmr_timeout;          /* timer for w_timeout */
 194: 
 195: FORWARD _PROTOTYPE( void init_params, (void) );
 196: FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) );
 197: FORWARD _PROTOTYPE( struct device *w_prepare, (int device) );
 198: FORWARD _PROTOTYPE( int w_identify, (void) );
 199: FORWARD _PROTOTYPE( char *w_name, (void) );
 200: FORWARD _PROTOTYPE( int w_specify, (void) );
 201: FORWARD _PROTOTYPE( int w_transfer, (int proc_nr, int opcode, off_t position,
 202:                                         iovec_t *iov, unsigned nr_req) );
 203: FORWARD _PROTOTYPE( int com_out, (struct command *cmd) );
 204: FORWARD _PROTOTYPE( void w_need_reset, (void) );
 205: FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
 206: FORWARD _PROTOTYPE( int com_simple, (struct command *cmd) );
 207: FORWARD _PROTOTYPE( void w_timeout, (timer_t *tp) );
 208: FORWARD _PROTOTYPE( int w_reset, (void) );
 209: FORWARD _PROTOTYPE( void w_intr_wait, (void) );
 210: FORWARD _PROTOTYPE( int at_intr_wait, (void) );
 211: FORWARD _PROTOTYPE( int w_waitfor, (int mask, int value) );
 212: FORWARD _PROTOTYPE( int w_handler, (irq_hook_t *hook) );
 213: FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry) );
 214: #if ENABLE_ATAPI
 215: FORWARD _PROTOTYPE( int atapi_sendpacket, (u8_t *packet, unsigned cnt) );
 216: FORWARD _PROTOTYPE( int atapi_intr_wait, (void) );
 217: FORWARD _PROTOTYPE( int atapi_open, (void) );
 218: FORWARD _PROTOTYPE( void atapi_close, (void) );
 219: FORWARD _PROTOTYPE( int atapi_transfer, (int proc_nr, int opcode,
 220:                         off_t position, iovec_t *iov, unsigned nr_req) );
 221: #endif
 222: 
 223: 
 224: /* Entry points to this driver. */
 225: PRIVATE struct driver w_dtab = {
 226:   w_name,               /* current device's name */
 227:   w_do_open,            /* open or mount request, initialize device */
 228:   w_do_close,           /* release device */
 229:   do_diocntl,           /* get or set a partition's geometry */
 230:   w_prepare,            /* prepare for I/O on a given minor device */
 231:   w_transfer,           /* do the I/O */
 232:   nop_cleanup,          /* nothing to clean up */
 233:   w_geometry,           /* tell the geometry of the disk */
 234: };
 235: 
 236: 
 237: /*===========================================================================*
 238:  *                              at_winchester_task                           *
 239:  *===========================================================================*/
 240: PUBLIC void at_winchester_task()
 241: {
 242: /* Set special disk parameters then call the generic main loop. */
 243: 
 244:   win_tasknr = proc_number(proc_ptr);
 245: 
 246:   init_params();
 247: 
 248:   driver_task(&w_dtab);
 249: }
 250: 
 251: 
 252: /*============================================================================*
 253:  *                              init_params                                   *
 254:  *============================================================================*/
 255: PRIVATE void init_params()
 256: {
 257: /* This routine is called at startup to initialize the drive parameters. */
 258: 
 259:   u16_t parv[2];
 260:   unsigned int vector;
 261:   int drive, nr_drives;
 262:   struct wini *wn;
 263:   u8_t params[16];
 264:   phys_bytes param_phys = vir2phys(params);
 265: 
 266:   /* Get the number of drives from the BIOS data area */
 267:   phys_copy(0x475L, param_phys, 1L);
 268:   if ((nr_drives = params[0]) > 2) nr_drives = 2;
 269: 
 270:   for (drive = 0, wn = wini; drive < MAX_DRIVES; drive++, wn++) {
 271:         if (drive < nr_drives) {
 272:                 /* Copy the BIOS parameter vector */
 273:                 vector = drive == 0 ? WINI_0_PARM_VEC : WINI_1_PARM_VEC;
 274:                 phys_copy(vector * 4L, vir2phys(parv), 4L);
 275: 
 276:                 /* Calculate the address of the parameters and copy them */
 277:                 phys_copy(hclick_to_physb(parv[1]) + parv[0], param_phys, 16L);
 278: 
 279:                 /* Copy the parameters to the structures of the drive */
 280:                 wn->lcylinders = bp_cylinders(params);
 281:                 wn->lheads = bp_heads(params);
 282:                 wn->lsectors = bp_sectors(params);
 283:                 wn->precomp = bp_precomp(params) >> 2;
 284:         }
 285:         wn->ldhpref = ldh_init(drive);
 286:         wn->max_count = MAX_SECS << SECTOR_SHIFT;
 287: 
 288:         /* Base I/O register to address controller. */
 289:         wn->base = drive < 2 ? REG_BASE0 : REG_BASE1;
 290:   }
 291: }
 292: 
 293: 
 294: /*============================================================================*
 295:  *                              w_do_open                                     *
 296:  *============================================================================*/
 297: PRIVATE int w_do_open(dp, m_ptr)
 298: struct driver *dp;
 299: message *m_ptr;
 300: {
 301: /* Device open: Initialize the controller and read the partition table. */
 302: 
 303:   struct wini *wn;
 304: 
 305:   if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
 306:   wn = w_wn;
 307: 
 308:   if (wn->state == 0) {
 309:         /* Try to identify the device. */
 310:         if (w_identify() != OK) {
 311:                 printf("%s: probe failed\n", w_name());
 312:                 if (wn->state & DEAF) w_reset();
 313:                 wn->state = 0;
 314:                 return(ENXIO);
 315:         }
 316:   }
 317:   if (wn->open_ct == 0) {
 318: #if ENABLE_ATAPI
 319:         if (wn->state & ATAPI) {
 320:                 int r;
 321: 
 322:                 if (m_ptr->COUNT & W_BIT) return(EACCES);
 323:                 if ((r = atapi_open()) != OK) return(r);
 324:         }
 325: #endif
 326:         /* Partition the disk. */
 327:         partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY);
 328:         wn->open_ct++;
 329:   }
 330:   return(OK);
 331: }
 332: 
 333: 
 334: /*===========================================================================*
 335:  *                              w_prepare                                    *
 336:  *===========================================================================*/
 337: PRIVATE struct device *w_prepare(device)
 338: int device;
 339: {
 340: /* Prepare for I/O on a device. */
 341: 
 342:   if (device < NR_DEVICES) {                     /* d0, d0p[0-3], d1, ... */
 343:         w_drive = device / DEV_PER_DRIVE;       /* save drive number */
 344:         w_wn = &wini[w_drive];
 345:         w_dv = &w_wn->part[device % DEV_PER_DRIVE];
 346:   } else
 347:   if ((unsigned) (device -= MINOR_d0p0s0) < NR_SUBDEVS) {/*d[0-7]p[0-3]s[0-3]*/
 348:         w_drive = device / SUB_PER_DRIVE;
 349:         w_wn = &wini[w_drive];
 350:         w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
 351:   } else {
 352:         return(NIL_DEV);
 353:   }
 354:   return(w_dv);
 355: }
 356: 
 357: 
 358: /*===========================================================================*
 359:  *                              w_identify                                   *
 360:  *===========================================================================*/
 361: PRIVATE int w_identify()
 362: {
 363: /* Find out if a device exists, if it is an old AT disk, or a newer ATA
 364:  * drive, a removable media device, etc.
 365:  */
 366: 
 367:   struct wini *wn = w_wn;
 368:   struct command cmd;
 369:   char id_string[40];
 370:   int i, r;
 371:   unsigned long size;
 372: #define id_byte(n)      (&tmp_buf[2 * (n)])
 373: #define id_word(n)      (((u16_t) id_byte(n)[0] <<  0) \
 374:                         |((u16_t) id_byte(n)[1] <<  8))
 375: #define id_longword(n)  (((u32_t) id_byte(n)[0] <<  0) \
 376:                         |((u32_t) id_byte(n)[1] <<  8) \
 377:                         |((u32_t) id_byte(n)[2] << 16) \
 378:                         |((u32_t) id_byte(n)[3] << 24))
 379: 
 380:   /* Try to identify the device. */
 381:   cmd.ldh     = wn->ldhpref;
 382:   cmd.command = ATA_IDENTIFY;
 383:   if (com_simple(&cmd) == OK) {
 384:         /* This is an ATA device. */
 385:         wn->state |= SMART;
 386: 
 387:         /* Device information. */
 388:         phys_insw(wn->base + REG_DATA, tmp_phys, SECTOR_SIZE);
 389: 
 390:         /* Why are the strings byte swapped??? */
 391:         for (i = 0; i < 40; i++) id_string[i] = id_byte(27)[i^1];
 392: 
 393:         /* Preferred CHS translation mode. */
 394:         wn->pcylinders = id_word(1);
 395:         wn->pheads = id_word(3);
 396:         wn->psectors = id_word(6);
 397:         size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
 398: 
 399:         if ((id_byte(49)[1] & 0x02) && size > 512L*1024*2) {
 400:                 /* Drive is LBA capable and is big enough to trust it to
 401:                  * not make a mess of it.
 402:                  */
 403:                 wn->ldhpref |= LDH_LBA;
 404:                 size = id_longword(60);
 405:         }
 406: 
 407:         if (wn->lcylinders == 0) {
 408:                 /* No BIOS parameters?  Then make some up. */
 409:                 wn->lcylinders = wn->pcylinders;
 410:                 wn->lheads = wn->pheads;
 411:                 wn->lsectors = wn->psectors;
 412:                 while (wn->lcylinders > 1024) {
 413:                         wn->lheads *= 2;
 414:                         wn->lcylinders /= 2;
 415:                 }
 416:         }
 417: #if ENABLE_ATAPI
 418:   } else
 419:   if (cmd.command = ATAPI_IDENTIFY, com_simple(&cmd) == OK) {
 420:         /* An ATAPI device. */
 421:         wn->state |= ATAPI;
 422: 
 423:         /* Device information. */
 424:         phys_insw(wn->base + REG_DATA, tmp_phys, 512);
 425: 
 426:         /* Why are the strings byte swapped??? */
 427:         for (i = 0; i < 40; i++) id_string[i] = id_byte(27)[i^1];
 428: 
 429:         size = 0;       /* Size set later. */
 430: #endif
 431:   } else {
 432:         /* Not an ATA device; no translations, no special features.  Don't
 433:          * touch it unless the BIOS knows about it.
 434:          */
 435:         if (wn->lcylinders == 0) return(ERR);    /* no BIOS parameters */
 436:         wn->pcylinders = wn->lcylinders;
 437:         wn->pheads = wn->lheads;
 438:         wn->psectors = wn->lsectors;
 439:         size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
 440:   }
 441: 
 442:   /* Size of the whole drive */
 443:   wn->part[0].dv_size = mul64u(size, SECTOR_SIZE);
 444: 
 445:   if (w_specify() != OK && w_specify() != OK) return(ERR);
 446: 
 447:   printf("%s: ", w_name());
 448:   if (wn->state & (SMART|ATAPI)) {
 449:         printf("%.40s\n", id_string);
 450:   } else {
 451:         printf("%ux%ux%u\n", wn->pcylinders, wn->pheads, wn->psectors);
 452:   }
 453: 
 454:   /* Everything looks OK; register IRQ so we can stop polling. */
 455:   wn->irq = w_drive < 2 ? AT_IRQ0 : AT_IRQ1;
 456:   put_irq_handler(&wn->hook, wn->irq, w_handler);
 457:   enable_irq(&wn->hook);
 458: 
 459:   return(OK);
 460: }
 461: 
 462: 
 463: /*===========================================================================*
 464:  *                              w_name                                       *
 465:  *===========================================================================*/
 466: PRIVATE char *w_name()
 467: {
 468: /* Return a name for the current device. */
 469:   static char name[] = "at-d0";
 470: 
 471:   name[4] = '0' + w_drive;
 472:   return name;
 473: }
 474: 
 475: 
 476: /*===========================================================================*
 477:  *                              w_specify                                    *
 478:  *===========================================================================*/
 479: PRIVATE int w_specify()
 480: {
 481: /* Routine to initialize the drive after boot or when a reset is needed. */
 482: 
 483:   struct wini *wn = w_wn;
 484:   struct command cmd;
 485: 
 486:   if ((wn->state & DEAF) && w_reset() != OK) return(ERR);
 487: 
 488:   if (!(wn->state & ATAPI)) {
 489:         /* Specify parameters: precompensation, number of heads and sectors. */
 490:         cmd.precomp = wn->precomp;
 491:         cmd.count   = wn->psectors;
 492:         cmd.ldh     = w_wn->ldhpref | (wn->pheads - 1);
 493:         cmd.command = CMD_SPECIFY;              /* Specify some parameters */
 494: 
 495:         /* Output command block and see if controller accepts the parameters. */
 496:         if (com_simple(&cmd) != OK) return(ERR);
 497: 
 498:         if (!(wn->state & SMART)) {
 499:                 /* Calibrate an old disk. */
 500:                 cmd.sector  = 0;
 501:                 cmd.cyl_lo  = 0;
 502:                 cmd.cyl_hi  = 0;
 503:                 cmd.ldh     = w_wn->ldhpref;
 504:                 cmd.command = CMD_RECALIBRATE;
 505: 
 506:                 if (com_simple(&cmd) != OK) return(ERR);
 507:         }
 508:   }
 509:   wn->state |= INITIALIZED;
 510:   return(OK);
 511: }
 512: 
 513: 
 514: /*===========================================================================*
 515:  *                              w_transfer                                   *
 516:  *===========================================================================*/
 517: PRIVATE int w_transfer(proc_nr, opcode, position, iov, nr_req)
 518: int proc_nr;                    /* process doing the request */
 519: int opcode;                     /* DEV_GATHER or DEV_SCATTER */
 520: off_t position;                 /* offset on device to read or write */
 521: iovec_t *iov;                   /* pointer to read or write request vector */
 522: unsigned nr_req;                /* length of request vector */
 523: {
 524:   struct wini *wn = w_wn;
 525:   iovec_t *iop, *iov_end = iov + nr_req;
 526:   int r, errors;
 527:   unsigned long block;
 528:   unsigned long dv_size = cv64ul(w_dv->dv_size);
 529:   struct command cmd;
 530:   unsigned cylinder, head, sector, nbytes, count, chunk;
 531:   unsigned secspcyl = wn->pheads * wn->psectors;
 532:   phys_bytes user_base = proc_vir2phys(proc_addr(proc_nr), 0);
 533: 
 534: #if ENABLE_ATAPI
 535:   if (w_wn->state & ATAPI) {
 536:         return atapi_transfer(proc_nr, opcode, position, iov, nr_req);
 537:   }
 538: #endif
 539: 
 540:   /* Check disk address. */
 541:   if ((position & SECTOR_MASK) != 0) return(EINVAL);
 542: 
 543:   errors = 0;
 544: 
 545:   while (nr_req > 0) {
 546:         /* How many bytes to transfer? */
 547:         nbytes = 0;
 548:         for (iop = iov; iop < iov_end; iop++) nbytes += iop->iov_size;
 549:         if ((nbytes & SECTOR_MASK) != 0) return(EINVAL);
 550: 
 551:         /* Which block on disk and how close to EOF? */
 552:         if (position >= dv_size) return(OK);             /* At EOF */
 553:         if (position + nbytes > dv_size) nbytes = dv_size - position;
 554:         block = div64u(add64ul(w_dv->dv_base, position), SECTOR_SIZE);
 555: 
 556:         if (nbytes >= wn->max_count) {
 557:                 /* The drive can't do more then max_count at once. */
 558:                 nbytes = wn->max_count;
 559:         }
 560: 
 561:         /* First check to see if a reinitialization is needed. */
 562:         if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO);
 563: 
 564:         /* Tell the controller to transfer nbytes bytes. */
 565:         cmd.precomp = wn->precomp;
 566:         cmd.count   = (nbytes >> SECTOR_SHIFT) & BYTE;
 567:         if (wn->ldhpref & LDH_LBA) {
 568:                 cmd.sector  = (block >>  0) & 0xFF;
 569:                 cmd.cyl_lo  = (block >>  8) & 0xFF;
 570:                 cmd.cyl_hi  = (block >> 16) & 0xFF;
 571:                 cmd.ldh     = wn->ldhpref | ((block >> 24) & 0xF);
 572:         } else {
 573:                 cylinder = block / secspcyl;
 574:                 head = (block % secspcyl) / wn->psectors;
 575:                 sector = block % wn->psectors;
 576:                 cmd.sector  = sector + 1;
 577:                 cmd.cyl_lo  = cylinder & BYTE;
 578:                 cmd.cyl_hi  = (cylinder >> 8) & BYTE;
 579:                 cmd.ldh     = wn->ldhpref | head;
 580:         }
 581:         cmd.command = opcode == DEV_SCATTER ? CMD_WRITE : CMD_READ;
 582: 
 583:         r = com_out(&cmd);
 584: 
 585:         while (r == OK && nbytes > 0) {
 586:                 /* For each sector, wait for an interrupt and fetch the data
 587:                  * (read), or supply data to the controller and wait for an
 588:                  * interrupt (write).
 589:                  */
 590: 
 591:                 if (opcode == DEV_GATHER) {
 592:                         /* First an interrupt, then data. */
 593:                         if ((r = at_intr_wait()) != OK) {
 594:                                 /* An error, send data to the bit bucket. */
 595:                                 if (w_status & STATUS_DRQ) {
 596:                                         phys_insw(w_wn->base + REG_DATA,
 597:                                                 tmp_phys, SECTOR_SIZE);
 598:                                 }
 599:                                 break;
 600:                         }
 601:                 }
 602: 
 603:                 /* Wait for data transfer requested. */
 604:                 if (!w_waitfor(STATUS_DRQ, STATUS_DRQ)) { r = ERR; break; }
 605: 
 606:                 /* Copy bytes to or from the device's buffer. */
 607:                 if (opcode == DEV_GATHER) {
 608:                         phys_insw(w_wn->base + REG_DATA,
 609:                                 user_base + iov->iov_addr, SECTOR_SIZE);
 610:                 } else {
 611:                         phys_outsw(w_wn->base + REG_DATA,
 612:                                 user_base + iov->iov_addr, SECTOR_SIZE);
 613: 
 614:                         /* Data sent, wait for an interrupt. */
 615:                         if ((r = at_intr_wait()) != OK) break;
 616:                 }
 617: 
 618:                 /* Book the bytes successfully transferred. */
 619:                 nbytes -= SECTOR_SIZE;
 620:                 position += SECTOR_SIZE;
 621:                 iov->iov_addr += SECTOR_SIZE;
 622:                 if ((iov->iov_size -= SECTOR_SIZE) == 0) { iov++; nr_req--; }
 623:         }
 624: 
 625:         /* Any errors? */
 626:         if (r != OK) {
 627:                 /* Don't retry if sector marked bad or too many errors. */
 628:                 if (r == ERR_BAD_SECTOR || ++errors == MAX_ERRORS) {
 629:                         w_command = CMD_IDLE;
 630:                         return(EIO);
 631:                 }
 632:         }
 633:   }
 634: 
 635:   w_command = CMD_IDLE;
 636:   return(OK);
 637: }
 638: 
 639: 
 640: /*============================================================================*
 641:  *                              com_out                                       *
 642:  *============================================================================*/
 643: PRIVATE int com_out(cmd)
 644: struct command *cmd;            /* Command block */
 645: {
 646: /* Output the command block to the winchester controller and return status */
 647: 
 648:   struct wini *wn = w_wn;
 649:   unsigned base = wn->base;
 650: 
 651:   if (!w_waitfor(STATUS_BSY, 0)) {
 652:         printf("%s: controller not ready\n", w_name());
 653:         return(ERR);
 654:   }
 655: 
 656:   /* Select drive. */
 657:   outb(base + REG_LDH, cmd->ldh);
 658: 
 659:   if (!w_waitfor(STATUS_BSY, 0)) {
 660:         printf("%s: drive not ready\n", w_name());
 661:         return(ERR);
 662:   }
 663: 
 664:   /* Schedule a wakeup call, some controllers are flaky. */
 665:   tmr_settimer(&w_tmr_timeout, CLOCK, get_uptime() + WAKEUP, w_timeout);
 666: 
 667:   outb(base + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS : 0);
 668:   outb(base + REG_PRECOMP, cmd->precomp);
 669:   outb(base + REG_COUNT, cmd->count);
 670:   outb(base + REG_SECTOR, cmd->sector);
 671:   outb(base + REG_CYL_LO, cmd->cyl_lo);
 672:   outb(base + REG_CYL_HI, cmd->cyl_hi);
 673:   w_status = STATUS_ADMBSY;
 674:   outb(base + REG_COMMAND, w_command = cmd->command);
 675:   return(OK);
 676: }
 677: 
 678: 
 679: /*===========================================================================*
 680:  *                              w_need_reset                                 *
 681:  *===========================================================================*/
 682: PRIVATE void w_need_reset()
 683: {
 684: /* The controller needs to be reset. */
 685:   struct wini *wn;
 686: 
 687:   for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
 688:         wn->state |= DEAF;
 689:         wn->state &= ~INITIALIZED;
 690:   }
 691: }
 692: 
 693: 
 694: /*============================================================================*
 695:  *                              w_do_close                                    *
 696:  *============================================================================*/
 697: PRIVATE int w_do_close(dp, m_ptr)
 698: struct driver *dp;
 699: message *m_ptr;
 700: {
 701: /* Device close: Release a device. */
 702: 
 703:   if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
 704:   w_wn->open_ct--;
 705: #if ENABLE_ATAPI
 706:   if (w_wn->open_ct == 0 && (w_wn->state & ATAPI)) atapi_close();
 707: #endif
 708:   return(OK);
 709: }
 710: 
 711: 
 712: /*============================================================================*
 713:  *                              com_simple                                    *
 714:  *============================================================================*/
 715: PRIVATE int com_simple(cmd)
 716: struct command *cmd;            /* Command block */
 717: {
 718: /* A simple controller command, only one interrupt and no data-out phase. */
 719:   int r;
 720: 
 721:   if ((r = com_out(cmd)) == OK) r = at_intr_wait();
 722:   w_command = CMD_IDLE;
 723:   return(r);
 724: }
 725: 
 726: 
 727: /*===========================================================================*
 728:  *                              w_timeout                                    *
 729:  *===========================================================================*/
 730: PRIVATE void w_timeout(tp)
 731: timer_t *tp;
 732: {
 733:   struct wini *wn = w_wn;
 734: 
 735:   switch (w_command) {
 736:   case CMD_IDLE:
 737:         break;          /* fine */
 738:   case CMD_READ:
 739:   case CMD_WRITE:
 740:         /* Impossible, but not on PC's:  The controller does not respond. */
 741: 
 742:         /* Limiting multisector I/O seems to help. */
 743:         if (wn->max_count > 8 * SECTOR_SIZE) {
 744:                 wn->max_count = 8 * SECTOR_SIZE;
 745:         } else {
 746:                 wn->max_count = SECTOR_SIZE;
 747:         }
 748:         /*FALL THROUGH*/
 749:   default:
 750:         /* Some other command. */
 751:         printf("%s: timeout on command %02x\n", w_name(), w_command);
 752:         w_need_reset();
 753:         w_status = 0;
 754:         interrupt(win_tasknr);
 755:   }
 756: }
 757: 
 758: 
 759: /*===========================================================================*
 760:  *                              w_reset                                      *
 761:  *===========================================================================*/
 762: PRIVATE int w_reset()
 763: {
 764: /* Issue a reset to the controller.  This is done after any catastrophe,
 765:  * like the controller refusing to respond.
 766:  */
 767: 
 768:   struct wini *wn;
 769: 
 770:   /* Wait for any internal drive recovery. */
 771:   micro_delay(RECOVERYTIME);
 772: 
 773:   /* Strobe reset bit */
 774:   outb(w_wn->base + REG_CTL, CTL_RESET);
 775:   micro_delay(1000L);
 776:   outb(w_wn->base + REG_CTL, 0);
 777:   micro_delay(1000L);
 778: 
 779:   /* Wait for controller ready */
 780:   if (!w_waitfor(STATUS_BSY, 0)) {
 781:         printf("%s: reset failed, drive busy\n", w_name());
 782:         return(ERR);
 783:   }
 784: 
 785:   /* The error register should be checked now, but some drives mess it up. */
 786: 
 787:   for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
 788:         if (wn->base == w_wn->base) wn->state &= ~DEAF;
 789:   }
 790:   return(OK);
 791: }
 792: 
 793: 
 794: /*============================================================================*
 795:  *                              w_intr_wait                                   *
 796:  *============================================================================*/
 797: PRIVATE void w_intr_wait()
 798: {
 799: /* Wait for a task completion interrupt. */
 800: 
 801:   message mess;
 802: 
 803:   if (w_wn->irq != NO_IRQ) {
 804:         /* Wait for an interrupt that sets w_status to "not busy". */
 805:         while (w_status & (STATUS_ADMBSY|STATUS_BSY)) receive(HARDWARE, &mess);
 806:   } else {
 807:         /* Interrupt not yet allocated; use polling. */
 808:         (void) w_waitfor(STATUS_BSY, 0);
 809:   }
 810: }
 811: 
 812: 
 813: /*============================================================================*
 814:  *                              at_intr_wait                                  *
 815:  *============================================================================*/
 816: PRIVATE int at_intr_wait()
 817: {
 818: /* Wait for an interrupt, study the status bits and return error/success. */
 819:   int r;
 820: 
 821:   w_intr_wait();
 822:   if ((w_status & (STATUS_BSY | STATUS_WF | STATUS_ERR)) == 0) {
 823:         r = OK;
 824:   } else
 825:   if ((w_status & STATUS_ERR) && (inb(w_wn->base + REG_ERROR) & ERROR_BB)) {
 826:         r = ERR_BAD_SECTOR;     /* sector marked bad, retries won't help */
 827:   } else {
 828:         r = ERR;                /* any other error */
 829:   }
 830:   w_status |= STATUS_ADMBSY;    /* assume still busy with I/O */
 831:   return(r);
 832: }
 833: 
 834: 
 835: /*==========================================================================*
 836:  *                              w_waitfor                                   *
 837:  *==========================================================================*/
 838: PRIVATE int w_waitfor(mask, value)
 839: int mask;                       /* status mask */
 840: int value;                      /* required status */
 841: {
 842: /* Wait until controller is in the required state.  Return zero on timeout. */
 843: 
 844:   struct micro_state ms;
 845: 
 846:   micro_start(&ms);
 847:   do {
 848:        w_status = inb(w_wn->base + REG_STATUS);
 849:        if ((w_status & mask) == value) return 1;
 850:   } while (micro_elapsed(&ms) < TIMEOUT);
 851: 
 852:   w_need_reset();       /* Controller gone deaf. */
 853:   return(0);
 854: }
 855: 
 856: 
 857: /*==========================================================================*
 858:  *                              w_handler                                   *
 859:  *==========================================================================*/
 860: PRIVATE int w_handler(hook)
 861: irq_hook_t *hook;
 862: {
 863: /* Disk interrupt, send message to winchester task and reenable interrupts. */
 864: 
 865:   w_status = inb(w_wn->base + REG_STATUS);       /* acknowledge interrupt */
 866:   interrupt(win_tasknr);
 867:   return 1;
 868: }
 869: 
 870: 
 871: /*============================================================================*
 872:  *                              w_geometry                                    *
 873:  *============================================================================*/
 874: PRIVATE void w_geometry(entry)
 875: struct partition *entry;
 876: {
 877:   struct wini *wn = w_wn;
 878: 
 879:   if (wn->state & ATAPI) {                /* Make up some numbers. */
 880:         entry->cylinders = div64u(wn->part[0].dv_size, SECTOR_SIZE) / (64*32);
 881:         entry->heads = 64;
 882:         entry->sectors = 32;
 883:   } else {                              /* Return logical geometry. */
 884:         entry->cylinders = wn->lcylinders;
 885:         entry->heads = wn->lheads;
 886:         entry->sectors = wn->lsectors;
 887:   }
 888: }
 889: 
 890: 
 891: #if ENABLE_ATAPI
 892: /*===========================================================================*
 893:  *                              atapi_open                                   *
 894:  *===========================================================================*/
 895: PRIVATE int atapi_open()
 896: {
 897: /* Should load and lock the device and obtain its size.  For now just set the
 898:  * size of the device to something big.  What is really needed is a generic
 899:  * SCSI layer that does all this stuff for ATAPI and SCSI devices (kjb). (XXX)
 900:  */
 901:   w_wn->part[0].dv_size = mul64u(800L*1024, 1024);
 902:   return(OK);
 903: }
 904: 
 905: /*===========================================================================*
 906:  *                              atapi_close                                  *
 907:  *===========================================================================*/
 908: PRIVATE void atapi_close()
 909: {
 910: /* Should unlock the device.  For now do nothing.  (XXX) */
 911: }
 912: 
 913: /*===========================================================================*
 914:  *                              atapi_transfer                               *
 915:  *===========================================================================*/
 916: PRIVATE int atapi_transfer(proc_nr, opcode, position, iov, nr_req)
 917: int proc_nr;                    /* process doing the request */
 918: int opcode;                     /* DEV_GATHER or DEV_SCATTER */
 919: off_t position;                 /* offset on device to read or write */
 920: iovec_t *iov;                   /* pointer to read or write request vector */
 921: unsigned nr_req;                /* length of request vector */
 922: {
 923:   struct wini *wn = w_wn;
 924:   iovec_t *iop, *iov_end = iov + nr_req;
 925:   int r, errors, fresh;
 926:   u64_t pos;
 927:   unsigned long block;
 928:   unsigned long dv_size = cv64ul(w_dv->dv_size);
 929:   unsigned nbytes, nblocks, count, before, chunk;
 930:   phys_bytes user_base = proc_vir2phys(proc_addr(proc_nr), 0);
 931:   u8_t packet[12];
 932: 
 933:   errors = fresh = 0;
 934: 
 935:   while (nr_req > 0 && !fresh) {
 936:         /* The Minix block size is smaller than the CD block size, so we
 937:          * may have to read extra before or after the good data.
 938:          */
 939:         pos = add64ul(w_dv->dv_base, position);
 940:         block = div64u(pos, CD_SECTOR_SIZE);
 941:         before = rem64u(pos, CD_SECTOR_SIZE);
 942: 
 943:         /* How many bytes to transfer? */
 944:         nbytes = count = 0;
 945:         for (iop = iov; iop < iov_end; iop++) {
 946:                 nbytes += iop->iov_size;
 947:                 if ((before + nbytes) % CD_SECTOR_SIZE == 0) count = nbytes;
 948:         }
 949: 
 950:         /* Does one of the memory chunks end nicely on a CD sector multiple? */
 951:         if (count != 0) nbytes = count;
 952: 
 953:         /* Data comes in as words, so we have to enforce even byte counts. */
 954:         if ((before | nbytes) & 1) return(EINVAL);
 955: 
 956:         /* Which block on disk and how close to EOF? */
 957:         if (position >= dv_size) return(OK);             /* At EOF */
 958:         if (position + nbytes > dv_size) nbytes = dv_size - position;
 959: 
 960:         nblocks = (before + nbytes + CD_SECTOR_SIZE - 1) / CD_SECTOR_SIZE;
 961:         if (ATAPI_DEBUG) {
 962:                 printf("block=%lu, before=%u, nbytes=%u, nblocks=%u\n",
 963:                         block, before, nbytes, nblocks);
 964:         }
 965: 
 966:         /* First check to see if a reinitialization is needed. */
 967:         if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO);
 968: 
 969:         /* Build an ATAPI command packet. */
 970:         packet[0] = SCSI_READ10;
 971:         packet[1] = 0;
 972:         packet[2] = (block >> 24) & 0xFF;
 973:         packet[3] = (block >> 16) & 0xFF;
 974:         packet[4] = (block >>  8) & 0xFF;
 975:         packet[5] = (block >>  0) & 0xFF;
 976:         packet[7] = (nblocks >> 8) & 0xFF;
 977:         packet[8] = (nblocks >> 0) & 0xFF;
 978:         packet[9] = 0;
 979:         packet[10] = 0;
 980:         packet[11] = 0;
 981: 
 982:         /* Tell the controller to execute the packet command. */
 983:         r = atapi_sendpacket(packet, nblocks * CD_SECTOR_SIZE);
 984:         if (r != OK) goto err;
 985: 
 986:         /* Read chunks of data. */
 987:         while ((r = atapi_intr_wait()) > 0) {
 988:                 count = r;
 989: 
 990:                 if (ATAPI_DEBUG) {
 991:                         printf("before=%u, nbytes=%u, count=%u\n",
 992:                                 before, nbytes, count);
 993:                 }
 994: 
 995:                 while (before > 0 && count > 0) {   /* Discard before. */
 996:                         chunk = before;
 997:                         if (chunk > count) chunk = count;
 998:                         if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE;
 999:                         phys_insw(w_wn->base + REG_DATA, tmp_phys, chunk);
1000:                         before -= chunk;
1001:                         count -= chunk;
1002:                 }
1003: 
1004:                 while (nbytes > 0 && count > 0) {   /* Requested data. */
1005:                         chunk = nbytes;
1006:                         if (chunk > count) chunk = count;
1007:                         if (chunk > iov->iov_size) chunk = iov->iov_size;
1008:                         phys_insw(w_wn->base + REG_DATA,
1009:                                         user_base + iov->iov_addr, chunk);
1010:                         position += chunk;
1011:                         nbytes -= chunk;
1012:                         count -= chunk;
1013:                         iov->iov_addr += chunk;
1014:                         fresh = 0;
1015:                         if ((iov->iov_size -= chunk) == 0) {
1016:                                 iov++;
1017:                                 nr_req--;
1018:                                 fresh = 1;      /* new element is optional */
1019:                         }
1020:                 }
1021: 
1022:                 while (count > 0) {              /* Excess data. */
1023:                         chunk = count;
1024:                         if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE;
1025:                         phys_insw(w_wn->base + REG_DATA, tmp_phys, chunk);
1026:                         count -= chunk;
1027:                 }
1028:         }
1029: 
1030:         if (r < 0) {
1031:   err:          /* Don't retry if too many errors. */
1032:                 if (++errors == MAX_ERRORS) {
1033:                         w_command = CMD_IDLE;
1034:                         return(EIO);
1035:                 }
1036:         }
1037:   }
1038: 
1039:   w_command = CMD_IDLE;
1040:   return(OK);
1041: }
1042: 
1043: /*===========================================================================*
1044:  *                              atapi_sendpacket                             *
1045:  *===========================================================================*/
1046: PRIVATE int atapi_sendpacket(packet, cnt)
1047: u8_t *packet;
1048: unsigned cnt;
1049: {
1050: /* Send an Atapi Packet Command */
1051:   struct wini *wn = w_wn;
1052:   message mess;
1053: 
1054:   /* Select Master/Slave drive */
1055:   outb(wn->base + REG_DRIVE, wn->ldhpref);
1056: 
1057:   if (!w_waitfor(STATUS_BSY | STATUS_DRQ, 0)) {
1058:         printf("%s: drive not ready\n", w_name());
1059:         return(ERR);
1060:   }
1061: 
1062:   /* Schedule wakeup call. */
1063:   tmr_settimer(&w_tmr_timeout, CLOCK, get_uptime() + WAKEUP, w_timeout);
1064: 
1065: #if _WORD_SIZE > 2
1066:   if (cnt > 0xFFFE) cnt = 0xFFFE;        /* Max data per interrupt. */
1067: #endif
1068: 
1069:   outb(wn->base + REG_FEAT, 0);
1070:   outb(wn->base + REG_IRR, 0);
1071:   outb(wn->base + REG_SAMTAG, 0);
1072:   outb(wn->base + REG_CNT_LO, (cnt >> 0) & 0xFF);
1073:   outb(wn->base + REG_CNT_HI, (cnt >> 8) & 0xFF);
1074:   outb(wn->base + REG_COMMAND, w_command = ATAPI_PACKETCMD);
1075: 
1076:   if (!w_waitfor(STATUS_BSY | STATUS_DRQ, STATUS_DRQ)) {
1077:         printf("%s: timeout (BSY|DRQ -> DRQ)\n");
1078:         return(ERR);
1079:   }
1080:   w_status |= STATUS_ADMBSY;            /* Command not at all done yet. */
1081: 
1082:   /* Send the command packet to the device. */
1083:   outsw(wn->base + REG_DATA, packet, 12);
1084:   return(OK);
1085: }
1086: 
1087: /*============================================================================*
1088:  *                              atapi_intr_wait                               *
1089:  *============================================================================*/
1090: PRIVATE int atapi_intr_wait()
1091: {
1092: /* Wait for an interrupt and study the results.  Returns a number of bytes
1093:  * that need to be transferred, or an error code.
1094:  */
1095:   struct wini *wn = w_wn;
1096:   int e;
1097:   int len;
1098:   int irr;
1099:   int r;
1100:   int phase;
1101: 
1102:   w_intr_wait();
1103: 
1104:   e = inb(wn->base + REG_ERROR);
1105:   len = inb(wn->base + REG_CNT_LO);
1106:   len |= inb(wn->base + REG_CNT_HI) << 8;
1107:   irr = inb(wn->base + REG_IRR);
1108:   if (ATAPI_DEBUG) {
1109:         printf("S=%02x E=%02x L=%04x I=%02x\n", w_status, e, len, irr);
1110:   }
1111:   if (w_status & (STATUS_BSY | STATUS_CHECK)) return ERR;
1112: 
1113:   phase = (w_status & STATUS_DRQ) | (irr & (IRR_COD | IRR_IO));
1114: 
1115:   switch (phase) {
1116:   case IRR_COD | IRR_IO:
1117:         if (ATAPI_DEBUG) printf("ACD: Phase Command Complete\n");
1118:         r = OK;
1119:         break;
1120:   case 0:
1121:         if (ATAPI_DEBUG) printf("ACD: Phase Command Aborted\n");
1122:         r = ERR;
1123:         break;
1124:   case STATUS_DRQ | IRR_COD:
1125:         if (ATAPI_DEBUG) printf("ACD: Phase Command Out\n");
1126:         r = ERR;
1127:         break;
1128:   case STATUS_DRQ:
1129:         if (ATAPI_DEBUG) printf("ACD: Phase Data Out %d\n", len);
1130:         r = len;
1131:         break;
1132:   case STATUS_DRQ | IRR_IO:
1133:         if (ATAPI_DEBUG) printf("ACD: Phase Data In %d\n", len);
1134:         r = len;
1135:         break;
1136:   default:
1137:         if (ATAPI_DEBUG) printf("ACD: Phase Unknown\n");
1138:         r = ERR;
1139:         break;
1140:   }
1141: 
1142: #if 0
1143:   /* retry if the media changed */
1144:   XXX while (phase == (IRR_IO | IRR_COD) && (w_status & STATUS_CHECK)
1145:         && (e & ERROR_SENSE) == SENSE_UATTN && --try > 0);
1146: #endif
1147: 
1148:   w_status |= STATUS_ADMBSY;    /* Assume not done yet. */
1149:   return(r);
1150: }
1151: #endif /* ENABLE_ATAPI */
1152: #endif /* ENABLE_AT_WINI */