The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bitsy/sdata.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include "u.h"
    2 #include "../port/lib.h"
    3 #include "mem.h"
    4 #include "dat.h"
    5 #include "fns.h"
    6 #include "io.h"
    7 #include "ureg.h"
    8 #include "../port/error.h"
    9 
   10 #include "../port/sd.h"
   11 
   12 
   13 extern SDifc sdataifc;
   14 
   15 //BUG?
   16 #define PCIWADDR(x)     ((ulong)(x))
   17 
   18 enum {
   19         DbgCONFIG       = 0x01,         /* detected drive config info */
   20         DbgIDENTIFY     = 0x02,         /* detected drive identify info */
   21         DbgSTATE        = 0x04,         /* dump state on panic */
   22         DbgPROBE        = 0x08,         /* trace device probing */
   23         DbgDEBUG        = 0x80,         /* the current problem... */
   24 };
   25 #define DEBUG           (DbgDEBUG|DbgSTATE|DbgCONFIG)
   26 
   27 enum {                                  /* I/O ports */
   28         Data            = 0,
   29         Error           = 1,            /* (read) */
   30         Features        = 1,            /* (write) */
   31         Count           = 2,            /* sector count */
   32         Ir              = 2,            /* interrupt reason (PACKET) */
   33         Sector          = 3,            /* sector number, LBA<7-0> */
   34         Cyllo           = 4,            /* cylinder low, LBA<15-8> */
   35         Bytelo          = 4,            /* byte count low (PACKET) */
   36         Cylhi           = 5,            /* cylinder high, LBA<23-16> */
   37         Bytehi          = 5,            /* byte count hi (PACKET) */
   38         Dh              = 6,            /* Device/Head, LBA<32-14> */
   39         Status          = 7,            /* (read) */
   40         Command         = 7,            /* (write) */
   41 
   42         As              = 2,            /* Alternate Status (read) */
   43         Dc              = 2,            /* Device Control (write) */
   44 };
   45 
   46 enum {                                  /* Error */
   47         Med             = 0x01,         /* Media error */
   48         Ili             = 0x01,         /* command set specific (PACKET) */
   49         Nm              = 0x02,         /* No Media */
   50         Eom             = 0x02,         /* command set specific (PACKET) */
   51         Abrt            = 0x04,         /* Aborted command */
   52         Mcr             = 0x08,         /* Media Change Request */
   53         Idnf            = 0x10,         /* no user-accessible address */
   54         Mc              = 0x20,         /* Media Change */
   55         Unc             = 0x40,         /* Uncorrectable data error */
   56         Wp              = 0x40,         /* Write Protect */
   57         Icrc            = 0x80,         /* Interface CRC error */
   58 };
   59 
   60 enum {                                  /* Features */
   61         Dma             = 0x01,         /* data transfer via DMA (PACKET) */
   62         Ovl             = 0x02,         /* command overlapped (PACKET) */
   63 };
   64 
   65 enum {                                  /* Interrupt Reason */
   66         Cd              = 0x01,         /* Command/Data */
   67         Io              = 0x02,         /* I/O direction */
   68         Rel             = 0x04,         /* Bus Release */
   69 };
   70 
   71 enum {                                  /* Device/Head */
   72         Dev0            = 0xA0,         /* Master */
   73         Dev1            = 0xB0,         /* Slave */
   74         Lba             = 0x40,         /* LBA mode */
   75 };
   76 
   77 enum {                                  /* Status, Alternate Status */
   78         Err             = 0x01,         /* Error */
   79         Chk             = 0x01,         /* Check error (PACKET) */
   80         Drq             = 0x08,         /* Data Request */
   81         Dsc             = 0x10,         /* Device Seek Complete */
   82         Serv            = 0x10,         /* Service */
   83         Df              = 0x20,         /* Device Fault */
   84         Dmrd            = 0x20,         /* DMA ready (PACKET) */
   85         Drdy            = 0x40,         /* Device Ready */
   86         Bsy             = 0x80,         /* Busy */
   87 };
   88 
   89 enum {                                  /* Command */
   90         Cnop            = 0x00,         /* NOP */
   91         Cdr             = 0x08,         /* Device Reset */
   92         Crs             = 0x20,         /* Read Sectors */
   93         Cws             = 0x30,         /* Write Sectors */
   94         Cedd            = 0x90,         /* Execute Device Diagnostics */
   95         Cpkt            = 0xA0,         /* Packet */
   96         Cidpkt          = 0xA1,         /* Identify Packet Device */
   97         Crsm            = 0xC4,         /* Read Multiple */
   98         Cwsm            = 0xC5,         /* Write Multiple */
   99         Csm             = 0xC6,         /* Set Multiple */
  100         Crdq            = 0xC7,         /* Read DMA queued */
  101         Crd             = 0xC8,         /* Read DMA */
  102         Cwd             = 0xCA,         /* Write DMA */
  103         Cwdq            = 0xCC,         /* Write DMA queued */
  104         Cstandby        = 0xE2,         /* Standby */
  105         Cid             = 0xEC,         /* Identify Device */
  106         Csf             = 0xEF,         /* Set Features */
  107 };
  108 
  109 enum {                                  /* Device Control */
  110         Nien            = 0x02,         /* (not) Interrupt Enable */
  111         Srst            = 0x04,         /* Software Reset */
  112 };
  113 
  114 enum {                                  /* PCI Configuration Registers */
  115         Bmiba           = 0x20,         /* Bus Master Interface Base Address */
  116         Idetim          = 0x40,         /* IE Timing */
  117         Sidetim         = 0x44,         /* Slave IE Timing */
  118         Udmactl         = 0x48,         /* Ultra DMA/33 Control */
  119         Udmatim         = 0x4A,         /* Ultra DMA/33 Timing */
  120 };
  121 
  122 enum {                                  /* Bus Master IDE I/O Ports */
  123         Bmicx           = 0,            /* Command */
  124         Bmisx           = 2,            /* Status */
  125         Bmidtpx         = 4,            /* Descriptor Table Pointer */
  126 };
  127 
  128 enum {                                  /* Bmicx */
  129         Ssbm            = 0x01,         /* Start/Stop Bus Master */
  130         Rwcon           = 0x08,         /* Read/Write Control */
  131 };
  132 
  133 enum {                                  /* Bmisx */
  134         Bmidea          = 0x01,         /* Bus Master IDE Active */
  135         Idedmae         = 0x02,         /* IDE DMA Error  (R/WC) */
  136         Ideints         = 0x04,         /* IDE Interrupt Status (R/WC) */
  137         Dma0cap         = 0x20,         /* Drive 0 DMA Capable */
  138         Dma1cap         = 0x40,         /* Drive 0 DMA Capable */
  139 };
  140 enum {                                  /* Physical Region Descriptor */
  141         PrdEOT          = 0x80000000,   /* Bus Master IDE Active */
  142 };
  143 
  144 enum {                                  /* offsets into the identify info. */
  145         Iconfig         = 0,            /* general configuration */
  146         Ilcyl           = 1,            /* logical cylinders */
  147         Ilhead          = 3,            /* logical heads */
  148         Ilsec           = 6,            /* logical sectors per logical track */
  149         Iserial         = 10,           /* serial number */
  150         Ifirmware       = 23,           /* firmware revision */
  151         Imodel          = 27,           /* model number */
  152         Imaxrwm         = 47,           /* max. read/write multiple sectors */
  153         Icapabilities   = 49,           /* capabilities */
  154         Istandby        = 50,           /* device specific standby timer */
  155         Ipiomode        = 51,           /* PIO data transfer mode number */
  156         Ivalid          = 53,
  157         Iccyl           = 54,           /* cylinders if (valid&0x01) */
  158         Ichead          = 55,           /* heads if (valid&0x01) */
  159         Icsec           = 56,           /* sectors if (valid&0x01) */
  160         Iccap           = 57,           /* capacity if (valid&0x01) */
  161         Irwm            = 59,           /* read/write multiple */
  162         Ilba0           = 60,           /* LBA size */
  163         Ilba1           = 61,           /* LBA size */
  164         Imwdma          = 63,           /* multiword DMA mode */
  165         Iapiomode       = 64,           /* advanced PIO modes supported */
  166         Iminmwdma       = 65,           /* min. multiword DMA cycle time */
  167         Irecmwdma       = 66,           /* rec. multiword DMA cycle time */
  168         Iminpio         = 67,           /* min. PIO cycle w/o flow control */
  169         Iminiordy       = 68,           /* min. PIO cycle with IORDY */
  170         Ipcktbr         = 71,           /* time from PACKET to bus release */
  171         Iserbsy         = 72,           /* time from SERVICE to !Bsy */
  172         Iqdepth         = 75,           /* max. queue depth */
  173         Imajor          = 80,           /* major version number */
  174         Iminor          = 81,           /* minor version number */
  175         Icsfs           = 82,           /* command set/feature supported */
  176         Icsfe           = 85,           /* command set/feature enabled */
  177         Iudma           = 88,           /* ultra DMA mode */
  178         Ierase          = 89,           /* time for security erase */
  179         Ieerase         = 90,           /* time for enhanced security erase */
  180         Ipower          = 91,           /* current advanced power management */
  181         Irmsn           = 127,          /* removable status notification */
  182         Istatus         = 128,          /* security status */
  183 };
  184 
  185 typedef struct Ctlr Ctlr;
  186 typedef struct Drive Drive;
  187 
  188 typedef struct Prd {
  189         ulong   pa;                     /* Physical Base Address */
  190         int     count;
  191 } Prd;
  192 
  193 enum {
  194         Nprd            = SDmaxio/(64*1024)+2,
  195 };
  196 
  197 typedef struct Ctlr {
  198         int     cmdport;
  199         int     ctlport;
  200         int     irq;
  201         int     tbdf;
  202         int     bmiba;                  /* bus master interface base address */
  203 
  204         void    (*ienable)(Ctlr*);
  205         SDev*   sdev;
  206 
  207         Drive*  drive[2];
  208 
  209         Prd*    prdt;                   /* physical region descriptor table */
  210 
  211         QLock;                          /* current command */
  212         Drive*  curdrive;
  213         int     command;                /* last command issued (debugging) */
  214         Rendez;
  215         int     done;
  216 
  217         Lock;                           /* register access */
  218 } Ctlr;
  219 
  220 typedef struct Drive {
  221         Ctlr*   ctlr;
  222 
  223         int     dev;
  224         ushort  info[256];
  225         int     c;                      /* cylinder */
  226         int     h;                      /* head */
  227         int     s;                      /* sector */
  228         int     sectors;                /* total */
  229         int     secsize;                /* sector size */
  230 
  231         int     dma;                    /* DMA R/W possible */
  232         int     dmactl;
  233         int     rwm;                    /* read/write multiple possible */
  234         int     rwmctl;
  235 
  236         int     pkt;                    /* PACKET device, length of pktcmd */
  237         uchar   pktcmd[16];
  238         int     pktdma;                 /* this PACKET command using dma */
  239 
  240         uchar   sense[18];
  241         uchar   inquiry[48];
  242 
  243         QLock;                          /* drive access */
  244         int     command;                /* current command */
  245         int     write;
  246         uchar*  data;
  247         int     dlen;
  248         uchar*  limit;
  249         int     count;                  /* sectors */
  250         int     block;                  /* R/W bytes per block */
  251         int     status;
  252         int     error;
  253 } Drive;
  254 
  255 
  256 
  257 static void
  258 atadumpstate(Drive* drive, uchar* cmd, int lba, int count)
  259 {
  260         Prd *prd;
  261         Ctlr *ctlr;
  262         int i, bmiba;
  263 
  264         if(!(DEBUG & DbgSTATE)){
  265                 USED(drive, cmd, lba, count);
  266                 return;
  267         }
  268 
  269         ctlr = drive->ctlr;
  270         print("command %2.2uX\n", ctlr->command);
  271         print("data %8.8p limit %8.8p dlen %d status %uX error %uX\n",
  272                 drive->data, drive->limit, drive->dlen,
  273                 drive->status, drive->error);
  274         if(cmd != nil){
  275                 print("lba %d -> %d, count %d -> %d (%d)\n",
  276                         (cmd[2]<<24)|(cmd[3]<<16)|(cmd[4]<<8)|cmd[5], lba,
  277                         (cmd[7]<<8)|cmd[8], count, drive->count);
  278         }
  279         if(!(inb(ctlr->ctlport+As) & Bsy)){
  280                 for(i = 1; i < 7; i++)
  281                         print(" 0x%2.2uX", inb(ctlr->cmdport+i));
  282                 print(" 0x%2.2uX\n", inb(ctlr->ctlport+As));
  283         }
  284         if(drive->command == Cwd || drive->command == Crd){
  285                 bmiba = ctlr->bmiba;
  286                 prd = ctlr->prdt;
  287                 print("bmicx %2.2uX bmisx %2.2uX prdt %8.8p\n",
  288                         inb(bmiba+Bmicx), inb(bmiba+Bmisx), prd);
  289                 for(;;){
  290                         print("pa 0x%8.8luX count %8.8uX\n",
  291                                 prd->pa, prd->count);
  292                         if(prd->count & PrdEOT)
  293                                 break;
  294                         prd++;
  295                 }
  296         }
  297 }
  298 
  299 static int
  300 atadebug(int cmdport, int ctlport, char* fmt, ...)
  301 {
  302         int i, n;
  303         va_list arg;
  304         char buf[PRINTSIZE];
  305 
  306         if(!(DEBUG & DbgPROBE)){
  307                 USED(cmdport, ctlport, fmt);
  308                 return 0;
  309         }
  310 
  311         va_start(arg, fmt);
  312         n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
  313         va_end(arg);
  314 
  315         if(cmdport){
  316                 if(buf[n-1] == '\n')
  317                         n--;
  318                 n += snprint(buf+n, PRINTSIZE-n, " ataregs 0x%uX:",
  319                         cmdport);
  320                 for(i = Features; i < Command; i++)
  321                         n += snprint(buf+n, PRINTSIZE-n, " 0x%2.2uX",
  322                                 inb(cmdport+i));
  323                 if(ctlport)
  324                         n += snprint(buf+n, PRINTSIZE-n, " 0x%2.2uX",
  325                                 inb(ctlport+As));
  326                 n += snprint(buf+n, PRINTSIZE-n, "\n");
  327         }
  328         putstrn(buf, n);
  329 
  330         return n;
  331 }
  332 
  333 static int
  334 ataready(int cmdport, int ctlport, int dev, int reset, int ready, int micro)
  335 {
  336         int as;
  337 
  338         atadebug(cmdport, ctlport, "ataready: dev %uX reset %uX ready %uX",
  339                 dev, reset, ready);
  340 
  341         for(;;){
  342                 /*
  343                  * Wait for the controller to become not busy and
  344                  * possibly for a status bit to become true (usually
  345                  * Drdy). Must change to the appropriate device
  346                  * register set if necessary before testing for ready.
  347                  * Always run through the loop at least once so it
  348                  * can be used as a test for !Bsy.
  349                  */
  350                 as = inb(ctlport+As);
  351                 if((as & reset) == 0){
  352                         if(dev){
  353                                 outb(cmdport+Dh, dev);
  354                                 dev = 0;
  355                         }
  356                         else if(ready == 0 || (as & ready)){
  357                                 atadebug(0, 0, "ataready: %d 0x%2.2uX\n", micro, as);
  358                                 return as;
  359                         }
  360                 }
  361                 if(micro-- <= 0){
  362                         atadebug(0, 0, "ataready: %d 0x%2.2uX\n", micro, as);
  363                         break;
  364                 }
  365                 microdelay(4);
  366         }
  367         atadebug(cmdport, ctlport, "ataready: timeout");
  368 
  369         return -1;
  370 }
  371 
  372 static int
  373 atacsf(Drive* drive, vlong csf, int supported)
  374 {
  375         ushort *info;
  376         int cmdset, i, x;
  377 
  378         if(supported)
  379                 info = &drive->info[Icsfs];
  380         else
  381                 info = &drive->info[Icsfe];
  382         
  383         for(i = 0; i < 3; i++){
  384                 x = (csf>>(16*i)) & 0xFFFF;
  385                 if(x == 0)
  386                         continue;
  387                 cmdset = info[i];
  388                 if(cmdset == 0 || cmdset == 0xFFFF)
  389                         return 0;
  390                 return cmdset & x;
  391         }
  392 
  393         return 0;
  394 }
  395 
  396 static int
  397 atadone(void* arg)
  398 {
  399         return ((Ctlr*)arg)->done;
  400 }
  401 
  402 static int
  403 atarwmmode(Drive* drive, int cmdport, int ctlport, int dev)
  404 {
  405         int as, maxrwm, rwm;
  406 
  407         maxrwm = (drive->info[Imaxrwm] & 0xFF);
  408         if(maxrwm == 0)
  409                 return 0;
  410 
  411         /*
  412          * Sometimes drives come up with the current count set
  413          * to 0; if so, set a suitable value, otherwise believe
  414          * the value in Irwm if the 0x100 bit is set.
  415          */
  416         if(drive->info[Irwm] & 0x100)
  417                 rwm = (drive->info[Irwm] & 0xFF);
  418         else
  419                 rwm = 0;
  420         if(rwm == 0)
  421                 rwm = maxrwm;
  422         if(rwm > 16)
  423                 rwm = 16;
  424         if(ataready(cmdport, ctlport, dev, Bsy|Drq, Drdy, 102*1000) < 0)
  425                 return 0;
  426         outb(cmdport+Count, rwm);
  427         outb(cmdport+Command, Csm);
  428         microdelay(4);
  429         as = ataready(cmdport, ctlport, 0, Bsy, Drdy|Df|Err, 1000);
  430         inb(cmdport+Status);
  431         if(as < 0 || (as & (Df|Err)))
  432                 return 0;
  433 
  434         drive->rwm = rwm;
  435 
  436         return rwm;
  437 }
  438 
  439 static int
  440 atadmamode(Drive* drive)
  441 {
  442         int dma;
  443 
  444         /*
  445          * Check if any DMA mode enabled.
  446          * Assumes the BIOS has picked and enabled the best.
  447          * This is completely passive at the moment, no attempt is
  448          * made to ensure the hardware is correctly set up.
  449          */
  450         dma = drive->info[Imwdma] & 0x0707;
  451         drive->dma = (dma>>8) & dma;
  452         if(drive->dma == 0 && (drive->info[Ivalid] & 0x04)){
  453                 dma = drive->info[Iudma] & 0x1F1F;
  454                 drive->dma = (dma>>8) & dma;
  455                 if(drive->dma)
  456                         drive->dma |= 'U'<<16;
  457         }
  458 
  459         return dma;
  460 }
  461 
  462 static int
  463 ataidentify(int cmdport, int ctlport, int dev, int pkt, void* info)
  464 {
  465         int as, command, drdy;
  466 
  467         if(pkt){
  468                 command = Cidpkt;
  469                 drdy = 0;
  470         }
  471         else{
  472                 command = Cid;
  473                 drdy = Drdy;
  474         }
  475         as = ataready(cmdport, ctlport, dev, Bsy|Drq, drdy, 103*1000);
  476         if(as < 0)
  477                 return as;
  478         outb(cmdport+Command, command);
  479         microdelay(4);
  480 
  481         as = ataready(cmdport, ctlport, 0, Bsy, Drq|Err, 400*1000);
  482         if(as < 0)
  483                 return -1;
  484         if(as & Err)
  485                 return as;
  486 
  487         memset(info, 0, 512);
  488         inss(cmdport+Data, info, 256);
  489         inb(cmdport+Status);
  490 
  491         if(DEBUG & DbgIDENTIFY){
  492                 int i;
  493                 ushort *sp;
  494 
  495                 sp = (ushort*)info;
  496                 for(i = 0; i < 32; i++){
  497                         if(i && (i%16) == 0)
  498                                 print("\n");
  499                         print(" %4.4uX", *sp);
  500                         sp++;
  501                 }
  502                 print("\n");
  503         }
  504 
  505         return 0;
  506 }
  507 
  508 static Drive*
  509 atadrive(int cmdport, int ctlport, int dev)
  510 {
  511         ushort *sp;
  512         Drive *drive;
  513         int as, i, pkt;
  514         uchar buf[512], *p;
  515 
  516         atadebug(0, 0, "identify: port 0x%uX dev 0x%2.2uX\n", cmdport, dev);
  517         pkt = 1;
  518 retry:
  519         as = ataidentify(cmdport, ctlport, dev, pkt, buf);
  520         if(as < 0)
  521                 return nil;
  522         if(as & Err){
  523                 if(pkt == 0)
  524                         return nil;
  525                 pkt = 0;
  526                 goto retry;
  527         }
  528 
  529         if((drive = malloc(sizeof(Drive))) == nil)
  530                 return nil;
  531         drive->dev = dev;
  532         memmove(drive->info, buf, sizeof(drive->info));
  533         drive->sense[0] = 0x70;
  534         drive->sense[7] = sizeof(drive->sense)-7;
  535 
  536         drive->inquiry[2] = 2;
  537         drive->inquiry[3] = 2;
  538         drive->inquiry[4] = sizeof(drive->inquiry)-4;
  539         p = &drive->inquiry[8];
  540         sp = &drive->info[Imodel];
  541         for(i = 0; i < 20; i++){
  542                 *p++ = *sp>>8;
  543                 *p++ = *sp++;
  544         }
  545 
  546         drive->secsize = 512;
  547         if(drive->info[Iconfig] != 0x848A && (drive->info[Iconfig] & 0xC000) == 0x8000){
  548                 if(drive->info[Iconfig] & 0x01)
  549                         drive->pkt = 16;
  550                 else
  551                         drive->pkt = 12;
  552         }
  553         else{
  554                 if(drive->info[Ivalid] & 0x0001){
  555                         drive->c = drive->info[Ilcyl];
  556                         drive->h = drive->info[Ilhead];
  557                         drive->s = drive->info[Ilsec];
  558                 }
  559                 else{
  560                         drive->c = drive->info[Iccyl];
  561                         drive->h = drive->info[Ichead];
  562                         drive->s = drive->info[Icsec];
  563                 }
  564                 if(drive->info[Icapabilities] & 0x0200){
  565                         drive->sectors = (drive->info[Ilba1]<<16)
  566                                          |drive->info[Ilba0];
  567                         drive->dev |= Lba;
  568                 }
  569                 else
  570                         drive->sectors = drive->c*drive->h*drive->s;
  571                 atarwmmode(drive, cmdport, ctlport, dev);
  572         }
  573         atadmamode(drive);      
  574 
  575         if(DEBUG & DbgCONFIG){
  576                 print("dev %2.2uX port %uX config %4.4uX capabilities %4.4uX",
  577                         dev, cmdport,
  578                         drive->info[Iconfig], drive->info[Icapabilities]);
  579                 print(" mwdma %4.4uX", drive->info[Imwdma]);
  580                 if(drive->info[Ivalid] & 0x04)
  581                         print(" udma %4.4uX", drive->info[Iudma]);
  582                 print(" dma %8.8uX rwm %ud\n", drive->dma, drive->rwm);
  583         }
  584 
  585         return drive;
  586 }
  587 
  588 static void
  589 atasrst(int ctlport)
  590 {
  591         /*
  592          * Srst is a big stick and may cause problems if further
  593          * commands are tried before the drives become ready again.
  594          * Also, there will be problems here if overlapped commands
  595          * are ever supported.
  596          */
  597         microdelay(20);
  598         outb(ctlport+Dc, Srst);
  599         microdelay(20);
  600         outb(ctlport+Dc, 0);
  601         microdelay(4*1000);
  602 }
  603 
  604 static SDev*
  605 ataprobe(int cmdport, int ctlport, int irq)
  606 {
  607         Ctlr* ctlr;
  608         SDev *sdev;
  609         Drive *drive;
  610         int dev, error, rhi, rlo;
  611 
  612         /*
  613          * Try to detect a floating bus.
  614          * Bsy should be cleared. If not, see if the cylinder registers
  615          * are read/write capable.
  616          * If the master fails, try the slave to catch slave-only
  617          * configurations.
  618          * There's no need to restore the tested registers as they will
  619          * be reset on any detected drives by the Cedd command.
  620          * All this indicates is that there is at least one drive on the
  621          * controller; when the non-existent drive is selected in a
  622          * single-drive configuration the registers of the existing drive
  623          * are often seen, only command execution fails.
  624          */
  625         dev = Dev0;
  626         if(inb(ctlport+As) & Bsy){
  627                 outb(cmdport+Dh, dev);
  628                 microdelay(5);
  629 trydev1:
  630                 atadebug(cmdport, ctlport, "ataprobe bsy");
  631                 outb(cmdport+Cyllo, 0xAA);
  632                 outb(cmdport+Cylhi, 0x55);
  633                 outb(cmdport+Sector, 0xFF);
  634                 rlo = inb(cmdport+Cyllo);
  635                 rhi = inb(cmdport+Cylhi);
  636                 if(rlo != 0xAA && (rlo == 0xFF || rhi != 0x55)){
  637                         if(dev == Dev1){
  638 release:
  639                                 return nil;
  640                         }
  641                         dev = Dev1;
  642                         if(ataready(cmdport, ctlport, dev, Bsy, 0, 20*1000) < 0)
  643                                 goto trydev1;
  644                 }
  645         }
  646 
  647         /*
  648          * Disable interrupts on any detected controllers.
  649          */
  650         outb(ctlport+Dc, Nien);
  651 tryedd1:
  652         if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 105*1000) < 0){
  653                 /*
  654                  * There's something there, but it didn't come up clean,
  655                  * so try hitting it with a big stick. The timing here is
  656                  * wrong but this is a last-ditch effort and it sometimes
  657                  * gets some marginal hardware back online.
  658                  */
  659                 atasrst(ctlport);
  660                 if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 106*1000) < 0)
  661                         goto release;
  662         }
  663 
  664         /*
  665          * Can only get here if controller is not busy.
  666          * If there are drives Bsy will be set within 400nS,
  667          * must wait 2mS before testing Status.
  668          * Wait for the command to complete (6 seconds max).
  669          */
  670         outb(cmdport+Command, Cedd);
  671         delay(5);
  672         if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 6*1000*1000) < 0)
  673                 goto release;
  674 
  675         /*
  676          * If bit 0 of the error register is set then the selected drive
  677          * exists. This is enough to detect single-drive configurations.
  678          * However, if the master exists there is no way short of executing
  679          * a command to determine if a slave is present.
  680          * It appears possible to get here testing Dev0 although it doesn't
  681          * exist and the EDD won't take, so try again with Dev1.
  682          */
  683         error = inb(cmdport+Error);
  684         atadebug(cmdport, ctlport, "ataprobe: dev %uX", dev);
  685         if((error & ~0x80) != 0x01){
  686                 if(dev == Dev1)
  687                         goto release;
  688                 dev = Dev1;
  689                 goto tryedd1;
  690         }
  691 
  692         /*
  693          * At least one drive is known to exist, try to
  694          * identify it. If that fails, don't bother checking
  695          * any further.
  696          * If the one drive found is Dev0 and the EDD command
  697          * didn't indicate Dev1 doesn't exist, check for it.
  698          */
  699         if((drive = atadrive(cmdport, ctlport, dev)) == nil)
  700                 goto release;
  701         if((ctlr = malloc(sizeof(Ctlr))) == nil){
  702                 free(drive);
  703                 goto release;
  704         }
  705         if((sdev = malloc(sizeof(SDev))) == nil){
  706                 free(ctlr);
  707                 free(drive);
  708                 goto release;
  709         }
  710         drive->ctlr = ctlr;
  711         if(dev == Dev0){
  712                 ctlr->drive[0] = drive;
  713 #ifdef notdef
  714                 if(!(error & 0x80)){
  715                         /*
  716                          * Always leave Dh pointing to a valid drive,
  717                          * otherwise a subsequent call to ataready on
  718                          * this controller may try to test a bogus Status.
  719                          * Ataprobe is the only place possibly invalid
  720                          * drives should be selected.
  721                          */
  722                         drive = atadrive(cmdport, ctlport, Dev1);
  723                         if(drive != nil){
  724                                 drive->ctlr = ctlr;
  725                                 ctlr->drive[1] = drive;
  726                         }
  727                         else{
  728                                 outb(cmdport+Dh, Dev0);
  729                                 microdelay(1);
  730                         }
  731                 }
  732 #endif
  733         }
  734         else
  735                 ctlr->drive[1] = drive;
  736 
  737         ctlr->cmdport = cmdport;
  738         ctlr->ctlport = ctlport;
  739         ctlr->irq = irq;
  740         ctlr->tbdf = -1;
  741         ctlr->command = Cedd;           /* debugging */
  742 
  743         sdev->ifc = &sdataifc;
  744         sdev->ctlr = ctlr;
  745         sdev->idno = 'C';
  746         sdev->nunit = 1;
  747         ctlr->sdev = sdev;
  748 
  749         return sdev;
  750 }
  751 
  752 static int
  753 atasetsense(Drive* drive, int status, int key, int asc, int ascq)
  754 {
  755         drive->sense[2] = key;
  756         drive->sense[12] = asc;
  757         drive->sense[13] = ascq;
  758 
  759         return status;
  760 }
  761 
  762 static int
  763 atastandby(Drive* drive, int period)
  764 {
  765         Ctlr* ctlr;
  766         int cmdport, done;
  767 
  768         ctlr = drive->ctlr;
  769         drive->command = Cstandby;
  770         qlock(ctlr);
  771 
  772         cmdport = ctlr->cmdport;
  773         ilock(ctlr);
  774         outb(cmdport+Count, period);
  775         outb(cmdport+Dh, drive->dev);
  776         ctlr->done = 0;
  777         ctlr->curdrive = drive;
  778         ctlr->command = Cstandby;       /* debugging */
  779         outb(cmdport+Command, Cstandby);
  780         iunlock(ctlr);
  781 
  782         while(waserror())
  783                 ;
  784         tsleep(ctlr, atadone, ctlr, 30*1000);
  785         poperror();
  786 
  787         done = ctlr->done;
  788         qunlock(ctlr);
  789 
  790         if(!done || (drive->status & Err))
  791                 return atasetsense(drive, SDcheck, 4, 8, drive->error);
  792         return SDok;
  793 }
  794 
  795 static int
  796 atamodesense(Drive* drive, uchar* cmd)
  797 {
  798         int len;
  799 
  800         /*
  801          * Fake a vendor-specific request with page code 0,
  802          * return the drive info.
  803          */
  804         if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
  805                 return atasetsense(drive, SDcheck, 0x05, 0x24, 0);
  806         len = (cmd[7]<<8)|cmd[8];
  807         if(len == 0)
  808                 return SDok;
  809         if(len < 8+sizeof(drive->info))
  810                 return atasetsense(drive, SDcheck, 0x05, 0x1A, 0);
  811         if(drive->data == nil || drive->dlen < len)
  812                 return atasetsense(drive, SDcheck, 0x05, 0x20, 1);
  813         memset(drive->data, 0, 8);
  814         drive->data[0] = sizeof(drive->info)>>8;
  815         drive->data[1] = sizeof(drive->info);
  816         memmove(drive->data+8, drive->info, sizeof(drive->info));
  817         drive->data += 8+sizeof(drive->info);
  818 
  819         return SDok;
  820 }
  821 
  822 static void
  823 atanop(Drive* drive, int subcommand)
  824 {
  825         Ctlr* ctlr;
  826         int as, cmdport, ctlport, timeo;
  827 
  828         /*
  829          * Attempt to abort a command by using NOP.
  830          * In response, the drive is supposed to set Abrt
  831          * in the Error register, set (Drdy|Err) in Status
  832          * and clear Bsy when done. However, some drives
  833          * (e.g. ATAPI Zip) just go Bsy then clear Status
  834          * when done, hence the timeout loop only on Bsy
  835          * and the forced setting of drive->error.
  836          */
  837         ctlr = drive->ctlr;
  838         cmdport = ctlr->cmdport;
  839         outb(cmdport+Features, subcommand);
  840         outb(cmdport+Dh, drive->dev);
  841         ctlr->command = Cnop;           /* debugging */
  842         outb(cmdport+Command, Cnop);
  843 
  844         microdelay(1);
  845         ctlport = ctlr->ctlport;
  846         for(timeo = 0; timeo < 1000; timeo++){
  847                 as = inb(ctlport+As);
  848                 if(!(as & Bsy))
  849                         break;
  850                 microdelay(1);
  851         }
  852         drive->error |= Abrt;
  853 }
  854 
  855 static void
  856 ataabort(Drive* drive, int dolock)
  857 {
  858         /*
  859          * If NOP is available (packet commands) use it otherwise
  860          * must try a software reset.
  861          */
  862         if(dolock)
  863                 ilock(drive->ctlr);
  864         if(atacsf(drive, 0x0000000000004000LL, 0))
  865                 atanop(drive, 0);
  866         else{
  867                 atasrst(drive->ctlr->ctlport);
  868                 drive->error |= Abrt;
  869         }
  870         if(dolock)
  871                 iunlock(drive->ctlr);
  872 }
  873 
  874 static int
  875 atadmasetup(Drive* drive, int )
  876 {
  877         drive->dmactl = 0;
  878         return -1;
  879 
  880 #ifdef notdef
  881         Prd *prd;
  882         ulong pa;
  883         Ctlr *ctlr;
  884         int bmiba, bmisx, count;
  885 
  886         pa = PCIWADDR(drive->data);
  887         if(pa & 0x03)
  888                 return -1;
  889         ctlr = drive->ctlr;
  890         prd = ctlr->prdt;
  891 
  892         /*
  893          * Sometimes drives identify themselves as being DMA capable
  894          * although they are not on a busmastering controller.
  895          */
  896         if(prd == nil){
  897                 drive->dmactl = 0;
  898                 return -1;
  899         }
  900 
  901         for(;;){
  902                 prd->pa = pa;
  903                 count = 64*1024 - (pa & 0xFFFF);
  904                 if(count >= len){
  905                         prd->count = PrdEOT|(len & 0xFFFF);
  906                         break;
  907                 }
  908                 prd->count = count;
  909                 len -= count;
  910                 pa += count;
  911                 prd++;
  912         }
  913 
  914         bmiba = ctlr->bmiba;
  915         outl(bmiba+Bmidtpx, PCIWADDR(ctlr->prdt));
  916         if(drive->write)
  917                 outb(ctlr->bmiba+Bmicx, 0);
  918         else
  919                 outb(ctlr->bmiba+Bmicx, Rwcon);
  920         bmisx = inb(bmiba+Bmisx);
  921         outb(bmiba+Bmisx, bmisx|Ideints|Idedmae);
  922 
  923         return 0;
  924 #endif
  925 }
  926 
  927 static void
  928 atadmastart(Ctlr* ctlr, int write)
  929 {
  930         if(write)
  931                 outb(ctlr->bmiba+Bmicx, Ssbm);
  932         else
  933                 outb(ctlr->bmiba+Bmicx, Rwcon|Ssbm);
  934 }
  935 
  936 static int
  937 atadmastop(Ctlr* ctlr)
  938 {
  939         int bmiba;
  940 
  941         bmiba = ctlr->bmiba;
  942         outb(bmiba+Bmicx, inb(bmiba+Bmicx) & ~Ssbm);
  943 
  944         return inb(bmiba+Bmisx);
  945 }
  946 
  947 static void
  948 atadmainterrupt(Drive* drive, int count)
  949 {
  950         Ctlr* ctlr;
  951         int bmiba, bmisx;
  952 
  953         ctlr = drive->ctlr;
  954         bmiba = ctlr->bmiba;
  955         bmisx = inb(bmiba+Bmisx);
  956         switch(bmisx & (Ideints|Idedmae|Bmidea)){
  957         case Bmidea:
  958                 /*
  959                  * Data transfer still in progress, nothing to do
  960                  * (this should never happen).
  961                  */
  962                 return;
  963 
  964         case Ideints:
  965         case Ideints|Bmidea:
  966                 /*
  967                  * Normal termination, tidy up.
  968                  */
  969                 drive->data += count;
  970                 break;
  971 
  972         default:
  973                 /*
  974                  * What's left are error conditions (memory transfer
  975                  * problem) and the device is not done but the PRD is
  976                  * exhausted. For both cases must somehow tell the
  977                  * drive to abort.
  978                  */
  979                 ataabort(drive, 0);
  980                 break;
  981         }
  982         atadmastop(ctlr);
  983         ctlr->done = 1;
  984 }
  985 
  986 static void
  987 atapktinterrupt(Drive* drive)
  988 {
  989         Ctlr* ctlr;
  990         int cmdport, len;
  991 
  992         ctlr = drive->ctlr;
  993         cmdport = ctlr->cmdport;
  994         switch(inb(cmdport+Ir) & (/*Rel|*/Io|Cd)){
  995         case Cd:
  996                 outss(cmdport+Data, drive->pktcmd, drive->pkt/2);
  997                 break;
  998 
  999         case 0:
 1000                 len = (inb(cmdport+Bytehi)<<8)|inb(cmdport+Bytelo);
 1001                 if(drive->data+len > drive->limit){
 1002                         atanop(drive, 0);
 1003                         break;
 1004                 }
 1005                 outss(cmdport+Data, drive->data, len/2);
 1006                 drive->data += len;
 1007                 break;
 1008 
 1009         case Io:
 1010                 len = (inb(cmdport+Bytehi)<<8)|inb(cmdport+Bytelo);
 1011                 if(drive->data+len > drive->limit){
 1012                         atanop(drive, 0);
 1013                         break;
 1014                 }
 1015                 inss(cmdport+Data, drive->data, len/2);
 1016                 drive->data += len;
 1017                 break;
 1018 
 1019         case Io|Cd:
 1020                 if(drive->pktdma)
 1021                         atadmainterrupt(drive, drive->dlen);
 1022                 else
 1023                         ctlr->done = 1;
 1024                 break;
 1025         }
 1026 }
 1027 
 1028 static int
 1029 atapktio(Drive* drive, uchar* cmd, int clen)
 1030 {
 1031         Ctlr *ctlr;
 1032         int as, cmdport, ctlport, len, r, timeo;
 1033 
 1034         if(cmd[0] == 0x5A && (cmd[2] & 0x3F) == 0)
 1035                 return atamodesense(drive, cmd);
 1036 
 1037         r = SDok;
 1038 
 1039         drive->command = Cpkt;
 1040         memmove(drive->pktcmd, cmd, clen);
 1041         memset(drive->pktcmd+clen, 0, drive->pkt-clen);
 1042         drive->limit = drive->data+drive->dlen;
 1043 
 1044         ctlr = drive->ctlr;
 1045         cmdport = ctlr->cmdport;
 1046         ctlport = ctlr->ctlport;
 1047 
 1048         qlock(ctlr);
 1049 
 1050         if(ataready(cmdport, ctlport, drive->dev, Bsy|Drq, 0, 107*1000) < 0){
 1051                 qunlock(ctlr);
 1052                 return -1;
 1053         }
 1054 
 1055         ilock(ctlr);
 1056         if(drive->dlen && drive->dmactl && !atadmasetup(drive, drive->dlen))
 1057                 drive->pktdma = Dma;
 1058         else
 1059                 drive->pktdma = 0;
 1060 
 1061         outb(cmdport+Features, drive->pktdma);
 1062         outb(cmdport+Count, 0);
 1063         outb(cmdport+Sector, 0);
 1064         len = 16*drive->secsize;
 1065         outb(cmdport+Bytelo, len);
 1066         outb(cmdport+Bytehi, len>>8);
 1067         outb(cmdport+Dh, drive->dev);
 1068         ctlr->done = 0;
 1069         ctlr->curdrive = drive;
 1070         ctlr->command = Cpkt;           /* debugging */
 1071         if(drive->pktdma)
 1072                 atadmastart(ctlr, drive->write);
 1073         outb(cmdport+Command, Cpkt);
 1074 
 1075         if((drive->info[Iconfig] & 0x0060) != 0x0020){
 1076                 microdelay(1);
 1077                 as = ataready(cmdport, ctlport, 0, Bsy, Drq|Chk, 4*1000);
 1078                 if(as < 0)
 1079                         r = SDtimeout;
 1080                 else if(as & Chk)
 1081                         r = SDcheck;
 1082                 else
 1083                         atapktinterrupt(drive);
 1084         }
 1085         iunlock(ctlr);
 1086 
 1087         while(waserror())
 1088                 ;
 1089         if(!drive->pktdma)
 1090                 sleep(ctlr, atadone, ctlr);
 1091         else for(timeo = 0; !ctlr->done; timeo++){
 1092                 tsleep(ctlr, atadone, ctlr, 1000);
 1093                 if(ctlr->done)
 1094                         break;
 1095                 ilock(ctlr);
 1096                 atadmainterrupt(drive, 0);
 1097                 if(!drive->error && timeo > 10){
 1098                         ataabort(drive, 0);
 1099                         atadmastop(ctlr);
 1100                         drive->dmactl = 0;
 1101                         drive->error |= Abrt;
 1102                 }
 1103                 if(drive->error){
 1104                         drive->status |= Chk;
 1105                         ctlr->curdrive = nil;
 1106                 }
 1107                 iunlock(ctlr);
 1108         }
 1109         poperror();
 1110 
 1111         qunlock(ctlr);
 1112 
 1113         if(drive->status & Chk)
 1114                 r = SDcheck;
 1115 
 1116         return r;
 1117 }
 1118 
 1119 static int
 1120 atageniostart(Drive* drive, int lba)
 1121 {
 1122         Ctlr *ctlr;
 1123         int as, c, cmdport, ctlport, h, len, s;
 1124 
 1125         if(drive->dev & Lba){
 1126                 c = (lba>>8) & 0xFFFF;
 1127                 h = (lba>>24) & 0x0F;
 1128                 s = lba & 0xFF;
 1129         }
 1130         else{
 1131                 c = lba/(drive->s*drive->h);
 1132                 h = ((lba/drive->s) % drive->h);
 1133                 s = (lba % drive->s) + 1;
 1134         }
 1135 
 1136         ctlr = drive->ctlr;
 1137         cmdport = ctlr->cmdport;
 1138         ctlport = ctlr->ctlport;
 1139         if(ataready(cmdport, ctlport, drive->dev, Bsy|Drq, 0, 101*1000) < 0)
 1140                 return -1;
 1141 
 1142         ilock(ctlr);
 1143         if(drive->dmactl && !atadmasetup(drive, drive->count*drive->secsize)){
 1144                 if(drive->write)
 1145                         drive->command = Cwd;
 1146                 else
 1147                         drive->command = Crd;
 1148         }
 1149         else if(drive->rwmctl){
 1150                 drive->block = drive->rwm*drive->secsize;
 1151                 if(drive->write)
 1152                         drive->command = Cwsm;
 1153                 else
 1154                         drive->command = Crsm;
 1155         }
 1156         else{
 1157                 drive->block = drive->secsize;
 1158                 if(drive->write)
 1159                         drive->command = Cws;
 1160                 else
 1161                         drive->command = Crs;
 1162         }
 1163         drive->limit = drive->data + drive->count*drive->secsize;
 1164 
 1165         outb(cmdport+Count, drive->count);
 1166         outb(cmdport+Sector, s);
 1167         outb(cmdport+Dh, drive->dev|h);
 1168         outb(cmdport+Cyllo, c);
 1169         outb(cmdport+Cylhi, c>>8);
 1170         ctlr->done = 0;
 1171         ctlr->curdrive = drive;
 1172         ctlr->command = drive->command; /* debugging */
 1173         outb(cmdport+Command, drive->command);
 1174 
 1175         switch(drive->command){
 1176         case Cws:
 1177         case Cwsm:
 1178                 microdelay(1);
 1179                 as = ataready(cmdport, ctlport, 0, Bsy, Drq|Err, 1000);
 1180                 if(as < 0 || (as & Err)){
 1181                         iunlock(ctlr);
 1182                         return -1;
 1183                 }
 1184                 len = drive->block;
 1185                 if(drive->data+len > drive->limit)
 1186                         len = drive->limit-drive->data;
 1187                 outss(cmdport+Data, drive->data, len/2);
 1188                 break;
 1189 
 1190         case Crd:
 1191         case Cwd:
 1192                 atadmastart(ctlr, drive->write);
 1193                 break;
 1194         }
 1195         iunlock(ctlr);
 1196 
 1197         return 0;
 1198 }
 1199 
 1200 static int
 1201 atagenioretry(Drive* drive)
 1202 {
 1203         if(drive->dmactl)
 1204                 drive->dmactl = 0;
 1205         else if(drive->rwmctl)
 1206                 drive->rwmctl = 0;
 1207         else
 1208                 return atasetsense(drive, SDcheck, 4, 8, drive->error);
 1209 
 1210         return SDretry;
 1211 }
 1212 
 1213 static int
 1214 atagenio(Drive* drive, uchar* cmd, int)
 1215 {
 1216         uchar *p;
 1217         Ctlr *ctlr;
 1218         int count, lba, len;
 1219 
 1220         /*
 1221          * Map SCSI commands into ATA commands for discs.
 1222          * Fail any command with a LUN except INQUIRY which
 1223          * will return 'logical unit not supported'.
 1224          */
 1225         if((cmd[1]>>5) && cmd[0] != 0x12)
 1226                 return atasetsense(drive, SDcheck, 0x05, 0x25, 0);
 1227 
 1228         switch(cmd[0]){
 1229         default:
 1230                 return atasetsense(drive, SDcheck, 0x05, 0x20, 0);
 1231 
 1232         case 0x00:                      /* test unit ready */
 1233                 return SDok;
 1234 
 1235         case 0x03:                      /* request sense */
 1236                 if(cmd[4] < sizeof(drive->sense))
 1237                         len = cmd[4];
 1238                 else
 1239                         len = sizeof(drive->sense);
 1240                 if(drive->data && drive->dlen >= len){
 1241                         memmove(drive->data, drive->sense, len);
 1242                         drive->data += len;
 1243                 }
 1244                 return SDok;
 1245 
 1246         case 0x12:                      /* inquiry */
 1247                 if(cmd[4] < sizeof(drive->inquiry))
 1248                         len = cmd[4];
 1249                 else
 1250                         len = sizeof(drive->inquiry);
 1251                 if(drive->data && drive->dlen >= len){
 1252                         memmove(drive->data, drive->inquiry, len);
 1253                         drive->data += len;
 1254                 }
 1255                 return SDok;
 1256 
 1257         case 0x1B:                      /* start/stop unit */
 1258                 /*
 1259                  * NOP for now, can use the power management feature
 1260                  * set later.
 1261                  */
 1262                 return SDok;
 1263 
 1264         case 0x25:                      /* read capacity */
 1265                 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
 1266                         return atasetsense(drive, SDcheck, 0x05, 0x24, 0);
 1267                 if(drive->data == nil || drive->dlen < 8)
 1268                         return atasetsense(drive, SDcheck, 0x05, 0x20, 1);
 1269                 /*
 1270                  * Read capacity returns the LBA of the last sector.
 1271                  */
 1272                 len = drive->sectors-1;
 1273                 p = drive->data;
 1274                 *p++ = len>>24;
 1275                 *p++ = len>>16;
 1276                 *p++ = len>>8;
 1277                 *p++ = len;
 1278                 len = drive->secsize;
 1279                 *p++ = len>>24;
 1280                 *p++ = len>>16;
 1281                 *p++ = len>>8;
 1282                 *p = len;
 1283                 drive->data += 8;
 1284                 return SDok;
 1285 
 1286         case 0x28:                      /* read */
 1287         case 0x2A:                      /* write */
 1288                 break;
 1289 
 1290         case 0x5A:
 1291                 return atamodesense(drive, cmd);
 1292         }
 1293 
 1294         ctlr = drive->ctlr;
 1295         lba = (cmd[2]<<24)|(cmd[3]<<16)|(cmd[4]<<8)|cmd[5];
 1296         count = (cmd[7]<<8)|cmd[8];
 1297         if(drive->data == nil)
 1298                 return SDok;
 1299         if(drive->dlen < count*drive->secsize)
 1300                 count = drive->dlen/drive->secsize;
 1301         qlock(ctlr);
 1302         while(count){
 1303                 if(count > 256)
 1304                         drive->count = 256;
 1305                 else
 1306                         drive->count = count;
 1307                 if(atageniostart(drive, lba)){
 1308                         ilock(ctlr);
 1309                         atanop(drive, 0);
 1310                         iunlock(ctlr);
 1311                         qunlock(ctlr);
 1312                         return atagenioretry(drive);
 1313                 }
 1314 
 1315                 while(waserror())
 1316                         ;
 1317                 tsleep(ctlr, atadone, ctlr, 30*1000);
 1318                 poperror();
 1319                 if(!ctlr->done){
 1320                         /*
 1321                          * What should the above timeout be? In
 1322                          * standby and sleep modes it could take as
 1323                          * long as 30 seconds for a drive to respond.
 1324                          * Very hard to get out of this cleanly.
 1325                          */
 1326                         atadumpstate(drive, cmd, lba, count);
 1327                         ataabort(drive, 1);
 1328                         qunlock(ctlr);
 1329                         return atagenioretry(drive);
 1330                 }
 1331 
 1332                 if(drive->status & Err){
 1333                         qunlock(ctlr);
 1334                         return atasetsense(drive, SDcheck, 4, 8, drive->error);
 1335                 }
 1336                 count -= drive->count;
 1337                 lba += drive->count;
 1338         }
 1339         qunlock(ctlr);
 1340 
 1341         return SDok;
 1342 }
 1343 
 1344 static int
 1345 atario(SDreq* r)
 1346 {
 1347         Ctlr *ctlr;
 1348         Drive *drive;
 1349         SDunit *unit;
 1350         uchar cmd10[10], *cmdp, *p;
 1351         int clen, reqstatus, status;
 1352 
 1353         unit = r->unit;
 1354         if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil){
 1355                 r->status = SDtimeout;
 1356                 return SDtimeout;
 1357         }
 1358         drive = ctlr->drive[unit->subno];
 1359 
 1360         /*
 1361          * Most SCSI commands can be passed unchanged except for
 1362          * the padding on the end. The few which require munging
 1363          * are not used internally. Mode select/sense(6) could be
 1364          * converted to the 10-byte form but it's not worth the
 1365          * effort. Read/write(6) are easy.
 1366          */
 1367         switch(r->cmd[0]){
 1368         case 0x08:                      /* read */
 1369         case 0x0A:                      /* write */
 1370                 cmdp = cmd10;
 1371                 memset(cmdp, 0, sizeof(cmd10));
 1372                 cmdp[0] = r->cmd[0]|0x20;
 1373                 cmdp[1] = r->cmd[1] & 0xE0;
 1374                 cmdp[5] = r->cmd[3];
 1375                 cmdp[4] = r->cmd[2];
 1376                 cmdp[3] = r->cmd[1] & 0x0F;
 1377                 cmdp[8] = r->cmd[4];
 1378                 clen = sizeof(cmd10);
 1379                 break;
 1380 
 1381         default:
 1382                 cmdp = r->cmd;
 1383                 clen = r->clen;
 1384                 break;
 1385         }
 1386 
 1387         qlock(drive);
 1388 retry:
 1389         drive->write = r->write;
 1390         drive->data = r->data;
 1391         drive->dlen = r->dlen;
 1392 
 1393         drive->status = 0;
 1394         drive->error = 0;
 1395         if(drive->pkt)
 1396                 status = atapktio(drive, cmdp, clen);
 1397         else
 1398                 status = atagenio(drive, cmdp, clen);
 1399         if(status == SDretry){
 1400                 if(DbgDEBUG)
 1401                         print("%s: retry: dma %8.8uX rwm %4.4uX\n",
 1402                                 unit->name, drive->dmactl, drive->rwmctl);
 1403                 goto retry;
 1404         }
 1405         if(status == SDok){
 1406                 atasetsense(drive, SDok, 0, 0, 0);
 1407                 if(drive->data){
 1408                         p = r->data;
 1409                         r->rlen = drive->data - p;
 1410                 }
 1411                 else
 1412                         r->rlen = 0;
 1413         }
 1414         else if(status == SDcheck && !(r->flags & SDnosense)){
 1415                 drive->write = 0;
 1416                 memset(cmd10, 0, sizeof(cmd10));
 1417                 cmd10[0] = 0x03;
 1418                 cmd10[1] = r->lun<<5;
 1419                 cmd10[4] = sizeof(r->sense)-1;
 1420                 drive->data = r->sense;
 1421                 drive->dlen = sizeof(r->sense)-1;
 1422                 drive->status = 0;
 1423                 drive->error = 0;
 1424                 if(drive->pkt)
 1425                         reqstatus = atapktio(drive, cmd10, 6);
 1426                 else
 1427                         reqstatus = atagenio(drive, cmd10, 6);
 1428                 if(reqstatus == SDok){
 1429                         r->flags |= SDvalidsense;
 1430                         atasetsense(drive, SDok, 0, 0, 0);
 1431                 }
 1432         }
 1433         qunlock(drive);
 1434         r->status = status;
 1435         if(status != SDok)
 1436                 return status;
 1437 
 1438         /*
 1439          * Fix up any results.
 1440          * Many ATAPI CD-ROMs ignore the LUN field completely and
 1441          * return valid INQUIRY data. Patch the response to indicate
 1442          * 'logical unit not supported' if the LUN is non-zero.
 1443          */
 1444         switch(cmdp[0]){
 1445         case 0x12:                      /* inquiry */
 1446                 if((p = r->data) == nil)
 1447                         break;
 1448                 if((cmdp[1]>>5) && (!drive->pkt || (p[0] & 0x1F) == 0x05))
 1449                         p[0] = 0x7F;
 1450                 /*FALLTHROUGH*/
 1451         default:
 1452                 break;
 1453         }
 1454 
 1455         return SDok;
 1456 }
 1457 
 1458 
 1459 static void
 1460 atainterrupt(Ureg*, void* arg)
 1461 {
 1462         Ctlr *ctlr;
 1463         Drive *drive;
 1464         int cmdport, len, status;
 1465 
 1466         ctlr = arg;
 1467 
 1468         ilock(ctlr);
 1469         if(inb(ctlr->ctlport+As) & Bsy){
 1470                 iunlock(ctlr);
 1471                 if(DEBUG & DbgDEBUG)
 1472                         print("IBsy+");
 1473                 return;
 1474         }
 1475         cmdport = ctlr->cmdport;
 1476         status = inb(cmdport+Status);
 1477         if((drive = ctlr->curdrive) == nil){
 1478                 iunlock(ctlr);
 1479                 if((DEBUG & DbgDEBUG) && ctlr->command != Cedd)
 1480                         print("Inil%2.2uX/%2.2uX+", ctlr->command, status);
 1481                 return;
 1482         }
 1483 
 1484         if(status & Err)
 1485                 drive->error = inb(cmdport+Error);
 1486         else switch(drive->command){
 1487         default:
 1488                 drive->error = Abrt;
 1489                 break;
 1490 
 1491         case Crs:
 1492         case Crsm:
 1493                 if(!(status & Drq)){
 1494                         drive->error = Abrt;
 1495                         break;
 1496                 }
 1497                 len = drive->block;
 1498                 if(drive->data+len > drive->limit)
 1499                         len = drive->limit-drive->data;
 1500                 inss(cmdport+Data, drive->data, len/2);
 1501                 drive->data += len;
 1502                 if(drive->data >= drive->limit)
 1503                         ctlr->done = 1;
 1504                 break;
 1505 
 1506         case Cws:
 1507         case Cwsm:
 1508                 len = drive->block;
 1509                 if(drive->data+len > drive->limit)
 1510                         len = drive->limit-drive->data;
 1511                 drive->data += len;
 1512                 if(drive->data >= drive->limit){
 1513                         ctlr->done = 1;
 1514                         break;
 1515                 }
 1516                 if(!(status & Drq)){
 1517                         drive->error = Abrt;
 1518                         break;
 1519                 }
 1520                 len = drive->block;
 1521                 if(drive->data+len > drive->limit)
 1522                         len = drive->limit-drive->data;
 1523                 outss(cmdport+Data, drive->data, len/2);
 1524                 break;
 1525 
 1526         case Cpkt:
 1527                 atapktinterrupt(drive);
 1528                 break;
 1529 
 1530         case Crd:
 1531         case Cwd:
 1532                 atadmainterrupt(drive, drive->count*drive->secsize);
 1533                 break;
 1534 
 1535         case Cstandby:
 1536                 ctlr->done = 1;
 1537                 break;
 1538         }
 1539         iunlock(ctlr);
 1540 
 1541         if(drive->error){
 1542                 status |= Err;
 1543                 ctlr->done = 1;
 1544         }
 1545 
 1546         if(ctlr->done){
 1547                 ctlr->curdrive = nil;
 1548                 drive->status = status;
 1549                 wakeup(ctlr);
 1550         }
 1551 }
 1552 
 1553 #ifdef notdef
 1554 static SDev*
 1555 atapnp(void)
 1556 {
 1557         int     cmdport;
 1558         int     ctlport;
 1559         int     irq;
 1560 
 1561         cmdport = 0x200;
 1562         ctlport = cmdport + 0x0C;
 1563         irq = 10;
 1564         return ataprobe(cmdport, ctlport, irq);
 1565 }
 1566 #endif
 1567 
 1568 
 1569 static SDev*
 1570 atalegacy(int port, int irq)
 1571 {
 1572         return ataprobe(port, port+0x204, irq);
 1573 }
 1574 
 1575 static int ataitype;
 1576 static int atairq;
 1577 static int
 1578 ataenable(SDev* sdev)
 1579 {
 1580         Ctlr *ctlr;
 1581         char name[KNAMELEN];
 1582 
 1583         ctlr = sdev->ctlr;
 1584 
 1585         if(ctlr->bmiba){
 1586                 ctlr->prdt = xspanalloc(Nprd*sizeof(Prd), 4, 4*1024);
 1587         }
 1588         snprint(name, KNAMELEN, "%s (%s)", sdev->name, sdev->ifc->name);
 1589 //      intrenable(ctlr->irq, atainterrupt, ctlr, ctlr->tbdf, name);
 1590         outb(ctlr->ctlport+Dc, 0);
 1591         intrenable(ataitype, atairq, atainterrupt, ctlr, name);
 1592         if(ctlr->ienable)
 1593                 ctlr->ienable(ctlr);
 1594 
 1595         return 1;
 1596 }
 1597 
 1598 static int
 1599 atarctl(SDunit* unit, char* p, int l)
 1600 {
 1601         int n;
 1602         Ctlr *ctlr;
 1603         Drive *drive;
 1604 
 1605         if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil)
 1606                 return 0;
 1607         drive = ctlr->drive[unit->subno];
 1608 
 1609         qlock(drive);
 1610         n = snprint(p, l, "config %4.4uX capabilities %4.4uX",
 1611                 drive->info[Iconfig], drive->info[Icapabilities]);
 1612         if(drive->dma)
 1613                 n += snprint(p+n, l-n, " dma %8.8uX dmactl %8.8uX",
 1614                         drive->dma, drive->dmactl);
 1615         if(drive->rwm)
 1616                 n += snprint(p+n, l-n, " rwm %ud rwmctl %ud",
 1617                         drive->rwm, drive->rwmctl);
 1618         n += snprint(p+n, l-n, "\n");
 1619         if(unit->sectors){
 1620                 n += snprint(p+n, l-n, "geometry %llud %ld",
 1621                         unit->sectors, unit->secsize);
 1622                 if(drive->pkt == 0)
 1623                         n += snprint(p+n, l-n, " %d %d %d",
 1624                                 drive->c, drive->h, drive->s);
 1625                 n += snprint(p+n, l-n, "\n");
 1626         }
 1627         qunlock(drive);
 1628 
 1629         return n;
 1630 }
 1631 
 1632 static int
 1633 atawctl(SDunit* unit, Cmdbuf* cb)
 1634 {
 1635         int period;
 1636         Ctlr *ctlr;
 1637         Drive *drive;
 1638 
 1639         if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil)
 1640                 return 0;
 1641         drive = ctlr->drive[unit->subno];
 1642 
 1643         qlock(drive);
 1644         if(waserror()){
 1645                 qunlock(drive);
 1646                 nexterror();
 1647         }
 1648 
 1649         /*
 1650          * Dma and rwm control is passive at the moment,
 1651          * i.e. it is assumed that the hardware is set up
 1652          * correctly already either by the BIOS or when
 1653          * the drive was initially identified.
 1654          */
 1655         if(strcmp(cb->f[0], "dma") == 0){
 1656                 if(cb->nf != 2 || drive->dma == 0)
 1657                         error(Ebadctl);
 1658                 if(strcmp(cb->f[1], "on") == 0)
 1659                         drive->dmactl = drive->dma;
 1660                 else if(strcmp(cb->f[1], "off") == 0)
 1661                         drive->dmactl = 0;
 1662                 else
 1663                         error(Ebadctl);
 1664         }
 1665         else if(strcmp(cb->f[0], "rwm") == 0){
 1666                 if(cb->nf != 2 || drive->rwm == 0)
 1667                         error(Ebadctl);
 1668                 if(strcmp(cb->f[1], "on") == 0)
 1669                         drive->rwmctl = drive->rwm;
 1670                 else if(strcmp(cb->f[1], "off") == 0)
 1671                         drive->rwmctl = 0;
 1672                 else
 1673                         error(Ebadctl);
 1674         }
 1675         else if(strcmp(cb->f[0], "standby") == 0){
 1676                 switch(cb->nf){
 1677                 default:
 1678                         error(Ebadctl);
 1679                 case 2:
 1680                         period = strtol(cb->f[1], 0, 0);
 1681                         if(period && (period < 30 || period > 240*5))
 1682                                 error(Ebadctl);
 1683                         period /= 5;
 1684                         break;
 1685                 }
 1686                 if(atastandby(drive, period) != SDok)
 1687                         error(Ebadctl);
 1688         }
 1689         else
 1690                 error(Ebadctl);
 1691         qunlock(drive);
 1692         poperror();
 1693 
 1694         return 0;
 1695 }
 1696 
 1697 static int
 1698 scsitest(SDreq* r)
 1699 {
 1700         r->write = 0;
 1701         memset(r->cmd, 0, sizeof(r->cmd));
 1702         r->cmd[1] = r->lun<<5;
 1703         r->clen = 6;
 1704         r->data = nil;
 1705         r->dlen = 0;
 1706         r->flags = 0;
 1707 
 1708         r->status = ~0;
 1709 
 1710         return r->unit->dev->ifc->rio(r);
 1711 }
 1712 
 1713 static int
 1714 scsirio(SDreq* r)
 1715 {
 1716         /*
 1717          * Perform an I/O request, returning
 1718          *      -1      failure
 1719          *       0      ok
 1720          *       1      no medium present
 1721          *       2      retry
 1722          * The contents of r may be altered so the
 1723          * caller should re-initialise if necesary.
 1724          */
 1725         r->status = ~0;
 1726         switch(r->unit->dev->ifc->rio(r)){
 1727         default:
 1728                 break;
 1729         case SDcheck:
 1730                 if(!(r->flags & SDvalidsense))
 1731                         break;
 1732                 switch(r->sense[2] & 0x0F){
 1733                 case 0x00:              /* no sense */
 1734                 case 0x01:              /* recovered error */
 1735                         return 2;
 1736                 case 0x06:              /* check condition */
 1737                         /*
 1738                          * 0x28 - not ready to ready transition,
 1739                          *        medium may have changed.
 1740                          * 0x29 - power on or some type of reset.
 1741                          */
 1742                         if(r->sense[12] == 0x28 && r->sense[13] == 0)
 1743                                 return 2;
 1744                         if(r->sense[12] == 0x29)
 1745                                 return 2;
 1746                         break;
 1747                 case 0x02:              /* not ready */
 1748                         /*
 1749                          * If no medium present, bail out.
 1750                          * If unit is becoming ready, rather than not
 1751                          * not ready, wait a little then poke it again.                                  */
 1752                         if(r->sense[12] == 0x3A)
 1753                                 break;
 1754                         if(r->sense[12] != 0x04 || r->sense[13] != 0x01)
 1755                                 break;
 1756 
 1757                         while(waserror())
 1758                                 ;
 1759                         tsleep(&up->sleep, return0, 0, 500);
 1760                         poperror();
 1761                         scsitest(r);
 1762                         return 2;
 1763                 default:
 1764                         break;
 1765                 }
 1766                 break;
 1767         case SDok:
 1768                 return 0;
 1769         }
 1770         return -1;
 1771 }
 1772 
 1773 
 1774 static int
 1775 ataverify(SDunit* unit)
 1776 {
 1777         SDreq *r;
 1778         int i, status;
 1779         uchar *inquiry;
 1780 
 1781         if((r = malloc(sizeof(SDreq))) == nil)
 1782                 return 0;
 1783         if((inquiry = sdmalloc(sizeof(unit->inquiry))) == nil){
 1784                 free(r);
 1785                 return 0;
 1786         }
 1787         r->unit = unit;
 1788         r->lun = 0;             /* ??? */
 1789 
 1790         memset(unit->inquiry, 0, sizeof(unit->inquiry));
 1791         r->write = 0;
 1792         r->cmd[0] = 0x12;
 1793         r->cmd[1] = r->lun<<5;
 1794         r->cmd[4] = sizeof(unit->inquiry)-1;
 1795         r->clen = 6;
 1796         r->data = inquiry;
 1797         r->dlen = sizeof(unit->inquiry)-1;
 1798         r->flags = 0;
 1799 
 1800         r->status = ~0;
 1801         if(unit->dev->ifc->rio(r) != SDok){
 1802                 free(r);
 1803                 return 0;
 1804         }
 1805         memmove(unit->inquiry, inquiry, r->dlen);
 1806         free(inquiry); 
 1807 
 1808         SET(status);
 1809         for(i = 0; i < 3; i++){
 1810                 while((status = scsitest(r)) == SDbusy)
 1811                         ;
 1812                 if(status == SDok || status != SDcheck)
 1813                         break;
 1814                 if(!(r->flags & SDvalidsense))
 1815                         break;
 1816                 if((r->sense[2] & 0x0F) != 0x02)
 1817                         continue;
 1818                 /*
 1819                  * Unit is 'not ready'.
 1820                  * If it needs an initialising command, set status
 1821                  * so it will be spun-up below.
 1822                  * If there's no medium, that's OK too, but don't
 1823                  * try to spin it up.
 1824                  */
 1825                 if(r->sense[12] == 0x04 && r->sense[13] == 0x02){
 1826                         status = SDok;
 1827                         break;
 1828                 }
 1829                 if(r->sense[12] == 0x3A)
 1830                         break;
 1831         }
 1832 
 1833         if(status == SDok){
 1834                 /*
 1835                  * Try to ensure a direct-access device is spinning.
 1836                  * Don't wait for completion, ignore the result.
 1837                  */
 1838                 if((unit->inquiry[0] & 0x1F) == 0){
 1839                         memset(r->cmd, 0, sizeof(r->cmd));
 1840                         r->write = 0;
 1841                         r->cmd[0] = 0x1B;
 1842                         r->cmd[1] = (r->lun<<5)|0x01;
 1843                         r->cmd[4] = 1;
 1844                         r->clen = 6;
 1845                         r->data = nil;
 1846                         r->dlen = 0;
 1847                         r->flags = 0;
 1848 
 1849                         r->status = ~0;
 1850                         unit->dev->ifc->rio(r);
 1851                 }
 1852         }
 1853         free(r);
 1854 
 1855         if(status == SDok || status == SDcheck)
 1856                 return 1;
 1857         return 0;
 1858 }
 1859 
 1860 static int
 1861 ataonline(SDunit* unit)
 1862 {
 1863         SDreq *r;
 1864         uchar *p;
 1865         int ok, retries;
 1866 
 1867         if((r = malloc(sizeof(SDreq))) == nil)
 1868                 return 0;
 1869         if((p = sdmalloc(8)) == nil){
 1870                 free(r);
 1871                 return 0;
 1872         }
 1873 
 1874         ok = 0;
 1875 
 1876         r->unit = unit;
 1877         r->lun = 0;                             /* ??? */
 1878         for(retries = 0; retries < 10; retries++){
 1879                 /*
 1880                  * Read-capacity is mandatory for DA, WORM, CD-ROM and
 1881                  * MO. It may return 'not ready' if type DA is not
 1882                  * spun up, type MO or type CD-ROM are not loaded or just
 1883                  * plain slow getting their act together after a reset.
 1884                  */
 1885                 r->write = 0;
 1886                 memset(r->cmd, 0, sizeof(r->cmd));
 1887                 r->cmd[0] = 0x25;
 1888                 r->cmd[1] = r->lun<<5;
 1889                 r->clen = 10;
 1890                 r->data = p;
 1891                 r->dlen = 8;
 1892                 r->flags = 0;
 1893         
 1894                 r->status = ~0;
 1895                 switch(scsirio(r)){
 1896                 default:
 1897                         break;
 1898                 case 0:
 1899                         unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
 1900                         /*
 1901                          * Read-capacity returns the LBA of the last sector,
 1902                          * therefore the number of sectors must be incremented.
 1903                          */
 1904                         unit->sectors++;
 1905                         unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];
 1906 
 1907                         /*
 1908                          * Some ATAPI CD readers lie about the block size.
 1909                          * Since we don't read audio via this interface
 1910                          * it's okay to always fudge this.
 1911                          */
 1912                         if(unit->secsize == 2352)
 1913                                 unit->secsize = 2048;
 1914                         ok = 1;
 1915                         break;
 1916                 case 1:
 1917                         ok = 1;
 1918                         break;
 1919                 case 2:
 1920                         continue;
 1921                 }
 1922                 break;
 1923         }
 1924         free(p);
 1925         free(r);
 1926 
 1927         if(ok)
 1928                 return ok+retries;
 1929         else
 1930                 return 0;
 1931 }
 1932 
 1933 static long
 1934 atabio(SDunit* unit, int lun, int write, void* data, long nb, uvlong bno)
 1935 {
 1936         SDreq *r;
 1937         long rlen;
 1938 
 1939         if((r = malloc(sizeof(SDreq))) == nil)
 1940                 error(Enomem);
 1941         r->unit = unit;
 1942         r->lun = lun;
 1943 again:
 1944         r->write = write;
 1945         if(write == 0)
 1946                 r->cmd[0] = 0x28;
 1947         else
 1948                 r->cmd[0] = 0x2A;
 1949         r->cmd[1] = (lun<<5);
 1950         r->cmd[2] = bno>>24;
 1951         r->cmd[3] = bno>>16;
 1952         r->cmd[4] = bno>>8;
 1953         r->cmd[5] = bno;
 1954         r->cmd[6] = 0;
 1955         r->cmd[7] = nb>>8;
 1956         r->cmd[8] = nb;
 1957         r->cmd[9] = 0;
 1958         r->clen = 10;
 1959         r->data = data;
 1960         r->dlen = nb*unit->secsize;
 1961         r->flags = 0;
 1962 
 1963         r->status = ~0;
 1964         switch(scsirio(r)){
 1965         default:
 1966                 rlen = -1;
 1967                 break;
 1968         case 0:
 1969                 rlen = r->rlen;
 1970                 break;
 1971         case 2:
 1972                 rlen = -1;
 1973                 if(!(r->flags & SDvalidsense))
 1974                         break;
 1975                 switch(r->sense[2] & 0x0F){
 1976                 default:
 1977                         break;
 1978                 case 0x06:              /* check condition */
 1979                         /*
 1980                          * Check for a removeable media change.
 1981                          * If so, mark it by zapping the geometry info
 1982                          * to force an online request.
 1983                          */
 1984                         if(r->sense[12] != 0x28 || r->sense[13] != 0)
 1985                                 break;
 1986                         if(unit->inquiry[1] & 0x80)
 1987                                 unit->sectors = 0;
 1988                         break;
 1989                 case 0x02:              /* not ready */
 1990                         /*
 1991                          * If unit is becoming ready,
 1992                          * rather than not not ready, try again.
 1993                          */
 1994                         if(r->sense[12] == 0x04 && r->sense[13] == 0x01)
 1995                                 goto again;
 1996                         break;
 1997                 }
 1998                 break;
 1999         }
 2000         free(r);
 2001 
 2002         return rlen;
 2003 }
 2004 
 2005 
 2006 struct Try {
 2007         int p;
 2008         int c;
 2009 } tries[] = {
 2010                    { 0, 0x0c },
 2011                    { 0, 0 }, 
 2012 };
 2013 
 2014 static SDev*
 2015 ataprobew(DevConf *cf)
 2016 {
 2017         int     cmdport;
 2018         int     ctlport;
 2019         int     irq;
 2020         SDev*   rc;
 2021         struct Try *try;
 2022 
 2023         rc = nil;
 2024         for (try = &tries[0]; try->p != 0 || try->c != 0; try++){
 2025                 ataitype = cf->itype;
 2026                 atairq  = cf->intnum;
 2027                 cmdport = cf->ports[0].port + try->p;
 2028                 ctlport = cmdport + try->c;
 2029                 irq = cf->intnum;
 2030                 rc = ataprobe(cmdport, ctlport, irq);
 2031                 if (rc)
 2032                         break;
 2033         }
 2034         return rc;
 2035 }
 2036 
 2037 static void
 2038 ataclear(SDev *sdev)
 2039 {
 2040         Ctlr* ctlr;
 2041 
 2042         ctlr = sdev->ctlr;
 2043 
 2044         if (ctlr->drive[0])
 2045                 free(ctlr->drive[0]);
 2046         if (ctlr->drive[1])
 2047                 free(ctlr->drive[1]);
 2048         if (sdev->name)
 2049                 free(sdev->name);
 2050         if (sdev->unitflg)
 2051                 free(sdev->unitflg);
 2052         if (sdev->unit)
 2053                 free(sdev->unit);
 2054         free(ctlr);
 2055         free(sdev);
 2056 }
 2057 
 2058 static char *
 2059 atastat(SDev *sdev, char *p, char *e)
 2060 {
 2061         Ctlr *ctlr = sdev->ctlr;
 2062 
 2063         return seprint(p, e, "%s ata port %X ctl %X irq %d\n", 
 2064                                sdev->name, ctlr->cmdport, ctlr->ctlport, ctlr->irq);
 2065 }
 2066 
 2067 
 2068 SDifc sdataifc = {
 2069         "ata",                          /* name */
 2070 
 2071         nil,                            /* pnp */
 2072         atalegacy,                      /* legacy */
 2073         ataenable,                      /* enable */
 2074         nil,                            /* disable */
 2075 
 2076         ataverify,                      /* verify */
 2077         ataonline,                      /* online */
 2078         atario,                         /* rio */
 2079         atarctl,                        /* rctl */
 2080         atawctl,                        /* wctl */
 2081 
 2082         atabio,                         /* bio */
 2083         ataprobew,                      /* probew */
 2084         ataclear,                       /* clear */
 2085         atastat,                        /* stat */
 2086 };
 2087 

Cache object: 4e2bebee5fecc705ec58d24e03e00ea6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.