at_wini.c

Go to the documentation of this file.
00001 /* This file contains the device dependent part of a driver for the IBM-AT
00002  * winchester controller.  Written by Adri Koppes.
00003  *
00004  * The file contains one entry point:
00005  *
00006  *   at_winchester_task:        main entry when system is brought up
00007  *
00008  * Changes:
00009  *   Aug 19, 2005   ATA PCI support, supports SATA  (Ben Gras)
00010  *   Nov 18, 2004   moved AT disk driver to user-space  (Jorrit N. Herder)
00011  *   Aug 20, 2004   watchdogs replaced by sync alarms  (Jorrit N. Herder)
00012  *   Mar 23, 2000   added ATAPI CDROM support  (Michael Temari)
00013  *   May 14, 2000   d-d/i rewrite  (Kees J. Bot)
00014  *   Apr 13, 1992   device dependent/independent split  (Kees J. Bot)
00015  */
00016 
00017 #include "at_wini.h"
00018 
00019 #include <minix/sysutil.h>
00020 #include <minix/keymap.h>
00021 #include <sys/ioc_disk.h>
00022 #include <ibm/pci.h>
00023 
00024 #define ATAPI_DEBUG         0   /* To debug ATAPI code. */
00025 
00026 /* I/O Ports used by winchester disk controllers. */
00027 
00028 /* Read and write registers */
00029 #define REG_CMD_BASE0   0x1F0   /* command base register of controller 0 */
00030 #define REG_CMD_BASE1   0x170   /* command base register of controller 1 */
00031 #define REG_CTL_BASE0   0x3F6   /* control base register of controller 0 */
00032 #define REG_CTL_BASE1   0x376   /* control base register of controller 1 */
00033 
00034 #define PCI_CTL_OFF         2   /* Offset of control registers from BAR2 */
00035 #define PCI_DMA_2ND_OFF     8   /* Offset of DMA registers from BAR4 for 
00036                                  * secondary channel
00037                                  */
00038 
00039 #define REG_DATA            0   /* data register (offset from the base reg.) */
00040 #define REG_PRECOMP         1   /* start of write precompensation */
00041 #define REG_COUNT           2   /* sectors to transfer */
00042 #define REG_SECTOR          3   /* sector number */
00043 #define REG_CYL_LO          4   /* low byte of cylinder number */
00044 #define REG_CYL_HI          5   /* high byte of cylinder number */
00045 #define REG_LDH             6   /* lba, drive and head */
00046 #define   LDH_DEFAULT           0xA0    /* ECC enable, 512 bytes per sector */
00047 #define   LDH_LBA               0x40    /* Use LBA addressing */
00048 #define   LDH_DEV               0x10    /* Drive 1 iff set */
00049 #define   ldh_init(drive)       (LDH_DEFAULT | ((drive) << 4))
00050 
00051 /* Read only registers */
00052 #define REG_STATUS          7   /* status */
00053 #define   STATUS_BSY            0x80    /* controller busy */
00054 #define   STATUS_RDY            0x40    /* drive ready */
00055 #define   STATUS_WF             0x20    /* write fault */
00056 #define   STATUS_SC             0x10    /* seek complete (obsolete) */
00057 #define   STATUS_DRQ            0x08    /* data transfer request */
00058 #define   STATUS_CRD            0x04    /* corrected data */
00059 #define   STATUS_IDX            0x02    /* index pulse */
00060 #define   STATUS_ERR            0x01    /* error */
00061 #define   STATUS_ADMBSY        0x100    /* administratively busy (software) */
00062 #define REG_ERROR           1   /* error code */
00063 #define   ERROR_BB              0x80    /* bad block */
00064 #define   ERROR_ECC             0x40    /* bad ecc bytes */
00065 #define   ERROR_ID              0x10    /* id not found */
00066 #define   ERROR_AC              0x04    /* aborted command */
00067 #define   ERROR_TK              0x02    /* track zero error */
00068 #define   ERROR_DM              0x01    /* no data address mark */
00069 
00070 /* Write only registers */
00071 #define REG_COMMAND         7   /* command */
00072 #define   CMD_IDLE              0x00    /* for w_command: drive idle */
00073 #define   CMD_RECALIBRATE       0x10    /* recalibrate drive */
00074 #define   CMD_READ              0x20    /* read data */
00075 #define   CMD_READ_EXT          0x24    /* read data (LBA48 addressed) */
00076 #define   CMD_READ_DMA_EXT      0x25    /* read data using DMA (w/ LBA48) */
00077 #define   CMD_WRITE             0x30    /* write data */
00078 #define   CMD_WRITE_EXT         0x34    /* write data (LBA48 addressed) */
00079 #define   CMD_WRITE_DMA_EXT     0x35    /* write data using DMA (w/ LBA48) */
00080 #define   CMD_READVERIFY        0x40    /* read verify */
00081 #define   CMD_FORMAT            0x50    /* format track */
00082 #define   CMD_SEEK              0x70    /* seek cylinder */
00083 #define   CMD_DIAG              0x90    /* execute device diagnostics */
00084 #define   CMD_SPECIFY           0x91    /* specify parameters */
00085 #define   CMD_READ_DMA          0xC8    /* read data using DMA */
00086 #define   CMD_WRITE_DMA         0xCA    /* write data using DMA */
00087 #define   ATA_IDENTIFY          0xEC    /* identify drive */
00088 /* #define REG_CTL              0x206   */ /* control register */
00089 #define REG_CTL         0       /* control register */
00090 #define   CTL_NORETRY           0x80    /* disable access retry */
00091 #define   CTL_NOECC             0x40    /* disable ecc retry */
00092 #define   CTL_EIGHTHEADS        0x08    /* more than eight heads */
00093 #define   CTL_RESET             0x04    /* reset controller */
00094 #define   CTL_INTDISABLE        0x02    /* disable interrupts */
00095 #define REG_CTL_ALTSTAT 0       /* alternate status register */
00096 
00097 /* Identify words */
00098 #define ID_GENERAL              0x00    /* General configuration information */
00099 #define         ID_GEN_NOT_ATA          0x8000  /* Not an ATA device */
00100 #define ID_CAPABILITIES         0x31    /* Capabilities (49)*/
00101 #define         ID_CAP_LBA              0x0200  /* LBA supported */
00102 #define         ID_CAP_DMA              0x0100  /* DMA supported */
00103 #define ID_FIELD_VALIDITY       0x35    /* Field Validity (53) */
00104 #define         ID_FV_88                0x04    /* Word 88 is valid (UDMA) */
00105 #define ID_MULTIWORD_DMA        0x3f    /* Multiword DMA (63) */
00106 #define         ID_MWDMA_2_SEL          0x0400  /* Mode 2 is selected */
00107 #define         ID_MWDMA_1_SEL          0x0200  /* Mode 1 is selected */
00108 #define         ID_MWDMA_0_SEL          0x0100  /* Mode 0 is selected */
00109 #define         ID_MWDMA_2_SUP          0x0004  /* Mode 2 is supported */
00110 #define         ID_MWDMA_1_SUP          0x0002  /* Mode 1 is supported */
00111 #define         ID_MWDMA_0_SUP          0x0001  /* Mode 0 is supported */
00112 #define ID_CSS                  0x53    /* Command Sets Supported (83) */
00113 #define         ID_CSS_LBA48            0x0400
00114 #define ID_ULTRA_DMA            0x58    /* Ultra DMA (88) */
00115 #define         ID_UDMA_5_SEL           0x2000  /* Mode 5 is selected */
00116 #define         ID_UDMA_4_SEL           0x1000  /* Mode 4 is selected */
00117 #define         ID_UDMA_3_SEL           0x0800  /* Mode 3 is selected */
00118 #define         ID_UDMA_2_SEL           0x0400  /* Mode 2 is selected */
00119 #define         ID_UDMA_1_SEL           0x0200  /* Mode 1 is selected */
00120 #define         ID_UDMA_0_SEL           0x0100  /* Mode 0 is selected */
00121 #define         ID_UDMA_5_SUP           0x0020  /* Mode 5 is supported */
00122 #define         ID_UDMA_4_SUP           0x0010  /* Mode 4 is supported */
00123 #define         ID_UDMA_3_SUP           0x0008  /* Mode 3 is supported */
00124 #define         ID_UDMA_2_SUP           0x0004  /* Mode 2 is supported */
00125 #define         ID_UDMA_1_SUP           0x0002  /* Mode 1 is supported */
00126 #define         ID_UDMA_0_SUP           0x0001  /* Mode 0 is supported */
00127 
00128 /* DMA registers */
00129 #define DMA_COMMAND             0               /* Command register */
00130 #define         DMA_CMD_WRITE           0x08    /* PCI bus master writes */
00131 #define         DMA_CMD_START           0x01    /* Start Bus Master */
00132 #define DMA_STATUS              2               /* Status register */
00133 #define         DMA_ST_D1_DMACAP        0x40    /* Drive 1 is DMA capable */
00134 #define         DMA_ST_D0_DMACAP        0x20    /* Drive 0 is DMA capable */
00135 #define         DMA_ST_INT              0x04    /* Interrupt */
00136 #define         DMA_ST_ERROR            0x02    /* Error */
00137 #define         DMA_ST_BM_ACTIVE        0x01    /* Bus Master IDE Active */
00138 #define DMA_PRDTP               4               /* PRD Table Pointer */
00139 
00140 /* Check for the presence of LBA48 only on drives that are 'big'. */
00141 #define LBA48_CHECK_SIZE        0x0f000000
00142 #define LBA_MAX_SIZE            0x0fffffff      /* Highest sector size for
00143                                                  * regular LBA.
00144                                                  */
00145 
00146 #if ENABLE_ATAPI
00147 #define   ERROR_SENSE           0xF0    /* sense key mask */
00148 #define     SENSE_NONE          0x00    /* no sense key */
00149 #define     SENSE_RECERR        0x10    /* recovered error */
00150 #define     SENSE_NOTRDY        0x20    /* not ready */
00151 #define     SENSE_MEDERR        0x30    /* medium error */
00152 #define     SENSE_HRDERR        0x40    /* hardware error */
00153 #define     SENSE_ILRQST        0x50    /* illegal request */
00154 #define     SENSE_UATTN         0x60    /* unit attention */
00155 #define     SENSE_DPROT         0x70    /* data protect */
00156 #define     SENSE_ABRT          0xb0    /* aborted command */
00157 #define     SENSE_MISCOM        0xe0    /* miscompare */
00158 #define   ERROR_MCR             0x08    /* media change requested */
00159 #define   ERROR_ABRT            0x04    /* aborted command */
00160 #define   ERROR_EOM             0x02    /* end of media detected */
00161 #define   ERROR_ILI             0x01    /* illegal length indication */
00162 #define REG_FEAT            1   /* features */
00163 #define   FEAT_OVERLAP          0x02    /* overlap */
00164 #define   FEAT_DMA              0x01    /* dma */
00165 #define REG_IRR             2   /* interrupt reason register */
00166 #define   IRR_REL               0x04    /* release */
00167 #define   IRR_IO                0x02    /* direction for xfer */
00168 #define   IRR_COD               0x01    /* command or data */
00169 #define REG_SAMTAG          3
00170 #define REG_CNT_LO          4   /* low byte of cylinder number */
00171 #define REG_CNT_HI          5   /* high byte of cylinder number */
00172 #define REG_DRIVE           6   /* drive select */
00173 #endif
00174 
00175 #define REG_STATUS          7   /* status */
00176 #define   STATUS_BSY            0x80    /* controller busy */
00177 #define   STATUS_DRDY           0x40    /* drive ready */
00178 #define   STATUS_DMADF          0x20    /* dma ready/drive fault */
00179 #define   STATUS_SRVCDSC        0x10    /* service or dsc */
00180 #define   STATUS_DRQ            0x08    /* data transfer request */
00181 #define   STATUS_CORR           0x04    /* correctable error occurred */
00182 #define   STATUS_CHECK          0x01    /* check error */
00183 
00184 #ifdef ENABLE_ATAPI
00185 #define   ATAPI_PACKETCMD       0xA0    /* packet command */
00186 #define   ATAPI_IDENTIFY        0xA1    /* identify drive */
00187 #define   SCSI_READ10           0x28    /* read from disk */
00188 #define   SCSI_SENSE            0x03    /* sense request */
00189 
00190 #define CD_SECTOR_SIZE          2048    /* sector size of a CD-ROM */
00191 #endif /* ATAPI */
00192 
00193 /* Interrupt request lines. */
00194 #define NO_IRQ           0      /* no IRQ set yet */
00195 
00196 #define ATAPI_PACKETSIZE        12
00197 #define SENSE_PACKETSIZE        18
00198 
00199 /* Common command block */
00200 struct command {
00201   u8_t  precomp;        /* REG_PRECOMP, etc. */
00202   u8_t  count;
00203   u8_t  sector;
00204   u8_t  cyl_lo;
00205   u8_t  cyl_hi;
00206   u8_t  ldh;
00207   u8_t  command;
00208 
00209   /* The following at for LBA48 */
00210   u8_t  count_prev;
00211   u8_t  sector_prev;
00212   u8_t  cyl_lo_prev;
00213   u8_t  cyl_hi_prev;
00214 };
00215 
00216 /* Error codes */
00217 #define ERR              (-1)   /* general error */
00218 #define ERR_BAD_SECTOR   (-2)   /* block marked bad detected */
00219 
00220 /* Some controllers don't interrupt, the clock will wake us up. */
00221 #define WAKEUP          (32*HZ) /* drive may be out for 31 seconds max */
00222 
00223 /* Miscellaneous. */
00224 #define MAX_DRIVES         8
00225 #define COMPAT_DRIVES      4
00226 #if _WORD_SIZE > 2
00227 #define MAX_SECS         256    /* controller can transfer this many sectors */
00228 #else
00229 #define MAX_SECS         127    /* but not to a 16 bit process */
00230 #endif
00231 #define MAX_ERRORS         4    /* how often to try rd/wt before quitting */
00232 #define NR_MINORS       (MAX_DRIVES * DEV_PER_DRIVE)
00233 #define SUB_PER_DRIVE   (NR_PARTITIONS * NR_PARTITIONS)
00234 #define NR_SUBDEVS      (MAX_DRIVES * SUB_PER_DRIVE)
00235 #define DELAY_USECS     1000    /* controller timeout in microseconds */
00236 #define DELAY_TICKS        1    /* controller timeout in ticks */
00237 #define DEF_TIMEOUT_TICKS       300     /* controller timeout in ticks */
00238 #define RECOVERY_USECS 500000   /* controller recovery time in microseconds */
00239 #define RECOVERY_TICKS    30    /* controller recovery time in ticks */
00240 #define INITIALIZED     0x01    /* drive is initialized */
00241 #define DEAF            0x02    /* controller must be reset */
00242 #define SMART           0x04    /* drive supports ATA commands */
00243 #if ENABLE_ATAPI
00244 #define ATAPI           0x08    /* it is an ATAPI device */
00245 #else
00246 #define ATAPI              0    /* don't bother with ATAPI; optimise out */
00247 #endif
00248 #define IDENTIFIED      0x10    /* w_identify done successfully */
00249 #define IGNORING        0x20    /* w_identify failed once */
00250 
00251 /* Timeouts and max retries. */
00252 int timeout_ticks = DEF_TIMEOUT_TICKS, max_errors = MAX_ERRORS;
00253 int wakeup_ticks = WAKEUP;
00254 long w_standard_timeouts = 0, w_pci_debug = 0, w_instance = 0,
00255         disable_dma = 0, atapi_debug = 0;
00256 
00257 int w_testing = 0, w_silent = 0;
00258 
00259 int w_next_drive = 0;
00260 
00261 /* Variables. */
00262 
00263 /* The struct wini is indexed by controller first, then drive (0-3).
00264  * Controller 0 is always the 'compatability' ide controller, at
00265  * the fixed locations, whether present or not.
00266  */
00267 PRIVATE struct wini {           /* main drive struct, one entry per drive */
00268   unsigned state;               /* drive state: deaf, initialized, dead */
00269   unsigned short w_status;      /* device status register */
00270   unsigned base_cmd;            /* command base register */
00271   unsigned base_ctl;            /* control base register */
00272   unsigned base_dma;            /* dma base register */
00273   unsigned irq;                 /* interrupt request line */
00274   unsigned irq_mask;            /* 1 << irq */
00275   unsigned irq_need_ack;        /* irq needs to be acknowledged */
00276   int irq_hook_id;              /* id of irq hook at the kernel */
00277   int lba48;                    /* supports lba48 */
00278   int dma;                      /* supports dma */
00279   unsigned lcylinders;          /* logical number of cylinders (BIOS) */
00280   unsigned lheads;              /* logical number of heads */
00281   unsigned lsectors;            /* logical number of sectors per track */
00282   unsigned pcylinders;          /* physical number of cylinders (translated) */
00283   unsigned pheads;              /* physical number of heads */
00284   unsigned psectors;            /* physical number of sectors per track */
00285   unsigned ldhpref;             /* top four bytes of the LDH (head) register */
00286   unsigned precomp;             /* write precompensation cylinder / 4 */
00287   unsigned max_count;           /* max request for this drive */
00288   unsigned open_ct;             /* in-use count */
00289   struct device part[DEV_PER_DRIVE];    /* disks and partitions */
00290   struct device subpart[SUB_PER_DRIVE]; /* subpartitions */
00291 } wini[MAX_DRIVES], *w_wn;
00292 
00293 PRIVATE int w_device = -1;
00294 PRIVATE int w_controller = -1;
00295 PRIVATE int w_major = -1;
00296 PRIVATE char w_id_string[40];
00297 
00298 PRIVATE int win_tasknr;                 /* my task number */
00299 PRIVATE int w_command;                  /* current command in execution */
00300 PRIVATE u8_t w_byteval;                 /* used for SYS_IRQCTL */
00301 PRIVATE int w_drive;                    /* selected drive */
00302 PRIVATE int w_controller;               /* selected controller */
00303 PRIVATE struct device *w_dv;            /* device's base and size */
00304 
00305 /* Unfortunately, DMA_SECTORS and DMA_BUF_SIZE are already defined libdriver
00306  * for 'tmp_buf'.
00307  */
00308 #define ATA_DMA_SECTORS 64
00309 #define ATA_DMA_BUF_SIZE        (ATA_DMA_SECTORS*SECTOR_SIZE)
00310 
00311 PRIVATE char dma_buf[ATA_DMA_BUF_SIZE];
00312 PRIVATE phys_bytes dma_buf_phys;
00313 
00314 #define N_PRDTE 1024    /* Should be enough for large requests */
00315 
00316 PRIVATE struct prdte
00317 {
00318         u32_t prdte_base;
00319         u16_t prdte_count;
00320         u8_t prdte_reserved;
00321         u8_t prdte_flags;
00322 } prdt[N_PRDTE];
00323 PRIVATE phys_bytes prdt_phys;
00324 
00325 #define PRDTE_FL_EOT    0x80    /* End of table */
00326 
00327 /* Some IDE devices announce themselves as RAID controllers */
00328 PRIVATE struct
00329 {
00330         u16_t vendor;
00331         u16_t device;
00332 } raid_table[]=
00333 {
00334         { 0x1106,       0x3149  },      /* VIA VT6420 */
00335         { 0,            0       }       /* end of list */
00336 };
00337 
00338 FORWARD _PROTOTYPE( void init_params, (void)                            );
00339 FORWARD _PROTOTYPE( void init_drive, (struct wini *w, int base_cmd,
00340         int base_ctl, int base_dma, int irq, int ack, int hook,
00341                                                         int drive)      );
00342 FORWARD _PROTOTYPE( void init_params_pci, (int)                         );
00343 FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr)  );
00344 FORWARD _PROTOTYPE( struct device *w_prepare, (int dev)                 );
00345 FORWARD _PROTOTYPE( int w_identify, (void)                              );
00346 FORWARD _PROTOTYPE( char *w_name, (void)                                );
00347 FORWARD _PROTOTYPE( int w_specify, (void)                               );
00348 FORWARD _PROTOTYPE( int w_io_test, (void)                               );
00349 FORWARD _PROTOTYPE( int w_transfer, (int proc_nr, int opcode, off_t position,
00350                                         iovec_t *iov, unsigned nr_req)  );
00351 FORWARD _PROTOTYPE( int com_out, (struct command *cmd)                  );
00352 FORWARD _PROTOTYPE( int com_out_ext, (struct command *cmd)              );
00353 FORWARD _PROTOTYPE( void setup_dma, (unsigned *sizep, int proc_nr,
00354                         iovec_t *iov, int do_write, int *do_copyoutp)   );
00355 FORWARD _PROTOTYPE( void w_need_reset, (void)                           );
00356 FORWARD _PROTOTYPE( void ack_irqs, (unsigned int)                       );
00357 FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
00358 FORWARD _PROTOTYPE( int w_other, (struct driver *dp, message *m_ptr)    );
00359 FORWARD _PROTOTYPE( int w_hw_int, (struct driver *dp, message *m_ptr)   );
00360 FORWARD _PROTOTYPE( int com_simple, (struct command *cmd)               );
00361 FORWARD _PROTOTYPE( void w_timeout, (void)                              );
00362 FORWARD _PROTOTYPE( int w_reset, (void)                                 );
00363 FORWARD _PROTOTYPE( void w_intr_wait, (void)                            );
00364 FORWARD _PROTOTYPE( int at_intr_wait, (void)                            );
00365 FORWARD _PROTOTYPE( int w_waitfor, (int mask, int value)                );
00366 FORWARD _PROTOTYPE( int w_waitfor_dma, (int mask, int value)            );
00367 FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry)          );
00368 #if ENABLE_ATAPI
00369 FORWARD _PROTOTYPE( int atapi_sendpacket, (u8_t *packet, unsigned cnt)  );
00370 FORWARD _PROTOTYPE( int atapi_intr_wait, (void)                         );
00371 FORWARD _PROTOTYPE( int atapi_open, (void)                              );
00372 FORWARD _PROTOTYPE( void atapi_close, (void)                            );
00373 FORWARD _PROTOTYPE( int atapi_transfer, (int proc_nr, int opcode,
00374                         off_t position, iovec_t *iov, unsigned nr_req)  );
00375 #endif
00376 
00377 /* Entry points to this driver. */
00378 PRIVATE struct driver w_dtab = {
00379   w_name,               /* current device's name */
00380   w_do_open,            /* open or mount request, initialize device */
00381   w_do_close,           /* release device */
00382   do_diocntl,           /* get or set a partition's geometry */
00383   w_prepare,            /* prepare for I/O on a given minor device */
00384   w_transfer,           /* do the I/O */
00385   nop_cleanup,          /* nothing to clean up */
00386   w_geometry,           /* tell the geometry of the disk */
00387   nop_signal,           /* no cleanup needed on shutdown */
00388   nop_alarm,            /* ignore leftover alarms */
00389   nop_cancel,           /* ignore CANCELs */
00390   nop_select,           /* ignore selects */
00391   w_other,              /* catch-all for unrecognized commands and ioctls */
00392   w_hw_int              /* leftover hardware interrupts */
00393 };
00394 
00395 /*===========================================================================*
00396  *                              at_winchester_task                           *
00397  *===========================================================================*/
00398 PUBLIC int main()
00399 {
00400 /* Install signal handlers. Ask PM to transform signal into message. */
00401   struct sigaction sa;
00402 
00403   sa.sa_handler = SIG_MESS;
00404   sigemptyset(&sa.sa_mask);
00405   sa.sa_flags = 0;
00406   if (sigaction(SIGTERM,&sa,NULL)<0) panic("AT","sigaction failed", errno);
00407 
00408   /* Set special disk parameters then call the generic main loop. */
00409   init_params();
00410   signal(SIGTERM, SIG_IGN);
00411   driver_task(&w_dtab);
00412   return(OK);
00413 }
00414 
00415 /*===========================================================================*
00416  *                              init_params                                  *
00417  *===========================================================================*/
00418 PRIVATE void init_params()
00419 {
00420 /* This routine is called at startup to initialize the drive parameters. */
00421 
00422   u16_t parv[2];
00423   unsigned int vector, size;
00424   int drive, nr_drives;
00425   struct wini *wn;
00426   u8_t params[16];
00427   int s;
00428 
00429   /* Boot variables. */
00430   env_parse("ata_std_timeout", "d", 0, &w_standard_timeouts, 0, 1);
00431   env_parse("ata_pci_debug", "d", 0, &w_pci_debug, 0, 1);
00432   env_parse("ata_instance", "d", 0, &w_instance, 0, 8);
00433   env_parse("ata_no_dma", "d", 0, &disable_dma, 0, 1);
00434   env_parse("atapi_debug", "d", 0, &atapi_debug, 0, 1);
00435 
00436   if (disable_dma)
00437         printf("DMA for ATA devices is disabled.\n");
00438 
00439   s= sys_umap(SELF, D, (vir_bytes)dma_buf, sizeof(dma_buf), &dma_buf_phys);
00440   if (s != 0)
00441         panic("at_wini", "can't map dma buffer", s);
00442 
00443   s= sys_umap(SELF, D, (vir_bytes)prdt, sizeof(prdt), &prdt_phys);
00444   if (s != 0)
00445         panic("at_wini", "can't map prd table", s);
00446 
00447   if (w_instance == 0) {
00448           /* Get the number of drives from the BIOS data area */
00449           if ((s=sys_vircopy(SELF, BIOS_SEG, NR_HD_DRIVES_ADDR, 
00450                         SELF, D, (vir_bytes) params, NR_HD_DRIVES_SIZE)) != OK)
00451                 panic(w_name(), "Couldn't read BIOS", s);
00452           if ((nr_drives = params[0]) > 2) nr_drives = 2;
00453 
00454           for (drive = 0, wn = wini; drive < COMPAT_DRIVES; drive++, wn++) {
00455                 if (drive < nr_drives) {
00456                     /* Copy the BIOS parameter vector */
00457                     vector = (drive == 0) ? BIOS_HD0_PARAMS_ADDR:BIOS_HD1_PARAMS_ADDR;
00458                     size = (drive == 0) ? BIOS_HD0_PARAMS_SIZE:BIOS_HD1_PARAMS_SIZE;
00459                     if ((s=sys_vircopy(SELF, BIOS_SEG, vector,
00460                                         SELF, D, (vir_bytes) parv, size)) != OK)
00461                                 panic(w_name(), "Couldn't read BIOS", s);
00462         
00463                         /* Calculate the address of the parameters and copy them */
00464                         if ((s=sys_vircopy(
00465                                 SELF, BIOS_SEG, hclick_to_physb(parv[1]) + parv[0],
00466                                 SELF, D, (phys_bytes) params, 16L))!=OK)
00467                             panic(w_name(),"Couldn't copy parameters", s);
00468         
00469                         /* Copy the parameters to the structures of the drive */
00470                         wn->lcylinders = bp_cylinders(params);
00471                         wn->lheads = bp_heads(params);
00472                         wn->lsectors = bp_sectors(params);
00473                         wn->precomp = bp_precomp(params) >> 2;
00474                 }
00475 
00476                 /* Fill in non-BIOS parameters. */
00477                 init_drive(wn,
00478                         drive < 2 ? REG_CMD_BASE0 : REG_CMD_BASE1,
00479                         drive < 2 ? REG_CTL_BASE0 : REG_CTL_BASE1,
00480                         0 /* no DMA */, NO_IRQ, 0, 0, drive);
00481                 w_next_drive++;
00482         }
00483   }
00484 
00485   /* Look for controllers on the pci bus. Skip none the first instance,
00486    * skip one and then 2 for every instance, for every next instance.
00487    */
00488   if (w_instance == 0)
00489         init_params_pci(0);
00490   else
00491         init_params_pci(w_instance*2-1);
00492 
00493 }
00494 
00495 #define ATA_IF_NOTCOMPAT1 (1L << 0)
00496 #define ATA_IF_NOTCOMPAT2 (1L << 2)
00497 
00498 /*===========================================================================*
00499  *                              init_drive                                   *
00500  *===========================================================================*/
00501 PRIVATE void init_drive(struct wini *w, int base_cmd, int base_ctl,
00502         int base_dma, int irq, int ack, int hook, int drive)
00503 {
00504         w->state = 0;
00505         w->w_status = 0;
00506         w->base_cmd = base_cmd;
00507         w->base_ctl = base_ctl;
00508         w->base_dma = base_dma;
00509         w->irq = irq;
00510         w->irq_mask = 1 << irq;
00511         w->irq_need_ack = ack;
00512         w->irq_hook_id = hook;
00513         w->ldhpref = ldh_init(drive);
00514         w->max_count = MAX_SECS << SECTOR_SHIFT;
00515         w->lba48 = 0;
00516         w->dma = 0;
00517 }
00518 
00519 /*===========================================================================*
00520  *                              init_params_pci                              *
00521  *===========================================================================*/
00522 PRIVATE void init_params_pci(int skip)
00523 {
00524   int i, r, devind, drive;
00525   int irq, irq_hook, raid;
00526   u8_t bcr, scr, interface;
00527   u16_t vid, did;
00528   u32_t base_dma, t3;
00529 
00530   pci_init();
00531   for(drive = w_next_drive; drive < MAX_DRIVES; drive++)
00532         wini[drive].state = IGNORING;
00533   for(r = pci_first_dev(&devind, &vid, &did); r != 0;
00534         r = pci_next_dev(&devind, &vid, &did)) {
00535 
00536         raid= 0;
00537 
00538         /* Except class 01h (mass storage), subclass be 01h (ATA).
00539          * Also check listed RAID controllers.
00540          */
00541         bcr= pci_attr_r8(devind, PCI_BCR);
00542         scr= pci_attr_r8(devind, PCI_SCR);
00543         interface= pci_attr_r8(devind, PCI_PIFR);
00544         t3= ((bcr << 16) | (scr << 8) | interface);
00545         if (bcr == PCI_BCR_MASS_STORAGE && scr == PCI_MS_IDE)
00546                 ;       /* Okay */
00547         else if (t3 == PCI_T3_RAID)
00548         {
00549                 for (i= 0; raid_table[i].vendor != 0; i++)
00550                 {
00551                         if (raid_table[i].vendor == vid &&
00552                                 raid_table[i].device == did)
00553                         {
00554                                 break;
00555                         }
00556                 }
00557                 if (raid_table[i].vendor == 0)
00558                 {
00559                         printf(
00560         "atapci skipping unsupported RAID controller 0x%04x / 0x%04x\n",
00561                                 vid, did);
00562                         continue;
00563                 }
00564                 printf("found supported RAID controller\n");
00565                 raid= 1;
00566         }
00567         else
00568                 continue;       /* Unsupported device class */
00569 
00570         /* Found a controller.
00571          * Programming interface register tells us more.
00572          */
00573         irq = pci_attr_r8(devind, PCI_ILR);
00574 
00575         /* Any non-compat drives? */
00576         if (raid || (interface & (ATA_IF_NOTCOMPAT1 | ATA_IF_NOTCOMPAT2))) {
00577                 int s;
00578 
00579                 if (w_next_drive >= MAX_DRIVES)
00580                 {
00581                         /* We can't accept more drives, but have to search for
00582                          * controllers operating in compatibility mode.
00583                          */
00584                         continue;
00585                 }
00586 
00587                 irq_hook = irq;
00588                 if (skip > 0) {
00589                         if (w_pci_debug)
00590                         {
00591                                 printf(
00592                                 "atapci skipping controller (remain %d)\n",
00593                                         skip);
00594                         }
00595                         skip--;
00596                         continue;
00597                 }
00598                 if ((s=sys_irqsetpolicy(irq, 0, &irq_hook)) != OK) {
00599                         printf("atapci: couldn't set IRQ policy %d\n", irq);
00600                         continue;
00601                 }
00602                 if ((s=sys_irqenable(&irq_hook)) != OK) {
00603                         printf("atapci: couldn't enable IRQ line %d\n", irq);
00604                         continue;
00605                 }
00606         } 
00607 
00608         base_dma = pci_attr_r32(devind, PCI_BAR_5) & 0xfffffffc;
00609 
00610         /* Primary channel not in compatability mode? */
00611         if (raid || (interface & ATA_IF_NOTCOMPAT1)) {
00612                 u32_t base_cmd, base_ctl;
00613 
00614                 base_cmd = pci_attr_r32(devind, PCI_BAR) & 0xfffffffc;
00615                 base_ctl = pci_attr_r32(devind, PCI_BAR_2) & 0xfffffffc;
00616                 if (base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) {
00617                         init_drive(&wini[w_next_drive],
00618                                 base_cmd, base_ctl+PCI_CTL_OFF,
00619                                 base_dma, irq, 1, irq_hook, 0);
00620                         init_drive(&wini[w_next_drive+1],
00621                                 base_cmd, base_ctl+PCI_CTL_OFF,
00622                                 base_dma, irq, 1, irq_hook, 1);
00623                         if (w_pci_debug)
00624                                 printf("atapci %d: 0x%x 0x%x irq %d\n", devind, base_cmd, base_ctl, irq);
00625                         w_next_drive += 2;
00626                 } else printf("atapci: ignored drives on primary channel, base %x\n", base_cmd);
00627         }
00628         else
00629         {
00630                 /* Update base_dma for compatibility device */
00631                 for (i= 0; i<MAX_DRIVES; i++)
00632                 {
00633                         if (wini[i].base_cmd == REG_CMD_BASE0)
00634                                 wini[i].base_dma= base_dma;
00635                 }
00636         }
00637 
00638         /* Secondary channel not in compatability mode? */
00639         if (raid || (interface & ATA_IF_NOTCOMPAT2)) {
00640                 u32_t base_cmd, base_ctl;
00641 
00642                 base_cmd = pci_attr_r32(devind, PCI_BAR_3) & 0xfffffffc;
00643                 base_ctl = pci_attr_r32(devind, PCI_BAR_4) & 0xfffffffc;
00644                 if (base_dma != 0)
00645                         base_dma += PCI_DMA_2ND_OFF;
00646                 if (base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) {
00647                         init_drive(&wini[w_next_drive],
00648                                 base_cmd, base_ctl+PCI_CTL_OFF, base_dma,
00649                                 irq, 1, irq_hook, 2);
00650                         init_drive(&wini[w_next_drive+1],
00651                                 base_cmd, base_ctl+PCI_CTL_OFF, base_dma,
00652                                 irq, 1, irq_hook, 3);
00653                         if (w_pci_debug)
00654                                 printf("atapci %d: 0x%x 0x%x irq %d\n", devind, base_cmd, base_ctl, irq);
00655                         w_next_drive += 2;
00656                 } else printf("atapci: ignored drives on secondary channel, base %x\n", base_cmd);
00657         }
00658         else
00659         {
00660                 /* Update base_dma for compatibility device */
00661                 for (i= 0; i<MAX_DRIVES; i++)
00662                 {
00663                         if (wini[i].base_cmd == REG_CMD_BASE1 && base_dma != 0)
00664                                 wini[i].base_dma= base_dma+PCI_DMA_2ND_OFF;
00665                 }
00666         }
00667   }
00668 }
00669 
00670 /*===========================================================================*
00671  *                              w_do_open                                    *
00672  *===========================================================================*/
00673 PRIVATE int w_do_open(dp, m_ptr)
00674 struct driver *dp;
00675 message *m_ptr;
00676 {
00677 /* Device open: Initialize the controller and read the partition table. */
00678 
00679   struct wini *wn;
00680 
00681   if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
00682 
00683   wn = w_wn;
00684 
00685   /* If we've probed it before and it failed, don't probe it again. */
00686   if (wn->state & IGNORING) return ENXIO;
00687 
00688   /* If we haven't identified it yet, or it's gone deaf, 
00689    * (re-)identify it.
00690    */
00691   if (!(wn->state & IDENTIFIED) || (wn->state & DEAF)) {
00692         /* Try to identify the device. */
00693         if (w_identify() != OK) {
00694 #if VERBOSE
00695                 printf("%s: probe failed\n", w_name());
00696 #endif
00697                 if (wn->state & DEAF) w_reset();
00698                 wn->state = IGNORING;
00699                 return(ENXIO);
00700         }
00701           /* Do a test transaction unless it's a CD drive (then
00702            * we can believe the controller, and a test may fail
00703            * due to no CD being in the drive). If it fails, ignore
00704            * the device forever.
00705            */
00706           if (!(wn->state & ATAPI) && w_io_test() != OK) {
00707                 wn->state |= IGNORING;
00708                 return(ENXIO);
00709           }
00710 
00711 #if VERBOSE
00712           printf("%s: AT driver detected ", w_name());
00713           if (wn->state & (SMART|ATAPI)) {
00714                 printf("%.40s\n", w_id_string);
00715           } else {
00716                 printf("%ux%ux%u\n", wn->pcylinders, wn->pheads, wn->psectors);
00717           }
00718 #endif
00719   }
00720 
00721 #if ENABLE_ATAPI
00722    if ((wn->state & ATAPI) && (m_ptr->COUNT & W_BIT))
00723         return(EACCES);
00724 #endif
00725 
00726   /* Partition the drive if it's being opened for the first time,
00727    * or being opened after being closed.
00728    */
00729   if (wn->open_ct == 0) {
00730 #if ENABLE_ATAPI
00731         if (wn->state & ATAPI) {
00732                 int r;
00733                 if ((r = atapi_open()) != OK) return(r);
00734         }
00735 #endif
00736 
00737         /* Partition the disk. */
00738         partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY, wn->state & ATAPI);
00739   }
00740   wn->open_ct++;
00741   return(OK);
00742 }
00743 
00744 /*===========================================================================*
00745  *                              w_prepare                                    *
00746  *===========================================================================*/
00747 PRIVATE struct device *w_prepare(int device)
00748 {
00749 /* Prepare for I/O on a device. */
00750 struct wini *prev_wn;
00751 prev_wn = w_wn;
00752   w_device = device;
00753 
00754   if (device < NR_MINORS) {                     /* d0, d0p[0-3], d1, ... */
00755         w_drive = device / DEV_PER_DRIVE;       /* save drive number */
00756         w_wn = &wini[w_drive];
00757         w_dv = &w_wn->part[device % DEV_PER_DRIVE];
00758   } else
00759   if ((unsigned) (device -= MINOR_d0p0s0) < NR_SUBDEVS) {/*d[0-7]p[0-3]s[0-3]*/
00760         w_drive = device / SUB_PER_DRIVE;
00761         w_wn = &wini[w_drive];
00762         w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
00763   } else {
00764         w_device = -1;
00765         return(NIL_DEV);
00766   }
00767   return(w_dv);
00768 }
00769 
00770 /*===========================================================================*
00771  *                              w_identify                                   *
00772  *===========================================================================*/
00773 PRIVATE int w_identify()
00774 {
00775 /* Find out if a device exists, if it is an old AT disk, or a newer ATA
00776  * drive, a removable media device, etc.
00777  */
00778 
00779   struct wini *wn = w_wn;
00780   struct command cmd;
00781   int i, s;
00782   int id_dma, ultra_dma;
00783   u32_t dma_base;
00784   u16_t w;
00785   unsigned long dma_status;
00786   unsigned long size;
00787 #define id_byte(n)      (&tmp_buf[2 * (n)])
00788 #define id_word(n)      (((u16_t) id_byte(n)[0] <<  0) \
00789                         |((u16_t) id_byte(n)[1] <<  8))
00790 #define id_longword(n)  (((u32_t) id_byte(n)[0] <<  0) \
00791                         |((u32_t) id_byte(n)[1] <<  8) \
00792                         |((u32_t) id_byte(n)[2] << 16) \
00793                         |((u32_t) id_byte(n)[3] << 24))
00794 
00795   /* Try to identify the device. */
00796   cmd.ldh     = wn->ldhpref;
00797   cmd.command = ATA_IDENTIFY;
00798   if (com_simple(&cmd) == OK && w_waitfor(STATUS_DRQ, STATUS_DRQ) &&
00799         !(wn->w_status & (STATUS_ERR|STATUS_WF))) {
00800 
00801         /* Device information. */
00802         if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, SECTOR_SIZE)) != OK)
00803                 panic(w_name(),"Call to sys_insw() failed", s);
00804 
00805         if (id_word(0) & ID_GEN_NOT_ATA)
00806         {
00807                 printf("%s: not an ATA device?\n", w_name());
00808                 return ERR;
00809         }
00810 
00811         /* This is an ATA device. */
00812         wn->state |= SMART;
00813 
00814         /* Why are the strings byte swapped??? */
00815         for (i = 0; i < 40; i++) w_id_string[i] = id_byte(27)[i^1];
00816 
00817         /* Preferred CHS translation mode. */
00818         wn->pcylinders = id_word(1);
00819         wn->pheads = id_word(3);
00820         wn->psectors = id_word(6);
00821         size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
00822 
00823         w= id_word(ID_CAPABILITIES);
00824         if ((w & ID_CAP_LBA) && size > 512L*1024*2) {
00825                 /* Drive is LBA capable and is big enough to trust it to
00826                  * not make a mess of it.
00827                  */
00828                 wn->ldhpref |= LDH_LBA;
00829                 size = id_longword(60);
00830 
00831                 w= id_word(ID_CSS);
00832                 if (size < LBA48_CHECK_SIZE)
00833                 {
00834                         /* No need to check for LBA48 */
00835                 }
00836                 else if (w & ID_CSS_LBA48) {
00837                         /* Drive is LBA48 capable (and LBA48 is turned on). */
00838                         if (id_longword(102)) {
00839                                 /* If no. of sectors doesn't fit in 32 bits,
00840                                  * trunacte to this. So it's LBA32 for now.
00841                                  * This can still address devices up to 2TB
00842                                  * though.
00843                                  */
00844                                 size = ULONG_MAX;
00845                         } else {
00846                                 /* Actual number of sectors fits in 32 bits. */
00847                                 size = id_longword(100);
00848                         }
00849                         wn->lba48 = 1;
00850                 }
00851 
00852                 /* Check for DMA. Assume that only LBA capable devices can do
00853                  * DMA.
00854                  */
00855                 w= id_word(ID_CAPABILITIES);
00856                 id_dma= !!(w & ID_CAP_DMA);
00857                 w= id_byte(ID_FIELD_VALIDITY)[0];
00858                 ultra_dma= !!(w & ID_FV_88);
00859                 dma_base= wn->base_dma;
00860                 if (dma_base)
00861                 {
00862                         if (sys_inb(dma_base + DMA_STATUS, &dma_status) != OK)
00863                         {
00864                                 panic(w_name(),
00865                                         "unable to read DMA status register",
00866                                         NO_NUM);
00867                         }
00868                 }
00869                 if (disable_dma)
00870                         ;       /* DMA is disabled */
00871                 else if (id_dma && dma_base)
00872                 {
00873                         w= id_word(ID_MULTIWORD_DMA);
00874                         if (w & (ID_MWDMA_2_SUP|ID_MWDMA_1_SUP|ID_MWDMA_0_SUP))
00875                         {
00876                                 printf(
00877                                 "%s: multiword DMA modes supported:%s%s%s\n",
00878                                         w_name(),
00879                                         (w & ID_MWDMA_0_SUP) ? " 0" : "",
00880                                         (w & ID_MWDMA_1_SUP) ? " 1" : "",
00881                                         (w & ID_MWDMA_2_SUP) ? " 2" : "");
00882                         }
00883                         if (w & (ID_MWDMA_0_SEL|ID_MWDMA_1_SEL|ID_MWDMA_2_SEL))
00884                         {
00885                                 printf(
00886                                 "%s: multiword DMA mode selected:%s%s%s\n",
00887                                         w_name(),
00888                                         (w & ID_MWDMA_0_SEL) ? " 0" : "",
00889                                         (w & ID_MWDMA_1_SEL) ? " 1" : "",
00890                                         (w & ID_MWDMA_2_SEL) ? " 2" : "");
00891                         }
00892                         if (ultra_dma) 
00893                         {
00894                                 w= id_word(ID_ULTRA_DMA);
00895                                 if (w & (ID_UDMA_0_SUP|ID_UDMA_1_SUP|
00896                                         ID_UDMA_2_SUP|ID_UDMA_3_SUP|
00897                                         ID_UDMA_4_SUP|ID_UDMA_5_SUP))
00898                                 {
00899                                         printf(
00900                                 "%s: Ultra DMA modes supported:%s%s%s%s%s%s\n",
00901                                         w_name(),
00902                                         (w & ID_UDMA_0_SUP) ? " 0" : "",
00903                                         (w & ID_UDMA_1_SUP) ? " 1" : "",
00904                                         (w & ID_UDMA_2_SUP) ? " 2" : "",
00905                                         (w & ID_UDMA_3_SUP) ? " 3" : "",
00906                                         (w & ID_UDMA_4_SUP) ? " 4" : "",
00907                                         (w & ID_UDMA_5_SUP) ? " 5" : "");
00908                                 }
00909                                 if (w & (ID_UDMA_0_SEL|ID_UDMA_1_SEL|
00910                                         ID_UDMA_2_SEL|ID_UDMA_3_SEL|
00911                                         ID_UDMA_4_SEL|ID_UDMA_5_SEL))
00912                                 {
00913                                         printf(
00914                                 "%s: Ultra DMA mode selected:%s%s%s%s%s%s\n",
00915                                         w_name(),
00916                                         (w & ID_UDMA_0_SEL) ? " 0" : "",
00917                                         (w & ID_UDMA_1_SEL) ? " 1" : "",
00918                                         (w & ID_UDMA_2_SEL) ? " 2" : "",
00919                                         (w & ID_UDMA_3_SEL) ? " 3" : "",
00920                                         (w & ID_UDMA_4_SEL) ? " 4" : "",
00921                                         (w & ID_UDMA_5_SEL) ? " 5" : "");
00922                                 }
00923                         }
00924                         wn->dma= 1;
00925                 }
00926                 else if (id_dma || dma_base)
00927                 {
00928                         printf("id_dma %d, dma_base 0x%x\n", id_dma, dma_base);
00929                 }
00930                 else
00931                         printf("no DMA support\n");
00932 
00933 #if 0
00934                 if (wn->dma && wn == &wini[0])
00935                 {
00936                         printf("disabling DMA for drive 0\n");
00937                         wn->dma= 0;
00938                 }
00939 #endif
00940         }
00941 
00942         if (wn->lcylinders == 0) {
00943                 /* No BIOS parameters?  Then make some up. */
00944                 wn->lcylinders = wn->pcylinders;
00945                 wn->lheads = wn->pheads;
00946                 wn->lsectors = wn->psectors;
00947                 while (wn->lcylinders > 1024) {
00948                         wn->lheads *= 2;
00949                         wn->lcylinders /= 2;
00950                 }
00951         }
00952 #if ENABLE_ATAPI
00953   } else
00954   if (cmd.command = ATAPI_IDENTIFY,
00955         com_simple(&cmd) == OK && w_waitfor(STATUS_DRQ, STATUS_DRQ) &&
00956         !(wn->w_status & (STATUS_ERR|STATUS_WF))) {
00957         /* An ATAPI device. */
00958         wn->state |= ATAPI;
00959 
00960         /* Device information. */
00961         if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, 512)) != OK)
00962                 panic(w_name(),"Call to sys_insw() failed", s);
00963 
00964         /* Why are the strings byte swapped??? */
00965         for (i = 0; i < 40; i++) w_id_string[i] = id_byte(27)[i^1];
00966 
00967         size = 0;       /* Size set later. */
00968 #endif
00969   } else {
00970         /* Not an ATA device; no translations, no special features.  Don't
00971          * touch it unless the BIOS knows about it.
00972          */
00973         if (wn->lcylinders == 0) { return(ERR); }       /* no BIOS parameters */
00974         wn->pcylinders = wn->lcylinders;
00975         wn->pheads = wn->lheads;
00976         wn->psectors = wn->lsectors;
00977         size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
00978   }
00979 
00980   /* Size of the whole drive */
00981   wn->part[0].dv_size = mul64u(size, SECTOR_SIZE);
00982 
00983   /* Reset/calibrate (where necessary) */
00984   if (w_specify() != OK && w_specify() != OK) {
00985         return(ERR);
00986   }
00987 
00988   if (wn->irq == NO_IRQ) {
00989           /* Everything looks OK; register IRQ so we can stop polling. */
00990           wn->irq = w_drive < 2 ? AT_WINI_0_IRQ : AT_WINI_1_IRQ;
00991           wn->irq_hook_id = wn->irq;    /* id to be returned if interrupt occurs */
00992           if ((s=sys_irqsetpolicy(wn->irq, IRQ_REENABLE, &wn->irq_hook_id)) != OK) 
00993                 panic(w_name(), "couldn't set IRQ policy", s);
00994           if ((s=sys_irqenable(&wn->irq_hook_id)) != OK)
00995                 panic(w_name(), "couldn't enable IRQ line", s);
00996   }
00997   wn->state |= IDENTIFIED;
00998   return(OK);
00999 }
01000 
01001 /*===========================================================================*
01002  *                              w_name                                       *
01003  *===========================================================================*/
01004 PRIVATE char *w_name()
01005 {
01006 /* Return a name for the current device. */
01007   static char name[] = "AT-D0";
01008 
01009   name[4] = '0' + w_drive;
01010   return name;
01011 }
01012 
01013 /*===========================================================================*
01014  *                              w_io_test                                    *
01015  *===========================================================================*/
01016 PRIVATE int w_io_test(void)
01017 {
01018         int r, save_dev;
01019         int save_timeout, save_errors, save_wakeup;
01020         iovec_t iov;
01021 #ifdef CD_SECTOR_SIZE
01022         static char buf[CD_SECTOR_SIZE];
01023 #else
01024         static char buf[SECTOR_SIZE];
01025 #endif
01026 
01027         iov.iov_addr = (vir_bytes) buf;
01028         iov.iov_size = sizeof(buf);
01029         save_dev = w_device;
01030 
01031         /* Reduce timeout values for this test transaction. */
01032         save_timeout = timeout_ticks;
01033         save_errors = max_errors;
01034         save_wakeup = wakeup_ticks;
01035 
01036         if (!w_standard_timeouts) {
01037                 timeout_ticks = HZ * 4;
01038                 wakeup_ticks = HZ * 6;
01039                 max_errors = 3;
01040         }
01041 
01042         w_testing = 1;
01043 
01044         /* Try I/O on the actual drive (not any (sub)partition). */
01045         if (w_prepare(w_drive * DEV_PER_DRIVE) == NIL_DEV)
01046                 panic(w_name(), "Couldn't switch devices", NO_NUM);
01047 
01048         r = w_transfer(SELF, DEV_GATHER, 0, &iov, 1);
01049 
01050         /* Switch back. */
01051         if (w_prepare(save_dev) == NIL_DEV)
01052                 panic(w_name(), "Couldn't switch back devices", NO_NUM);
01053 
01054         /* Restore parameters. */
01055         timeout_ticks = save_timeout;
01056         max_errors = save_errors;
01057         wakeup_ticks = save_wakeup;
01058         w_testing = 0;
01059 
01060         /* Test if everything worked. */
01061         if (r != OK || iov.iov_size != 0) {
01062                 return ERR;
01063         }
01064 
01065         /* Everything worked. */
01066 
01067         return OK;
01068 }
01069 
01070 /*===========================================================================*
01071  *                              w_specify                                    *
01072  *===========================================================================*/
01073 PRIVATE int w_specify()
01074 {
01075 /* Routine to initialize the drive after boot or when a reset is needed. */
01076 
01077   struct wini *wn = w_wn;
01078   struct command cmd;
01079 
01080   if ((wn->state & DEAF) && w_reset() != OK) {
01081         return(ERR);
01082   }
01083 
01084   if (!(wn->state & ATAPI)) {
01085         /* Specify parameters: precompensation, number of heads and sectors. */
01086         cmd.precomp = wn->precomp;
01087         cmd.count   = wn->psectors;
01088         cmd.ldh     = w_wn->ldhpref | (wn->pheads - 1);
01089         cmd.command = CMD_SPECIFY;              /* Specify some parameters */
01090 
01091         /* Output command block and see if controller accepts the parameters. */
01092         if (com_simple(&cmd) != OK) return(ERR);
01093 
01094         if (!(wn->state & SMART)) {
01095                 /* Calibrate an old disk. */
01096                 cmd.sector  = 0;
01097                 cmd.cyl_lo  = 0;
01098                 cmd.cyl_hi  = 0;
01099                 cmd.ldh     = w_wn->ldhpref;
01100                 cmd.command = CMD_RECALIBRATE;
01101 
01102                 if (com_simple(&cmd) != OK) return(ERR);
01103         }
01104   }
01105   wn->state |= INITIALIZED;
01106   return(OK);
01107 }
01108 
01109 /*===========================================================================*
01110  *                              do_transfer                                  *
01111  *===========================================================================*/
01112 PRIVATE int do_transfer(struct wini *wn, unsigned int precomp,
01113         unsigned int count, unsigned int sector,
01114         unsigned int opcode, int do_dma)
01115 {
01116         struct command cmd;
01117         unsigned int sector_high;
01118         unsigned secspcyl = wn->pheads * wn->psectors;
01119         int do_lba48;
01120 
01121         sector_high= 0; /* For future extensions */
01122 
01123         do_lba48= 0;
01124         if (sector >= LBA48_CHECK_SIZE || sector_high != 0)
01125         {
01126                 if (wn->lba48)
01127                         do_lba48= 1;
01128                 else if (sector > LBA_MAX_SIZE || sector_high != 0)
01129                 {
01130                         /* Strange sector count for LBA device */
01131                         return EIO;
01132                 }
01133         }
01134 
01135         cmd.precomp = precomp;
01136         cmd.count   = count;
01137         if (do_dma)
01138         {
01139                 cmd.command = opcode == DEV_SCATTER ? CMD_WRITE_DMA :
01140                         CMD_READ_DMA;
01141         }
01142         else
01143                 cmd.command = opcode == DEV_SCATTER ? CMD_WRITE : CMD_READ;
01144 
01145         if (do_lba48) {
01146                 if (do_dma)
01147                 {
01148                         cmd.command = ((opcode == DEV_SCATTER) ?
01149                                 CMD_WRITE_DMA_EXT : CMD_READ_DMA_EXT);
01150                 }
01151                 else
01152                 {
01153                         cmd.command = ((opcode == DEV_SCATTER) ?
01154                                 CMD_WRITE_EXT : CMD_READ_EXT);
01155                 }
01156                 cmd.count_prev= (count >> 8);
01157                 cmd.sector  = (sector >>  0) & 0xFF;
01158                 cmd.cyl_lo  = (sector >>  8) & 0xFF;
01159                 cmd.cyl_hi  = (sector >> 16) & 0xFF;
01160                 cmd.sector_prev= (sector >> 24) & 0xFF;
01161                 cmd.cyl_lo_prev= (sector_high) & 0xFF;
01162                 cmd.cyl_hi_prev= (sector_high >> 8) & 0xFF;
01163                 cmd.ldh     = wn->ldhpref;
01164 
01165                 return com_out_ext(&cmd);
01166         } else if (wn->ldhpref & LDH_LBA) {
01167                 cmd.sector  = (sector >>  0) & 0xFF;
01168                 cmd.cyl_lo  = (sector >>  8) & 0xFF;
01169                 cmd.cyl_hi  = (sector >> 16) & 0xFF;
01170                 cmd.ldh     = wn->ldhpref | ((sector >> 24) & 0xF);
01171         } else {
01172                 int cylinder, head, sec;
01173                 cylinder = sector / secspcyl;
01174                 head = (sector % secspcyl) / wn->psectors;
01175                 sec = sector % wn->psectors;
01176                 cmd.sector  = sec + 1;
01177                 cmd.cyl_lo  = cylinder & BYTE;
01178                 cmd.cyl_hi  = (cylinder >> 8) & BYTE;
01179                 cmd.ldh     = wn->ldhpref | head;
01180         }
01181 
01182         return com_out(&cmd);
01183 }
01184 
01185 /*===========================================================================*
01186  *                              w_transfer                                   *
01187  *===========================================================================*/
01188 PRIVATE int w_transfer(proc_nr, opcode, position, iov, nr_req)
01189 int proc_nr;                    /* process doing the request */
01190 int opcode;                     /* DEV_GATHER or DEV_SCATTER */
01191 off_t position;                 /* offset on device to read or write */
01192 iovec_t *iov;                   /* pointer to read or write request vector */
01193 unsigned nr_req;                /* length of request vector */
01194 {
01195   struct wini *wn = w_wn;
01196   iovec_t *iop, *iov_end = iov + nr_req;
01197   int n, r, s, errors, do_dma, do_write, do_copyout;
01198   unsigned long v, block, w_status;
01199   unsigned long dv_size = cv64ul(w_dv->dv_size);
01200   unsigned cylinder, head, sector, nbytes;
01201   unsigned dma_buf_offset;
01202 
01203 #if ENABLE_ATAPI
01204   if (w_wn->state & ATAPI) {
01205         return atapi_transfer(proc_nr, opcode, position, iov, nr_req);
01206   }
01207 #endif
01208 
01209   
01210 
01211   /* Check disk address. */
01212   if ((position & SECTOR_MASK) != 0) return(EINVAL);
01213 
01214   errors = 0;
01215 
01216   while (nr_req > 0) {
01217         /* How many bytes to transfer? */
01218         nbytes = 0;
01219         for (iop = iov; iop < iov_end; iop++) nbytes += iop->iov_size;
01220         if ((nbytes & SECTOR_MASK) != 0) return(EINVAL);
01221 
01222         /* Which block on disk and how close to EOF? */
01223         if (position >= dv_size) return(OK);            /* At EOF */
01224         if (position + nbytes > dv_size) nbytes = dv_size - position;
01225         block = div64u(add64ul(w_dv->dv_base, position), SECTOR_SIZE);
01226 
01227         do_dma= wn->dma;
01228         do_write= (opcode == DEV_SCATTER);
01229         
01230         if (nbytes >= wn->max_count) {
01231                 /* The drive can't do more then max_count at once. */
01232                 nbytes = wn->max_count;
01233         }
01234 
01235         /* First check to see if a reinitialization is needed. */
01236         if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO);
01237 
01238         if (do_dma)
01239         {
01240                 setup_dma(&nbytes, proc_nr, iov, do_write, &do_copyout);
01241 #if 0
01242                 printf("nbytes = %d\n", nbytes);
01243 #endif
01244         }
01245 
01246         /* Tell the controller to transfer nbytes bytes. */
01247         r = do_transfer(wn, wn->precomp, (nbytes >> SECTOR_SHIFT),
01248                 block, opcode, do_dma);
01249 
01250         if (opcode == DEV_SCATTER) {
01251                 /* The specs call for a 400 ns wait after issuing the command.
01252                  * Reading the alternate status register is the suggested 
01253                  * way to implement this wait.
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                 /* Wait for the interrupt, check DMA status and optionally
01262                  * copy out.
01263                  */
01264 
01265                 if ((r = at_intr_wait()) != OK) 
01266                 {
01267                         /* Don't retry if sector marked bad or too many
01268                          * errors.
01269                          */
01270                         if (r == ERR_BAD_SECTOR || ++errors == max_errors) {
01271                                 w_command = CMD_IDLE;
01272                                 return(EIO);
01273                         }
01274                         continue;
01275                 }
01276 
01277                 /* Wait for DMA_ST_INT to get set */
01278                 w_waitfor_dma(DMA_ST_INT, DMA_ST_INT);
01279 
01280                 r= sys_inb(wn->base_dma + DMA_STATUS, &v);
01281                 if (r != 0) panic("at_wini", "w_transfer: sys_inb failed", r);
01282 
01283 #if 0
01284                 printf("dma_status: 0x%x\n", v);
01285 #endif
01286                 if (!(v & DMA_ST_INT))
01287                 {
01288                         /* DMA did not complete successfully */
01289                         if (v & DMA_ST_BM_ACTIVE)
01290                                 panic(w_name(), "DMA did not complete", NO_NUM);
01291                         else if (v & DMA_ST_ERROR)
01292                         {
01293                                 printf("at_wini: DMA error\n");
01294                                 r= EIO;
01295                                 break;
01296                         }
01297                         else
01298                         {
01299 #if 0
01300                                 printf("DMA buffer too small\n");
01301 #endif
01302                                 panic(w_name(), "DMA buffer too small", NO_NUM);
01303                         }
01304                 }
01305                 else if (v & DMA_ST_BM_ACTIVE)
01306                         panic(w_name(), "DMA buffer too large", NO_NUM);
01307 
01308                 dma_buf_offset= 0;
01309                 while (r == OK && nbytes > 0)
01310                 {
01311                         n= iov->iov_size;
01312                         if (n > nbytes)
01313                                 n= nbytes;
01314 
01315                         if (do_copyout)
01316                         {
01317                                 s= sys_vircopy(SELF, D,
01318                                         (vir_bytes)dma_buf+dma_buf_offset, 
01319                                         proc_nr, D, iov->iov_addr, n);
01320                                 if (s != OK)
01321                                 {
01322                                         panic(w_name(),
01323                                         "w_transfer: sys_vircopy failed",
01324                                                 s);
01325                                 }
01326                         }
01327 
01328                         /* Book the bytes successfully transferred. */
01329                         nbytes -= n;
01330                         position += n;
01331                         iov->iov_addr += n;
01332                         if ((iov->iov_size -= n) == 0)
01333                                 { iov++; nr_req--; }
01334                         dma_buf_offset += n;
01335                 }
01336         }
01337 
01338         while (r == OK && nbytes > 0) {
01339                 /* For each sector, wait for an interrupt and fetch the data
01340                  * (read), or supply data to the controller and wait for an
01341                  * interrupt (write).
01342                  */
01343 
01344                 if (opcode == DEV_GATHER) {
01345                         /* First an interrupt, then data. */
01346                         if ((r = at_intr_wait()) != OK) {
01347                                 /* An error, send data to the bit bucket. */
01348                                 if (w_wn->w_status & STATUS_DRQ) {
01349                                         if ((s=sys_insw(wn->base_cmd+REG_DATA,
01350                                                 SELF, tmp_buf,
01351                                                 SECTOR_SIZE)) != OK)
01352                                         {
01353                                                 panic(w_name(),
01354                                                 "Call to sys_insw() failed",
01355                                                         s);
01356                                         }
01357                                 }
01358                                 break;
01359                         }
01360                 }
01361 
01362                 /* Wait for busy to clear. */
01363                 if (!w_waitfor(STATUS_BSY, 0)) { r = ERR; break; }
01364 
01365                 /* Wait for data transfer requested. */
01366                 if (!w_waitfor(STATUS_DRQ, STATUS_DRQ)) { r = ERR; break; }
01367 
01368                 /* Copy bytes to or from the device's buffer. */
01369                 if (opcode == DEV_GATHER) {
01370                         if ((s=sys_insw(wn->base_cmd + REG_DATA, proc_nr, 
01371                                 (void *) iov->iov_addr, SECTOR_SIZE)) != OK)
01372                         {
01373                                 panic(w_name(),"Call to sys_insw() failed", s);
01374                         }
01375                 } else {
01376                         if ((s=sys_outsw(wn->base_cmd + REG_DATA, proc_nr,
01377                                 (void *) iov->iov_addr, SECTOR_SIZE)) != OK)
01378                         {
01379                                 panic(w_name(),"Call to sys_outsw() failed",
01380                                         s);
01381                         }
01382 
01383                         /* Data sent, wait for an interrupt. */
01384                         if ((r = at_intr_wait()) != OK) break;
01385                 }
01386 
01387                 /* Book the bytes successfully transferred. */
01388                 nbytes -= SECTOR_SIZE;
01389                 position += SECTOR_SIZE;
01390                 iov->iov_addr += SECTOR_SIZE;
01391                 if ((iov->iov_size -= SECTOR_SIZE) == 0) { iov++; nr_req--; }
01392         }
01393 
01394         /* Any errors? */
01395         if (r != OK) {
01396                 /* Don't retry if sector marked bad or too many errors. */
01397                 if (r == ERR_BAD_SECTOR || ++errors == max_errors) {
01398                         w_command = CMD_IDLE;
01399                         return(EIO);
01400                 }
01401         }
01402   }
01403 
01404   w_command = CMD_IDLE;
01405   return(OK);
01406 }
01407 
01408 /*===========================================================================*
01409  *                              com_out                                      *
01410  *===========================================================================*/
01411 PRIVATE int com_out(cmd)
01412 struct command *cmd;            /* Command block */
01413 {
01414 /* Output the command block to the winchester controller and return status */
01415 
01416   struct wini *wn = w_wn;
01417   unsigned base_cmd = wn->base_cmd;
01418   unsigned base_ctl = wn->base_ctl;
01419   pvb_pair_t outbyte[7];                /* vector for sys_voutb() */
01420   int s;                                /* status for sys_(v)outb() */
01421 
01422   if (w_wn->state & IGNORING) return ERR;
01423 
01424   if (!w_waitfor(STATUS_BSY, 0)) {
01425         printf("%s: controller not ready\n", w_name());
01426         return(ERR);
01427   }
01428 
01429   /* Select drive. */
01430   if ((s=sys_outb(base_cmd + REG_LDH, cmd->ldh)) != OK)
01431         panic(w_name(),"Couldn't write register to select drive",s);
01432 
01433   if (!w_waitfor(STATUS_BSY, 0)) {
01434         printf("%s: com_out: drive not ready\n", w_name());
01435         return(ERR);
01436   }
01437 
01438   /* Schedule a wakeup call, some controllers are flaky. This is done with
01439    * a synchronous alarm. If a timeout occurs a SYN_ALARM message is sent
01440    * from HARDWARE, so that w_intr_wait() can call w_timeout() in case the
01441    * controller was not able to execute the command. Leftover timeouts are
01442    * simply ignored by the main loop. 
01443    */
01444   sys_setalarm(wakeup_ticks, 0);
01445 
01446   wn->w_status = STATUS_ADMBSY;
01447   w_command = cmd->command;
01448   pv_set(outbyte[0], base_ctl + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS : 0);
01449   pv_set(outbyte[1], base_cmd + REG_PRECOMP, cmd->precomp);
01450   pv_set(outbyte[2], base_cmd + REG_COUNT, cmd->count);
01451   pv_set(outbyte[3], base_cmd + REG_SECTOR, cmd->sector);
01452   pv_set(outbyte[4], base_cmd + REG_CYL_LO, cmd->cyl_lo);
01453   pv_set(outbyte[5], base_cmd + REG_CYL_HI, cmd->cyl_hi);
01454   pv_set(outbyte[6], base_cmd + REG_COMMAND, cmd->command);
01455   if ((s=sys_voutb(outbyte,7)) != OK)
01456         panic(w_name(),"Couldn't write registers with sys_voutb()",s);
01457   return(OK);
01458 }
01459 
01460 /*===========================================================================*
01461  *                              com_out_ext                                  *
01462  *===========================================================================*/
01463 PRIVATE int com_out_ext(cmd)
01464 struct command *cmd;            /* Command block */
01465 {
01466 /* Output the command block to the winchester controller and return status */
01467 
01468   struct wini *wn = w_wn;
01469   unsigned base_cmd = wn->base_cmd;
01470   unsigned base_ctl = wn->base_ctl;
01471   pvb_pair_t outbyte[11];               /* vector for sys_voutb() */
01472   int s;                                /* status for sys_(v)outb() */
01473   unsigned long w_status;
01474 
01475   if (w_wn->state & IGNORING) return ERR;
01476 
01477   if (!w_waitfor(STATUS_BSY, 0)) {
01478         printf("%s: controller not ready\n", w_name());
01479         return(ERR);
01480   }
01481 
01482   /* Select drive. */
01483   if ((s=sys_outb(base_cmd + REG_LDH, cmd->ldh)) != OK)
01484         panic(w_name(),"Couldn't write register to select drive",s);
01485 
01486   if (!w_waitfor(STATUS_BSY, 0)) {
01487         printf("%s: com_out: drive not ready\n", w_name());
01488         return(ERR);
01489   }
01490 
01491   /* Schedule a wakeup call, some controllers are flaky. This is done with
01492    * a synchronous alarm. If a timeout occurs a SYN_ALARM message is sent
01493    * from HARDWARE, so that w_intr_wait() can call w_timeout() in case the
01494    * controller was not able to execute the command. Leftover timeouts are
01495    * simply ignored by the main loop. 
01496    */
01497   sys_setalarm(wakeup_ticks, 0);
01498 
01499   wn->w_status = STATUS_ADMBSY;
01500   w_command = cmd->command;
01501   pv_set(outbyte[0], base_ctl + REG_CTL, 0);
01502   pv_set(outbyte[1], base_cmd + REG_COUNT, cmd->count_prev);
01503   pv_set(outbyte[2], base_cmd + REG_SECTOR, cmd->sector_prev);
01504   pv_set(outbyte[3], base_cmd + REG_CYL_LO, cmd->cyl_lo_prev);
01505   pv_set(outbyte[4], base_cmd + REG_CYL_HI, cmd->cyl_hi_prev);
01506   pv_set(outbyte[5], base_cmd + REG_COUNT, cmd->count);
01507   pv_set(outbyte[6], base_cmd + REG_SECTOR, cmd->sector);
01508   pv_set(outbyte[7], base_cmd + REG_CYL_LO, cmd->cyl_lo);
01509   pv_set(outbyte[8], base_cmd + REG_CYL_HI, cmd->cyl_hi);
01510 
01511   pv_set(outbyte[10], base_cmd + REG_COMMAND, cmd->command);
01512   if ((s=sys_voutb(outbyte, 11)) != OK)
01513         panic(w_name(),"Couldn't write registers with sys_voutb()",s);
01514 
01515   return(OK);
01516 }
01517 
01518 /*===========================================================================*
01519  *                              setup_dma                                    *
01520  *===========================================================================*/
01521 PRIVATE void setup_dma(sizep, proc_nr, iov, do_write, do_copyoutp)
01522 unsigned *sizep;
01523 int proc_nr;
01524 iovec_t *iov;
01525 int do_write;
01526 int *do_copyoutp;
01527 {
01528         phys_bytes phys, user_phys;
01529         unsigned n, offset, size;
01530         int i, j, r, bad;
01531         unsigned long v;
01532         struct wini *wn = w_wn;
01533 
01534         /* First try direct scatter/gather to the supplied buffers */
01535         size= *sizep;
01536         i= 0;   /* iov index */
01537         j= 0;   /* prdt index */
01538         bad= 0;
01539         offset= 0;      /* Offset in current iov */
01540 
01541 #if 0
01542         printf("setup_dma: proc_nr %d\n", proc_nr);
01543 #endif
01544 
01545         while (size > 0)
01546         {
01547 #if 0
01548                 printf(
01549                 "setup_dma: iov[%d]: addr 0x%x, size %d offset %d, size %d\n",
01550                         i, iov[i].iov_addr, iov[i].iov_size, offset, size);
01551 #endif
01552                         
01553                 n= iov[i].iov_size-offset;
01554                 if (n > size)
01555                         n= size;
01556                 if (n == 0 || (n & 1))
01557                         panic("at_wini", "bad size in iov", iov[i].iov_size);
01558                 r= sys_umap(proc_nr, D, iov[i].iov_addr+offset, n, &user_phys);
01559                 if (r != 0)
01560                         panic("at_wini", "can't map user buffer", r);
01561                 if (user_phys & 1)
01562                 {
01563                         /* Buffer is not aligned */
01564                         printf("setup_dma: user buffer is not aligned\n");
01565                         bad= 1;
01566                         break;
01567                 }
01568 
01569                 /* vector is not allowed to cross a 64K boundary */
01570                 if (user_phys/0x10000 != (user_phys+n-1)/0x10000)
01571                         n= ((user_phys/0x10000)+1)*0x10000 - user_phys;
01572 
01573                 /* vector is not allowed to be bigger than 64K, but we get that
01574                  * for free.
01575                  */
01576 
01577                 if (j >= N_PRDTE)
01578                 {
01579                         /* Too many entries */
01580                         bad= 1;
01581                         break;
01582                 }
01583 
01584                 prdt[j].prdte_base= user_phys;
01585                 prdt[j].prdte_count= n;
01586                 prdt[j].prdte_reserved= 0;
01587                 prdt[j].prdte_flags= 0;
01588                 j++;
01589 
01590                 offset += n;
01591                 if (offset >= iov[i].iov_size)
01592                 {
01593                         i++;
01594                         offset= 0;
01595                 }
01596 
01597                 size -= n;
01598         }
01599 
01600         if (!bad)
01601         {
01602                 if (j <= 0 || j > N_PRDTE)
01603                         panic("at_wini", "bad prdt index", j);
01604                 prdt[j-1].prdte_flags |= PRDTE_FL_EOT;
01605 
01606 #if 0
01607                 for (i= 0; i<j; i++)
01608                 {
01609                         printf("prdt[%d]: base 0x%x, size %d, flags 0x%x\n",
01610                                 i, prdt[i].prdte_base, prdt[i].prdte_count,
01611                                 prdt[i].prdte_flags);
01612                 }
01613 #endif
01614         }
01615 
01616         /* The caller needs to perform a copy-out from the dma buffer if
01617          * this is a read request and we can't DMA directly to the user's
01618          * buffers.
01619          */
01620         *do_copyoutp= (!do_write && bad);
01621 
01622         if (bad)
01623         {
01624                 /* Adjust request size */
01625                 size= *sizep;
01626                 if (size > ATA_DMA_BUF_SIZE)
01627                         *sizep= size= ATA_DMA_BUF_SIZE;
01628 
01629                 if (do_write)
01630                 {
01631                         /* Copy-in */
01632                         for (offset= 0; offset < size; offset += n)
01633                         {
01634                                 n= size-offset;
01635                                 if (n > iov->iov_size)
01636                                         n= iov->iov_size;
01637                         
01638                                 r= sys_vircopy(proc_nr, D, iov->iov_addr,
01639                                         SELF, D, (vir_bytes)dma_buf+offset, 
01640                                         n);
01641                                 if (r != OK)
01642                                 {
01643                                         panic(w_name(),
01644                                         "setup_dma: sys_vircopy failed",
01645                                                 r);
01646                                 }
01647                                 iov++;
01648                         }
01649                 }
01650         
01651                 /* Fill-in the physical region descriptor table */
01652                 phys= dma_buf_phys;
01653                 if (phys & 1)
01654                 {
01655                         /* Two byte alignment is required */
01656                         panic("at_wini", "bad buffer alignment in setup_dma",
01657                                 phys);
01658                 }
01659                 for (j= 0; j<N_PRDTE; i++)
01660                 {
01661                         if (size == 0)
01662                         {
01663                                 panic("at_wini", "bad size in setup_dma",
01664                                         size);
01665                         }
01666                         if (size & 1)
01667                         {
01668                                 /* Two byte alignment is required for size */
01669                                 panic("at_wini",
01670                                         "bad size alignment in setup_dma",
01671                                         size);
01672                         }
01673                         n= size;
01674 
01675                         /* Buffer is not allowed to cross a 64K boundary */
01676                         if (phys / 0x10000 != (phys+n-1) / 0x10000)
01677                         {
01678                                 n= ((phys/0x10000)+1)*0x10000 - phys;
01679                         }
01680                         prdt[j].prdte_base= phys;
01681                         prdt[j].prdte_count= n;
01682                         prdt[j].prdte_reserved= 0;
01683                         prdt[j].prdte_flags= 0;
01684 
01685                         size -= n;
01686                         if (size == 0)
01687                         {
01688                                 prdt[j].prdte_flags |= PRDTE_FL_EOT;
01689                                 break;
01690                         }
01691                 }
01692                 if (size != 0)
01693                         panic("at_wini", "size to large for prdt", NO_NUM);
01694 
01695 #if 0
01696                 for (i= 0; i<=j; i++)
01697                 {
01698                         printf("prdt[%d]: base 0x%x, size %d, flags 0x%x\n",
01699                                 i, prdt[i].prdte_base, prdt[i].prdte_count,
01700                                 prdt[i].prdte_flags);
01701                 }
01702 #endif
01703         }
01704 
01705         /* Stop bus master operation */
01706         r= sys_outb(wn->base_dma + DMA_COMMAND, 0);
01707         if (r != 0) panic("at_wini", "setup_dma: sys_outb failed", r);
01708 
01709         /* Verify that the bus master is not active */
01710         r= sys_inb(wn->base_dma + DMA_STATUS, &v);
01711         if (r != 0) panic("at_wini", "setup_dma: sys_inb failed", r);
01712         if (v & DMA_ST_BM_ACTIVE)
01713                 panic("at_wini", "Bus master IDE active", NO_NUM);
01714 
01715         if (prdt_phys & 3)
01716                 panic("at_wini", "prdt not aligned", prdt_phys);
01717         r= sys_outl(wn->base_dma + DMA_PRDTP, prdt_phys);
01718         if (r != 0) panic("at_wini", "setup_dma: sys_outl failed", r);
01719 
01720         /* Clear interrupt and error flags */
01721         r= sys_outb(wn->base_dma + DMA_STATUS, DMA_ST_INT | DMA_ST_ERROR);
01722         if (r != 0) panic("at_wini", "setup_dma: sys_outb failed", r);
01723 
01724         /* Assume disk reads. Start DMA */
01725         v= DMA_CMD_START;
01726         if (!do_write)
01727         {
01728                 /* Disk reads generate PCI write cycles. */
01729                 v |= DMA_CMD_WRITE;     
01730         }
01731         r= sys_outb(wn->base_dma + DMA_COMMAND, v);
01732         if (r != 0) panic("at_wini", "setup_dma: sys_outb failed", r);
01733 
01734 #if 0
01735         r= sys_inb(wn->base_dma + DMA_STATUS, &v);
01736         if (r != 0) panic("at_wini", "setup_dma: sys_inb failed", r);
01737         printf("dma status: 0x%x\n", v);
01738 #endif
01739 }
01740 
01741 
01742 /*===========================================================================*
01743  *                              w_need_reset                                 *
01744  *===========================================================================*/
01745 PRIVATE void w_need_reset()
01746 {
01747 /* The controller needs to be reset. */
01748   struct wini *wn;
01749   int dr = 0;
01750 
01751   for (wn = wini; wn < &wini[MAX_DRIVES]; wn++, dr++) {
01752         if (wn->base_cmd == w_wn->base_cmd) {
01753                 wn->state |= DEAF;
01754                 wn->state &= ~INITIALIZED;
01755         }
01756   }
01757 }
01758 
01759 /*===========================================================================*
01760  *                              w_do_close                                   *
01761  *===========================================================================*/
01762 PRIVATE int w_do_close(dp, m_ptr)
01763 struct driver *dp;
01764 message *m_ptr;
01765 {
01766 /* Device close: Release a device. */
01767   if (w_prepare(m_ptr->DEVICE) == NIL_DEV)
01768         return(ENXIO);
01769   w_wn->open_ct--;
01770 #if ENABLE_ATAPI
01771   if (w_wn->open_ct == 0 && (w_wn->state & ATAPI)) atapi_close();
01772 #endif
01773   return(OK);
01774 }
01775 
01776 /*===========================================================================*
01777  *                              com_simple                                   *
01778  *===========================================================================*/
01779 PRIVATE int com_simple(cmd)
01780 struct command *cmd;            /* Command block */
01781 {
01782 /* A simple controller command, only one interrupt and no data-out phase. */
01783   int r;
01784 
01785   if (w_wn->state & IGNORING) return ERR;
01786 
01787   if ((r = com_out(cmd)) == OK) r = at_intr_wait();
01788   w_command = CMD_IDLE;
01789   return(r);
01790 }
01791 
01792 /*===========================================================================*
01793  *                              w_timeout                                    *
01794  *===========================================================================*/
01795 PRIVATE void w_timeout(void)
01796 {
01797   struct wini *wn = w_wn;
01798 
01799   switch (w_command) {
01800   case CMD_IDLE:
01801         break;          /* fine */
01802   case CMD_READ:
01803   case CMD_READ_EXT:
01804   case CMD_WRITE:
01805   case CMD_WRITE_EXT:
01806         /* Impossible, but not on PC's:  The controller does not respond. */
01807 
01808         /* Limiting multisector I/O seems to help. */
01809         if (wn->max_count > 8 * SECTOR_SIZE) {
01810                 wn->max_count = 8 * SECTOR_SIZE;
01811         } else {
01812                 wn->max_count = SECTOR_SIZE;
01813         }
01814         /*FALL THROUGH*/
01815   default:
01816         /* Some other command. */
01817         if (w_testing)  wn->state |= IGNORING;  /* Kick out this drive. */
01818         else if (!w_silent) printf("%s: timeout on command 0x%02x\n",
01819                 w_name(), w_command);
01820         w_need_reset();
01821         wn->w_status = 0;
01822   }
01823 }
01824 
01825 /*===========================================================================*
01826  *                              w_reset                                      *
01827  *===========================================================================*/
01828 PRIVATE int w_reset()
01829 {
01830 /* Issue a reset to the controller.  This is done after any catastrophe,
01831  * like the controller refusing to respond.
01832  */
01833   int s;
01834   struct wini *wn = w_wn;
01835 
01836   /* Don't bother if this drive is forgotten. */
01837   if (w_wn->state & IGNORING) return ERR;
01838 
01839   /* Wait for any internal drive recovery. */
01840   tickdelay(RECOVERY_TICKS);
01841 
01842   /* Strobe reset bit */
01843   if ((s=sys_outb(wn->base_ctl + REG_CTL, CTL_RESET)) != OK)
01844         panic(w_name(),"Couldn't strobe reset bit",s);
01845   tickdelay(DELAY_TICKS);
01846   if ((s=sys_outb(wn->base_ctl + REG_CTL, 0)) != OK)
01847         panic(w_name(),"Couldn't strobe reset bit",s);
01848   tickdelay(DELAY_TICKS);
01849 
01850   /* Wait for controller ready */
01851   if (!w_waitfor(STATUS_BSY, 0)) {
01852         printf("%s: reset failed, drive busy\n", w_name());
01853         return(ERR);
01854   }
01855 
01856   /* The error register should be checked now, but some drives mess it up. */
01857 
01858   for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
01859         if (wn->base_cmd == w_wn->base_cmd) {
01860                 wn->state &= ~DEAF;
01861                 if (w_wn->irq_need_ack) {
01862                         /* Make sure irq is actually enabled.. */
01863                         sys_irqenable(&w_wn->irq_hook_id);
01864                 }
01865         }
01866   }
01867                 
01868 
01869   return(OK);
01870 }
01871 
01872 /*===========================================================================*
01873  *                              w_intr_wait                                  *
01874  *===========================================================================*/
01875 PRIVATE void w_intr_wait()
01876 {
01877 /* Wait for a task completion interrupt. */
01878 
01879   int r;
01880   unsigned long w_status;
01881   message m;
01882 
01883   if (w_wn->irq != NO_IRQ) {
01884         /* Wait for an interrupt that sets w_status to "not busy". */
01885         while (w_wn->w_status & (STATUS_ADMBSY|STATUS_BSY)) {
01886                 int rr;
01887                 if((rr=receive(ANY, &m)) != OK) { /* expect HARD_INT message */
01888                         printf("w_intr_wait: receive from ANY failed (%d)\n",
01889                                 r);
01890                         continue;       /* try again */
01891                 }
01892                 if (m.m_type == SYN_ALARM) {    /* but check for timeout */
01893                     w_timeout();                /* a.o. set w_status */
01894                 } else if (m.m_type == HARD_INT) {
01895                     r= sys_inb(w_wn->base_cmd + REG_STATUS, &w_status);
01896                     if (r != 0)
01897                         panic("at_wini", "sys_inb failed", r);
01898                     w_wn->w_status= w_status;
01899                     ack_irqs(m.NOTIFY_ARG);
01900                 } else if (m.m_type == DEV_PING) {
01901                     notify(m.m_source);
01902                 } else {
01903                         printf("AT_WINI got unexpected message %d from %d\n",
01904                                 m.m_type, m.m_source);
01905                 }
01906         }
01907   } else {
01908         /* Interrupt not yet allocated; use polling. */
01909         (void) w_waitfor(STATUS_BSY, 0);
01910   }
01911 }
01912 
01913 /*===========================================================================*
01914  *                              at_intr_wait                                 *
01915  *===========================================================================*/
01916 PRIVATE int at_intr_wait()
01917 {
01918 /* Wait for an interrupt, study the status bits and return error/success. */
01919   int r, s;
01920   unsigned long inbval;
01921 
01922   w_intr_wait();
01923   if ((w_wn->w_status & (STATUS_BSY | STATUS_WF | STATUS_ERR)) == 0) {
01924         r = OK;
01925   } else {
01926         if ((s=sys_inb(w_wn->base_cmd + REG_ERROR, &inbval)) != OK)
01927                 panic(w_name(),"Couldn't read register",s);
01928         if ((w_wn->w_status & STATUS_ERR) && (inbval & ERROR_BB)) {
01929                 r = ERR_BAD_SECTOR;     /* sector marked bad, retries won't help */
01930         } else {
01931                 r = ERR;                /* any other error */
01932         }
01933   }
01934   w_wn->w_status |= STATUS_ADMBSY;      /* assume still busy with I/O */
01935   return(r);
01936 }
01937 
01938 /*===========================================================================*
01939  *                              w_waitfor                                    *
01940  *===========================================================================*/
01941 PRIVATE int w_waitfor(mask, value)
01942 int mask;                       /* status mask */
01943 int value;                      /* required status */
01944 {
01945 /* Wait until controller is in the required state.  Return zero on timeout.
01946  * An alarm that set a timeout flag is used. TIMEOUT is in micros, we need
01947  * ticks. Disabling the alarm is not needed, because a static flag is used
01948  * and a leftover timeout cannot do any harm.
01949  */
01950   unsigned long w_status;
01951   clock_t t0, t1;
01952   int s;
01953 
01954   getuptime(&t0);
01955   do {
01956         if ((s=sys_inb(w_wn->base_cmd + REG_STATUS, &w_status)) != OK)
01957                 panic(w_name(),"Couldn't read register",s);
01958         w_wn->w_status= w_status;
01959         if ((w_wn->w_status & mask) == value) {
01960                 return 1;
01961         }
01962   } while ((s=getuptime(&t1)) == OK && (t1-t0) < timeout_ticks );
01963   if (OK != s) printf("AT_WINI: warning, get_uptime failed: %d\n",s);
01964 
01965   w_need_reset();                       /* controller gone deaf */
01966   return(0);
01967 }
01968 
01969 /*===========================================================================*
01970  *                              w_waitfor_dma                                *
01971  *===========================================================================*/
01972 PRIVATE int w_waitfor_dma(mask, value)
01973 int mask;                       /* status mask */
01974 int value;                      /* required status */
01975 {
01976 /* Wait until controller is in the required state.  Return zero on timeout.
01977  * An alarm that set a timeout flag is used. TIMEOUT is in micros, we need
01978  * ticks. Disabling the alarm is not needed, because a static flag is used
01979  * and a leftover timeout cannot do any harm.
01980  */
01981   unsigned long w_status;
01982   clock_t t0, t1;
01983   int s;
01984 
01985   getuptime(&t0);
01986   do {
01987         if ((s=sys_inb(w_wn->base_dma + DMA_STATUS, &w_status)) != OK)
01988                 panic(w_name(),"Couldn't read register",s);
01989         if ((w_status & mask) == value) {
01990                 return 1;
01991         }
01992   } while ((s=getuptime(&t1)) == OK && (t1-t0) < timeout_ticks );
01993   if (OK != s) printf("AT_WINI: warning, get_uptime failed: %d\n",s);
01994 
01995   return(0);
01996 }
01997 
01998 /*===========================================================================*
01999  *                              w_geometry                                   *
02000  *===========================================================================*/
02001 PRIVATE void w_geometry(entry)
02002 struct partition *entry;
02003 {
02004   struct wini *wn = w_wn;
02005 
02006   if (wn->state & ATAPI) {              /* Make up some numbers. */
02007         entry->cylinders = div64u(wn->part[0].dv_size, SECTOR_SIZE) / (64*32);
02008         entry->heads = 64;
02009         entry->sectors = 32;
02010   } else {                              /* Return logical geometry. */
02011         entry->cylinders = wn->lcylinders;
02012         entry->heads = wn->lheads;
02013         entry->sectors = wn->lsectors;
02014   }
02015 }
02016 
02017 #if ENABLE_ATAPI
02018 /*===========================================================================*
02019  *                              atapi_open                                   *
02020  *===========================================================================*/
02021 PRIVATE int atapi_open()
02022 {
02023 /* Should load and lock the device and obtain its size.  For now just set the
02024  * size of the device to something big.  What is really needed is a generic
02025  * SCSI layer that does all this stuff for ATAPI and SCSI devices (kjb). (XXX)
02026  */
02027   w_wn->part[0].dv_size = mul64u(800L*1024, 1024);
02028   return(OK);
02029 }
02030 
02031 /*===========================================================================*
02032  *                              atapi_close                                  *
02033  *===========================================================================*/
02034 PRIVATE void atapi_close()
02035 {
02036 /* Should unlock the device.  For now do nothing.  (XXX) */
02037 }
02038 
02039 void sense_request(void)
02040 {
02041         int r, i;
02042         static u8_t sense[100], packet[ATAPI_PACKETSIZE];
02043 
02044         packet[0] = SCSI_SENSE;
02045         packet[1] = 0;
02046         packet[2] = 0;
02047         packet[3] = 0;
02048         packet[4] = SENSE_PACKETSIZE;
02049         packet[5] = 0;
02050         packet[7] = 0;
02051         packet[8] = 0;
02052         packet[9] = 0;
02053         packet[10] = 0;
02054         packet[11] = 0;
02055 
02056         for(i = 0; i < SENSE_PACKETSIZE; i++) sense[i] = 0xff;
02057         r = atapi_sendpacket(packet, SENSE_PACKETSIZE);
02058         if (r != OK) { printf("request sense command failed\n"); return; }
02059         if (atapi_intr_wait() <= 0) { printf("WARNING: request response failed\n"); }
02060 
02061         if (sys_insw(w_wn->base_cmd + REG_DATA, SELF, (void *) sense, SENSE_PACKETSIZE) != OK)
02062                 printf("WARNING: sense reading failed\n");
02063 
02064         printf("sense data:");
02065         for(i = 0; i < SENSE_PACKETSIZE; i++) printf(" %02x", sense[i]);
02066         printf("\n");
02067 }
02068 
02069 /*===========================================================================*
02070  *                              atapi_transfer                               *
02071  *===========================================================================*/
02072 PRIVATE int atapi_transfer(proc_nr, opcode, position, iov, nr_req)
02073 int proc_nr;                    /* process doing the request */
02074 int opcode;                     /* DEV_GATHER or DEV_SCATTER */
02075 off_t position;                 /* offset on device to read or write */
02076 iovec_t *iov;                   /* pointer to read or write request vector */
02077 unsigned nr_req;                /* length of request vector */
02078 {
02079   struct wini *wn = w_wn;
02080   iovec_t *iop, *iov_end = iov + nr_req;
02081   int r, s, errors, fresh;
02082   u64_t pos;
02083   unsigned long block;
02084   unsigned long dv_size = cv64ul(w_dv->dv_size);
02085   unsigned nbytes, nblocks, count, before, chunk;
02086   static u8_t packet[ATAPI_PACKETSIZE];
02087 
02088   errors = fresh = 0;
02089 
02090   while (nr_req > 0 && !fresh) {
02091         /* The Minix block size is smaller than the CD block size, so we
02092          * may have to read extra before or after the good data.
02093          */
02094         pos = add64ul(w_dv->dv_base, position);
02095         block = div64u(pos, CD_SECTOR_SIZE);
02096         before = rem64u(pos, CD_SECTOR_SIZE);
02097 
02098         /* How many bytes to transfer? */
02099         nbytes = count = 0;
02100         for (iop = iov; iop < iov_end; iop++) {
02101                 nbytes += iop->iov_size;
02102                 if ((before + nbytes) % CD_SECTOR_SIZE == 0) count = nbytes;
02103         }
02104 
02105         /* Does one of the memory chunks end nicely on a CD sector multiple? */
02106         if (count != 0) nbytes = count;
02107 
02108         /* Data comes in as words, so we have to enforce even byte counts. */
02109         if ((before | nbytes) & 1) return(EINVAL);
02110 
02111         /* Which block on disk and how close to EOF? */
02112         if (position >= dv_size) return(OK);            /* At EOF */
02113         if (position + nbytes > dv_size) nbytes = dv_size - position;
02114 
02115         nblocks = (before + nbytes + CD_SECTOR_SIZE - 1) / CD_SECTOR_SIZE;
02116         if (ATAPI_DEBUG) {
02117                 printf("block=%lu, before=%u, nbytes=%u, nblocks=%u\n",
02118                         block, before, nbytes, nblocks);
02119         }
02120 
02121         /* First check to see if a reinitialization is needed. */
02122         if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO);
02123 
02124         /* Build an ATAPI command packet. */
02125         packet[0] = SCSI_READ10;
02126         packet[1] = 0;
02127         packet[2] = (block >> 24) & 0xFF;
02128         packet[3] = (block >> 16) & 0xFF;
02129         packet[4] = (block >>  8) & 0xFF;
02130         packet[5] = (block >>  0) & 0xFF;
02131         packet[7] = (nblocks >> 8) & 0xFF;
02132         packet[8] = (nblocks >> 0) & 0xFF;
02133         packet[9] = 0;
02134         packet[10] = 0;
02135         packet[11] = 0;
02136 
02137         /* Tell the controller to execute the packet command. */
02138         r = atapi_sendpacket(packet, nblocks * CD_SECTOR_SIZE);
02139         if (r != OK) goto err;
02140 
02141         /* Read chunks of data. */
02142         while ((r = atapi_intr_wait()) > 0) {
02143                 count = r;
02144 
02145                 if (ATAPI_DEBUG) {
02146                         printf("before=%u, nbytes=%u, count=%u\n",
02147                                 before, nbytes, count);
02148                 }
02149 
02150                 while (before > 0 && count > 0) {       /* Discard before. */
02151                         chunk = before;
02152                         if (chunk > count) chunk = count;
02153                         if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE;
02154         if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, chunk)) != OK)
02155                 panic(w_name(),"Call to sys_insw() failed", s);
02156                         before -= chunk;
02157                         count -= chunk;
02158                 }
02159 
02160                 while (nbytes > 0 && count > 0) {       /* Requested data. */
02161                         chunk = nbytes;
02162                         if (chunk > count) chunk = count;
02163                         if (chunk > iov->iov_size) chunk = iov->iov_size;
02164         if ((s=sys_insw(wn->base_cmd + REG_DATA, proc_nr, (void *) iov->iov_addr, chunk)) != OK)
02165                 panic(w_name(),"Call to sys_insw() failed", s);
02166                         position += chunk;
02167                         nbytes -= chunk;
02168                         count -= chunk;
02169                         iov->iov_addr += chunk;
02170                         fresh = 0;
02171                         if ((iov->iov_size -= chunk) == 0) {
02172                                 iov++;
02173                                 nr_req--;
02174                                 fresh = 1;      /* new element is optional */
02175                         }
02176                 }
02177 
02178                 while (count > 0) {             /* Excess data. */
02179                         chunk = count;
02180                         if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE;
02181         if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, chunk)) != OK)
02182                 panic(w_name(),"Call to sys_insw() failed", s);
02183                         count -= chunk;
02184                 }
02185         }
02186 
02187         if (r < 0) {
02188   err:          /* Don't retry if too many errors. */
02189                 if (atapi_debug) sense_request();
02190                 if (++errors == max_errors) {
02191                         w_command = CMD_IDLE;
02192                         if (atapi_debug) printf("giving up (%d)\n", errors);
02193                         return(EIO);
02194                 }
02195                 if (atapi_debug) printf("retry (%d)\n", errors);
02196         }
02197   }
02198 
02199   w_command = CMD_IDLE;
02200   return(OK);
02201 }
02202 
02203 /*===========================================================================*
02204  *                              atapi_sendpacket                             *
02205  *===========================================================================*/
02206 PRIVATE int atapi_sendpacket(packet, cnt)
02207 u8_t *packet;
02208 unsigned cnt;
02209 {
02210 /* Send an Atapi Packet Command */
02211   struct wini *wn = w_wn;
02212   pvb_pair_t outbyte[6];                /* vector for sys_voutb() */
02213   int s;
02214 
02215   if (wn->state & IGNORING) return ERR;
02216 
02217   /* Select Master/Slave drive */
02218   if ((s=sys_outb(wn->base_cmd + REG_DRIVE, wn->ldhpref)) != OK)
02219         panic(w_name(),"Couldn't select master/ slave drive",s);
02220 
02221   if (!w_waitfor(STATUS_BSY | STATUS_DRQ, 0)) {
02222         printf("%s: atapi_sendpacket: drive not ready\n", w_name());
02223         return(ERR);
02224   }
02225 
02226   /* Schedule a wakeup call, some controllers are flaky. This is done with
02227    * a synchronous alarm. If a timeout occurs a SYN_ALARM message is sent
02228    * from HARDWARE, so that w_intr_wait() can call w_timeout() in case the
02229    * controller was not able to execute the command. Leftover timeouts are
02230    * simply ignored by the main loop. 
02231    */
02232   sys_setalarm(wakeup_ticks, 0);
02233 
02234 #if _WORD_SIZE > 2
02235   if (cnt > 0xFFFE) cnt = 0xFFFE;       /* Max data per interrupt. */
02236 #endif
02237 
02238   w_command = ATAPI_PACKETCMD;
02239   pv_set(outbyte[0], wn->base_cmd + REG_FEAT, 0);
02240   pv_set(outbyte[1], wn->base_cmd + REG_IRR, 0);
02241   pv_set(outbyte[2], wn->base_cmd + REG_SAMTAG, 0);
02242   pv_set(outbyte[3], wn->base_cmd + REG_CNT_LO, (cnt >> 0) & 0xFF);
02243   pv_set(outbyte[4], wn->base_cmd + REG_CNT_HI, (cnt >> 8) & 0xFF);
02244   pv_set(outbyte[5], wn->base_cmd + REG_COMMAND, w_command);
02245   if (atapi_debug) printf("cmd: %x  ", w_command);
02246   if ((s=sys_voutb(outbyte,6)) != OK)
02247         panic(w_name(),"Couldn't write registers with sys_voutb()",s);
02248 
02249   if (!w_waitfor(STATUS_BSY | STATUS_DRQ, STATUS_DRQ)) {
02250         printf("%s: timeout (BSY|DRQ -> DRQ)\n", w_name());
02251         return(ERR);
02252   }
02253   wn->w_status |= STATUS_ADMBSY;                /* Command not at all done yet. */
02254 
02255   /* Send the command packet to the device. */
02256   if ((s=sys_outsw(wn->base_cmd + REG_DATA, SELF, packet, ATAPI_PACKETSIZE)) != OK)
02257         panic(w_name(),"sys_outsw() failed", s);
02258 
02259  {
02260  int p;
02261  if (atapi_debug) {
02262         printf("sent command:");
02263          for(p = 0; p < ATAPI_PACKETSIZE; p++) { printf(" %02x", packet[p]); }
02264          printf("\n");
02265         }
02266  }
02267   return(OK);
02268 }
02269 
02270 
02271 #endif /* ENABLE_ATAPI */
02272 
02273 /*===========================================================================*
02274  *                              w_other                                      *
02275  *===========================================================================*/
02276 PRIVATE int w_other(dr, m)
02277 struct driver *dr;
02278 message *m;
02279 {
02280         int r, timeout, prev;
02281 
02282         if (m->m_type != DEV_IOCTL ) {
02283                 return EINVAL;
02284         }
02285 
02286         if (m->REQUEST == DIOCTIMEOUT) {
02287                 if ((r=sys_datacopy(m->IO_ENDPT, (vir_bytes)m->ADDRESS,
02288                         SELF, (vir_bytes)&timeout, sizeof(timeout))) != OK)
02289                         return r;
02290         
02291                 if (timeout == 0) {
02292                         /* Restore defaults. */
02293                         timeout_ticks = DEF_TIMEOUT_TICKS;
02294                         max_errors = MAX_ERRORS;
02295                         wakeup_ticks = WAKEUP;
02296                         w_silent = 0;
02297                 } else if (timeout < 0) {
02298                         return EINVAL;
02299                 } else  {
02300                         prev = wakeup_ticks;
02301         
02302                         if (!w_standard_timeouts) {
02303                                 /* Set (lower) timeout, lower error
02304                                  * tolerance and set silent mode.
02305                                  */
02306                                 wakeup_ticks = timeout;
02307                                 max_errors = 3;
02308                                 w_silent = 1;
02309         
02310                                 if (timeout_ticks > timeout)
02311                                         timeout_ticks = timeout;
02312                         }
02313         
02314                         if ((r=sys_datacopy(SELF, (vir_bytes)&prev, 
02315                                 m->IO_ENDPT, (vir_bytes)m->ADDRESS, sizeof(prev))) != OK)
02316                                 return r;
02317                 }
02318         
02319                 return OK;
02320         } else  if (m->REQUEST == DIOCOPENCT) {
02321                 int count;
02322                 if (w_prepare(m->DEVICE) == NIL_DEV) return ENXIO;
02323                 count = w_wn->open_ct;
02324                 if ((r=sys_datacopy(SELF, (vir_bytes)&count, 
02325                         m->IO_ENDPT, (vir_bytes)m->ADDRESS, sizeof(count))) != OK)
02326                         return r;
02327                 return OK;
02328         }
02329         return EINVAL;
02330 }
02331 
02332 /*===========================================================================*
02333  *                              w_hw_int                                     *
02334  *===========================================================================*/
02335 PRIVATE int w_hw_int(dr, m)
02336 struct driver *dr;
02337 message *m;
02338 {
02339   /* Leftover interrupt(s) received; ack it/them. */
02340   ack_irqs(m->NOTIFY_ARG);
02341 
02342   return OK;
02343 }
02344 
02345 
02346 /*===========================================================================*
02347  *                              ack_irqs                                     *
02348  *===========================================================================*/
02349 PRIVATE void ack_irqs(unsigned int irqs)
02350 {
02351   unsigned int drive;
02352   unsigned long w_status;
02353 
02354   for (drive = 0; drive < MAX_DRIVES && irqs; drive++) {
02355         if (!(wini[drive].state & IGNORING) && wini[drive].irq_need_ack &&
02356                 (wini[drive].irq_mask & irqs)) {
02357                 if (sys_inb((wini[drive].base_cmd + REG_STATUS),
02358                         &w_status) != OK)
02359                 {
02360                         panic(w_name(), "couldn't ack irq on drive %d\n",
02361                                 drive);
02362                 }
02363                 wini[drive].w_status= w_status;
02364                 if (sys_irqenable(&wini[drive].irq_hook_id) != OK)
02365                         printf("couldn't re-enable drive %d\n", drive);
02366                 irqs &= ~wini[drive].irq_mask;
02367         }
02368   }
02369 }
02370 
02371 
02372 #define STSTR(a) if (status & STATUS_ ## a) { strcat(str, #a); strcat(str, " "); }
02373 #define ERRSTR(a) if (e & ERROR_ ## a) { strcat(str, #a); strcat(str, " "); }
02374 char *strstatus(int status)
02375 {
02376         static char str[200];
02377         str[0] = '\0';
02378 
02379         STSTR(BSY);
02380         STSTR(DRDY);
02381         STSTR(DMADF);
02382         STSTR(SRVCDSC);
02383         STSTR(DRQ);
02384         STSTR(CORR);
02385         STSTR(CHECK);
02386         return str;
02387 }
02388 
02389 char *strerr(int e)
02390 {
02391         static char str[200];
02392         str[0] = '\0';
02393 
02394         ERRSTR(BB);
02395         ERRSTR(ECC);
02396         ERRSTR(ID);
02397         ERRSTR(AC);
02398         ERRSTR(TK);
02399         ERRSTR(DM);
02400 
02401         return str;
02402 }
02403 
02404 #if ENABLE_ATAPI
02405 
02406 /*===========================================================================*
02407  *                              atapi_intr_wait                              *
02408  *===========================================================================*/
02409 PRIVATE int atapi_intr_wait()
02410 {
02411 /* Wait for an interrupt and study the results.  Returns a number of bytes
02412  * that need to be transferred, or an error code.
02413  */
02414   struct wini *wn = w_wn;
02415   pvb_pair_t inbyte[4];         /* vector for sys_vinb() */
02416   int s;                        /* status for sys_vinb() */
02417   int e;
02418   int len;
02419   int irr;
02420   int r;
02421   int phase;
02422 
02423   w_intr_wait();
02424 
02425   /* Request series of device I/O. */
02426   inbyte[0].port = wn->base_cmd + REG_ERROR;
02427   inbyte[1].port = wn->base_cmd + REG_CNT_LO;
02428   inbyte[2].port = wn->base_cmd + REG_CNT_HI;
02429   inbyte[3].port = wn->base_cmd + REG_IRR;
02430   if ((s=sys_vinb(inbyte, 4)) != OK)
02431         panic(w_name(),"ATAPI failed sys_vinb()", s);
02432   e = inbyte[0].value;
02433   len = inbyte[1].value;
02434   len |= inbyte[2].value << 8;
02435   irr = inbyte[3].value;
02436 
02437 #if ATAPI_DEBUG
02438         printf("wn %p  S=%x=%s E=%02x=%s L=%04x I=%02x\n", wn, wn->w_status, strstatus(wn->w_status), e, strerr(e), len, irr);
02439 #endif
02440   if (wn->w_status & (STATUS_BSY | STATUS_CHECK)) {
02441         if (atapi_debug) {
02442                 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);
02443         }
02444         return ERR;
02445   }
02446 
02447   phase = (wn->w_status & STATUS_DRQ) | (irr & (IRR_COD | IRR_IO));
02448 
02449   switch (phase) {
02450   case IRR_COD | IRR_IO:
02451         if (ATAPI_DEBUG) printf("ACD: Phase Command Complete\n");
02452         r = OK;
02453         break;
02454   case 0:
02455         if (ATAPI_DEBUG) printf("ACD: Phase Command Aborted\n");
02456         r = ERR;
02457         break;
02458   case STATUS_DRQ | IRR_COD:
02459         if (ATAPI_DEBUG) printf("ACD: Phase Command Out\n");
02460         r = ERR;
02461         break;
02462   case STATUS_DRQ:
02463         if (ATAPI_DEBUG) printf("ACD: Phase Data Out %d\n", len);
02464         r = len;
02465         break;
02466   case STATUS_DRQ | IRR_IO:
02467         if (ATAPI_DEBUG) printf("ACD: Phase Data In %d\n", len);
02468         r = len;
02469         break;
02470   default:
02471         if (ATAPI_DEBUG) printf("ACD: Phase Unknown\n");
02472         r = ERR;
02473         break;
02474   }
02475 
02476 #if 0
02477   /* retry if the media changed */
02478   XXX while (phase == (IRR_IO | IRR_COD) && (wn->w_status & STATUS_CHECK)
02479         && (e & ERROR_SENSE) == SENSE_UATTN && --try > 0);
02480 #endif
02481 
02482   wn->w_status |= STATUS_ADMBSY;        /* Assume not done yet. */
02483   return(r);
02484 }
02485 #endif /* ENABLE_ATAPI */

Generated on Fri Apr 14 22:57:15 2006 for minix by  doxygen 1.4.6