]> git.lizzy.rs Git - plan9front.git/blob - sys/src/boot/pc/sdata.c
perms
[plan9front.git] / sys / src / boot / pc / sdata.c
1 #include "u.h"
2 #include "lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "ureg.h"
8 #include "error.h"
9
10 #include "sd.h"
11
12 extern SDifc sdataifc;
13
14 enum {
15         DbgCONFIG       = 0x0001,       /* detected drive config info */
16         DbgIDENTIFY     = 0x0002,       /* detected drive identify info */
17         DbgSTATE        = 0x0004,       /* dump state on panic */
18         DbgPROBE        = 0x0008,       /* trace device probing */
19         DbgDEBUG        = 0x0080,       /* the current problem... */
20         DbgINL          = 0x0100,       /* That Inil20+ message we hate */
21         Dbg48BIT        = 0x0200,       /* 48-bit LBA */
22         DbgBsy          = 0x0400,       /* interrupt but Bsy (shared IRQ) */
23 };
24 #define DEBUG           (DbgDEBUG|DbgCONFIG)
25
26 enum {                                  /* I/O ports */
27         Data            = 0,
28         Error           = 1,            /* (read) */
29         Features        = 1,            /* (write) */
30         Count           = 2,            /* sector count<7-0>, sector count<15-8> */
31         Ir              = 2,            /* interrupt reason (PACKET) */
32         Sector          = 3,            /* sector number */
33         Lbalo           = 3,            /* LBA<7-0>, LBA<31-24> */
34         Cyllo           = 4,            /* cylinder low */
35         Bytelo          = 4,            /* byte count low (PACKET) */
36         Lbamid          = 4,            /* LBA<15-8>, LBA<39-32> */
37         Cylhi           = 5,            /* cylinder high */
38         Bytehi          = 5,            /* byte count hi (PACKET) */
39         Lbahi           = 5,            /* LBA<23-16>, LBA<47-40> */
40         Dh              = 6,            /* Device/Head, LBA<32-14> */
41         Status          = 7,            /* (read) */
42         Command         = 7,            /* (write) */
43
44         As              = 2,            /* Alternate Status (read) */
45         Dc              = 2,            /* Device Control (write) */
46 };
47
48 enum {                                  /* Error */
49         Med             = 0x01,         /* Media error */
50         Ili             = 0x01,         /* command set specific (PACKET) */
51         Nm              = 0x02,         /* No Media */
52         Eom             = 0x02,         /* command set specific (PACKET) */
53         Abrt            = 0x04,         /* Aborted command */
54         Mcr             = 0x08,         /* Media Change Request */
55         Idnf            = 0x10,         /* no user-accessible address */
56         Mc              = 0x20,         /* Media Change */
57         Unc             = 0x40,         /* Uncorrectable data error */
58         Wp              = 0x40,         /* Write Protect */
59         Icrc            = 0x80,         /* Interface CRC error */
60 };
61
62 enum {                                  /* Features */
63         Dma             = 0x01,         /* data transfer via DMA (PACKET) */
64         Ovl             = 0x02,         /* command overlapped (PACKET) */
65 };
66
67 enum {                                  /* Interrupt Reason */
68         Cd              = 0x01,         /* Command/Data */
69         Io              = 0x02,         /* I/O direction */
70         Rel             = 0x04,         /* Bus Release */
71 };
72
73 enum {                                  /* Device/Head */
74         Dev0            = 0xA0,         /* Master */
75         Dev1            = 0xB0,         /* Slave */
76         Lba             = 0x40,         /* LBA mode */
77 };
78
79 enum {                                  /* Status, Alternate Status */
80         Err             = 0x01,         /* Error */
81         Chk             = 0x01,         /* Check error (PACKET) */
82         Drq             = 0x08,         /* Data Request */
83         Dsc             = 0x10,         /* Device Seek Complete */
84         Serv            = 0x10,         /* Service */
85         Df              = 0x20,         /* Device Fault */
86         Dmrd            = 0x20,         /* DMA ready (PACKET) */
87         Drdy            = 0x40,         /* Device Ready */
88         Bsy             = 0x80,         /* Busy */
89 };
90
91 enum {                                  /* Command */
92         Cnop            = 0x00,         /* NOP */
93         Cdr             = 0x08,         /* Device Reset */
94         Crs             = 0x20,         /* Read Sectors */
95         Crs48           = 0x24,         /* Read Sectors Ext */
96         Crd48           = 0x25,         /* Read w/ DMA Ext */
97         Crdq48          = 0x26,         /* Read w/ DMA Queued Ext */
98         Crsm48          = 0x29,         /* Read Multiple Ext */
99         Cws             = 0x30,         /* Write Sectors */
100         Cws48           = 0x34,         /* Write Sectors Ext */
101         Cwd48           = 0x35,         /* Write w/ DMA Ext */
102         Cwdq48          = 0x36,         /* Write w/ DMA Queued Ext */
103         Cwsm48          = 0x39,         /* Write Multiple Ext */
104         Cedd            = 0x90,         /* Execute Device Diagnostics */
105         Cpkt            = 0xA0,         /* Packet */
106         Cidpkt          = 0xA1,         /* Identify Packet Device */
107         Crsm            = 0xC4,         /* Read Multiple */
108         Cwsm            = 0xC5,         /* Write Multiple */
109         Csm             = 0xC6,         /* Set Multiple */
110         Crdq            = 0xC7,         /* Read DMA queued */
111         Crd             = 0xC8,         /* Read DMA */
112         Cwd             = 0xCA,         /* Write DMA */
113         Cwdq            = 0xCC,         /* Write DMA queued */
114         Cstandby        = 0xE2,         /* Standby */
115         Cid             = 0xEC,         /* Identify Device */
116         Csf             = 0xEF,         /* Set Features */
117 };
118
119 enum {                                  /* Device Control */
120         Nien            = 0x02,         /* (not) Interrupt Enable */
121         Srst            = 0x04,         /* Software Reset */
122 };
123
124 enum {                                  /* PCI Configuration Registers */
125         Bmiba           = 0x20,         /* Bus Master Interface Base Address */
126         Idetim          = 0x40,         /* IE Timing */
127         Sidetim         = 0x44,         /* Slave IE Timing */
128         Udmactl         = 0x48,         /* Ultra DMA/33 Control */
129         Udmatim         = 0x4A,         /* Ultra DMA/33 Timing */
130 };
131
132 enum {                                  /* Bus Master IDE I/O Ports */
133         Bmicx           = 0,            /* Command */
134         Bmisx           = 2,            /* Status */
135         Bmidtpx         = 4,            /* Descriptor Table Pointer */
136 };
137
138 enum {                                  /* Bmicx */
139         Ssbm            = 0x01,         /* Start/Stop Bus Master */
140         Rwcon           = 0x08,         /* Read/Write Control */
141 };
142
143 enum {                                  /* Bmisx */
144         Bmidea          = 0x01,         /* Bus Master IDE Active */
145         Idedmae         = 0x02,         /* IDE DMA Error  (R/WC) */
146         Ideints         = 0x04,         /* IDE Interrupt Status (R/WC) */
147         Dma0cap         = 0x20,         /* Drive 0 DMA Capable */
148         Dma1cap         = 0x40,         /* Drive 0 DMA Capable */
149 };
150 enum {                                  /* Physical Region Descriptor */
151         PrdEOT          = 0x80000000,   /* Bus Master IDE Active */
152 };
153
154 enum {                                  /* offsets into the identify info. */
155         Iconfig         = 0,            /* general configuration */
156         Ilcyl           = 1,            /* logical cylinders */
157         Ilhead          = 3,            /* logical heads */
158         Ilsec           = 6,            /* logical sectors per logical track */
159         Iserial         = 10,           /* serial number */
160         Ifirmware       = 23,           /* firmware revision */
161         Imodel          = 27,           /* model number */
162         Imaxrwm         = 47,           /* max. read/write multiple sectors */
163         Icapabilities   = 49,           /* capabilities */
164         Istandby        = 50,           /* device specific standby timer */
165         Ipiomode        = 51,           /* PIO data transfer mode number */
166         Ivalid          = 53,
167         Iccyl           = 54,           /* cylinders if (valid&0x01) */
168         Ichead          = 55,           /* heads if (valid&0x01) */
169         Icsec           = 56,           /* sectors if (valid&0x01) */
170         Iccap           = 57,           /* capacity if (valid&0x01) */
171         Irwm            = 59,           /* read/write multiple */
172         Ilba            = 60,           /* LBA size */
173         Imwdma          = 63,           /* multiword DMA mode */
174         Iapiomode       = 64,           /* advanced PIO modes supported */
175         Iminmwdma       = 65,           /* min. multiword DMA cycle time */
176         Irecmwdma       = 66,           /* rec. multiword DMA cycle time */
177         Iminpio         = 67,           /* min. PIO cycle w/o flow control */
178         Iminiordy       = 68,           /* min. PIO cycle with IORDY */
179         Ipcktbr         = 71,           /* time from PACKET to bus release */
180         Iserbsy         = 72,           /* time from SERVICE to !Bsy */
181         Iqdepth         = 75,           /* max. queue depth */
182         Imajor          = 80,           /* major version number */
183         Iminor          = 81,           /* minor version number */
184         Icsfs           = 82,           /* command set/feature supported */
185         Icsfe           = 85,           /* command set/feature enabled */
186         Iudma           = 88,           /* ultra DMA mode */
187         Ierase          = 89,           /* time for security erase */
188         Ieerase         = 90,           /* time for enhanced security erase */
189         Ipower          = 91,           /* current advanced power management */
190         Ilba48          = 100,          /* 48-bit LBA size (64 bits in 100-103) */
191         Irmsn           = 127,          /* removable status notification */
192         Isecstat        = 128,          /* security status */
193 };
194
195 typedef struct Ctlr Ctlr;
196 typedef struct Drive Drive;
197
198 typedef struct Prd {
199         ulong   pa;                     /* Physical Base Address */
200         int     count;
201 } Prd;
202
203 enum {
204         Nprd            = SDmaxio/(64*1024)+2,
205 };
206
207 typedef struct Ctlr {
208         int     cmdport;
209         int     ctlport;
210         int     irq;
211         int     tbdf;
212
213         Pcidev* pcidev;
214         void    (*ienable)(Ctlr*);
215         SDev*   sdev;
216
217         Drive*  drive[2];
218
219         Prd*    prdt;                   /* physical region descriptor table */
220
221 //      QLock;                          /* current command */
222         Drive*  curdrive;
223         int     command;                /* last command issued (debugging) */
224 //      Rendez;
225         int     done;
226
227         Lock;                           /* register access */
228 } Ctlr;
229
230 typedef struct Drive {
231         Ctlr*   ctlr;
232
233         int     dev;
234         ushort  info[256];
235         int     c;                      /* cylinder */
236         int     h;                      /* head */
237         int     s;                      /* sector */
238         vlong   sectors;                /* total */
239         int     secsize;                /* sector size */
240
241 //      int     dma;                    /* DMA R/W possible */
242 //      int     dmactl;
243 //      int     rwm;                    /* read/write multiple possible */
244 //      int     rwmctl;
245
246         int     pkt;                    /* PACKET device, length of pktcmd */
247         uchar   pktcmd[16];
248 //      int     pktdma;                 /* this PACKET command using dma */
249
250         uchar   sense[18];
251         uchar   inquiry[48];
252
253 //      QLock;                          /* drive access */
254         int     command;                /* current command */
255         int     write;
256         uchar*  data;
257         int     dlen;
258         uchar*  limit;
259         int     count;                  /* sectors */
260         int     block;                  /* R/W bytes per block */
261         int     status;
262         int     error;
263         int     flags;                  /* internal flags */
264 } Drive;
265
266 enum {                                  /* internal flags */
267         Lba48           = 0x1,          /* LBA48 mode */
268         Lba48always     = 0x2,          /* ... */
269 };
270
271 static void
272 pc87415ienable(Ctlr* ctlr)
273 {
274         Pcidev *p;
275         int x;
276
277         p = ctlr->pcidev;
278         if(p == nil)
279                 return;
280
281         x = pcicfgr32(p, 0x40);
282         if(ctlr->cmdport == p->mem[0].bar)
283                 x &= ~0x00000100;
284         else
285                 x &= ~0x00000200;
286         pcicfgw32(p, 0x40, x);
287 }
288
289 static int
290 atadebug(int cmdport, int ctlport, char* fmt, ...)
291 {
292         int i, n;
293         va_list arg;
294         char buf[PRINTSIZE];
295
296         if(!(DEBUG & DbgPROBE)){
297                 USED(cmdport, ctlport, fmt);
298                 return 0;
299         }
300
301         va_start(arg, fmt);
302         n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
303         va_end(arg);
304
305         if(cmdport){
306                 if(buf[n-1] == '\n')
307                         n--;
308                 n += snprint(buf+n, PRINTSIZE-n, " ataregs 0x%uX:",
309                         cmdport);
310                 for(i = Features; i < Command; i++)
311                         n += snprint(buf+n, PRINTSIZE-n, " 0x%2.2uX",
312                                 inb(cmdport+i));
313                 if(ctlport)
314                         n += snprint(buf+n, PRINTSIZE-n, " 0x%2.2uX",
315                                 inb(ctlport+As));
316                 n += snprint(buf+n, PRINTSIZE-n, "\n");
317         }
318         putstrn(buf, n);
319
320         return n;
321 }
322
323 static int
324 ataready(int cmdport, int ctlport, int dev, int reset, int ready, int micro)
325 {
326         int as;
327
328         atadebug(cmdport, ctlport, "ataready: dev %uX reset %uX ready %uX",
329                 dev, reset, ready);
330
331         for(;;){
332                 /*
333                  * Wait for the controller to become not busy and
334                  * possibly for a status bit to become true (usually
335                  * Drdy). Must change to the appropriate device
336                  * register set if necessary before testing for ready.
337                  * Always run through the loop at least once so it
338                  * can be used as a test for !Bsy.
339                  */
340                 as = inb(ctlport+As);
341                 if(as & reset){
342                         /* nothing to do */;
343                 }
344                 else if(dev){
345                         outb(cmdport+Dh, dev);
346                         dev = 0;
347                 }
348                 else if(ready == 0 || (as & ready)){
349                         atadebug(0, 0, "ataready: %d 0x%2.2uX\n", micro, as);
350                         return as;
351                 }
352
353                 if(micro-- <= 0){
354                         atadebug(0, 0, "ataready: %d 0x%2.2uX\n", micro, as);
355                         break;
356                 }
357                 microdelay(1);
358         }
359         atadebug(cmdport, ctlport, "ataready: timeout");
360
361         return -1;
362 }
363
364 static int
365 atacsfenabled(Drive* drive, vlong csf)
366 {
367         int cmdset, i, x;
368
369         for(i = 0; i < 3; i++){
370                 x = (csf>>(16*i)) & 0xFFFF;
371                 if(x == 0)
372                         continue;
373                 cmdset = drive->info[Icsfe+i];
374                 if(cmdset == 0 || cmdset == 0xFFFF)
375                         return 0;
376                 return cmdset & x;
377         }
378
379         return 0;
380 }
381
382 /*
383 static int
384 atasf(int cmdport, int ctlport, int dev, uchar* command)
385 {
386         int as, i;
387
388         if(ataready(cmdport, ctlport, dev, Bsy|Drq, Drdy, 108*1000) < 0)
389                 return -1;
390
391         for(i = Features; i < Dh; i++)
392                 outb(cmdport+i, command[i]);
393         outb(cmdport+Command, Csf);
394         microdelay(100);
395         as = ataready(cmdport, ctlport, 0, Bsy, Drdy|Df|Err, 109*1000);
396         if(as < 0 || (as & (Df|Err)))
397                 return -1;
398         return 0;
399 }
400  */
401
402 static int
403 ataidentify(int cmdport, int ctlport, int dev, int pkt, void* info)
404 {
405         int as, command, drdy;
406
407         if(pkt){
408                 command = Cidpkt;
409                 drdy = 0;
410         }
411         else{
412                 command = Cid;
413                 drdy = Drdy;
414         }
415         as = ataready(cmdport, ctlport, dev, Bsy|Drq, drdy, 103*1000);
416         if(as < 0)
417                 return as;
418         outb(cmdport+Command, command);
419         microdelay(1);
420
421         as = ataready(cmdport, ctlport, 0, Bsy, Drq|Err, 400*1000);
422         if(as < 0)
423                 return -1;
424         if(as & Err)
425                 return as;
426
427         memset(info, 0, 512);
428         inss(cmdport+Data, info, 256);
429         inb(cmdport+Status);
430
431         if(DEBUG & DbgIDENTIFY){
432                 int i;
433                 ushort *sp;
434
435                 sp = (ushort*)info;
436                 for(i = 0; i < 256; i++){
437                         if(i && (i%16) == 0)
438                                 print("\n");
439                         print(" %4.4uX ", *sp);
440                         sp++;
441                 }
442                 print("\n");
443         }
444
445         return 0;
446 }
447
448 static Drive*
449 atadrive(int cmdport, int ctlport, int dev)
450 {
451         Drive *drive;
452         int as, i, pkt;
453         uchar buf[512], *p;
454         ushort iconfig, *sp;
455
456         atadebug(0, 0, "identify: port 0x%uX dev 0x%2.2uX\n", cmdport, dev);
457         pkt = 1;
458 retry:
459         as = ataidentify(cmdport, ctlport, dev, pkt, buf);
460         if(as < 0)
461                 return nil;
462         if(as & Err){
463                 if(pkt == 0)
464                         return nil;
465                 pkt = 0;
466                 goto retry;
467         }
468
469         if((drive = malloc(sizeof(Drive))) == nil)
470                 return nil;
471         drive->dev = dev;
472         memmove(drive->info, buf, sizeof(drive->info));
473         drive->sense[0] = 0x70;
474         drive->sense[7] = sizeof(drive->sense)-7;
475
476         drive->inquiry[2] = 2;
477         drive->inquiry[3] = 2;
478         drive->inquiry[4] = sizeof(drive->inquiry)-4;
479         p = &drive->inquiry[8];
480         sp = &drive->info[Imodel];
481         for(i = 0; i < 20; i++){
482                 *p++ = *sp>>8;
483                 *p++ = *sp++;
484         }
485
486         drive->secsize = 512;
487
488         /*
489          * Beware the CompactFlash Association feature set.
490          * Now, why this value in Iconfig just walks all over the bit
491          * definitions used in the other parts of the ATA/ATAPI standards
492          * is a mystery and a sign of true stupidity on someone's part.
493          * Anyway, the standard says if this value is 0x848A then it's
494          * CompactFlash and it's NOT a packet device.
495          */
496         iconfig = drive->info[Iconfig];
497         if(iconfig != 0x848A && (iconfig & 0xC000) == 0x8000){
498                 if(iconfig & 0x01)
499                         drive->pkt = 16;
500                 else
501                         drive->pkt = 12;
502         }
503         else{
504                 if(drive->info[Ivalid] & 0x0001){
505                         drive->c = drive->info[Iccyl];
506                         drive->h = drive->info[Ichead];
507                         drive->s = drive->info[Icsec];
508                 }
509                 else{
510                         drive->c = drive->info[Ilcyl];
511                         drive->h = drive->info[Ilhead];
512                         drive->s = drive->info[Ilsec];
513                 }
514                 if(drive->info[Icapabilities] & 0x0200){
515                         if(drive->info[Icsfs+1] & 0x0400){
516                                 drive->sectors = drive->info[Ilba48]
517                                         |(drive->info[Ilba48+1]<<16)
518                                         |((vlong)drive->info[Ilba48+2]<<32);
519                                 drive->flags |= Lba48;
520                         }
521                         else{
522                                 drive->sectors = (drive->info[Ilba+1]<<16)
523                                          |drive->info[Ilba];
524                         }
525                         drive->dev |= Lba;
526                 }
527                 else
528                         drive->sectors = drive->c*drive->h*drive->s;
529         //      atarwmmode(drive, cmdport, ctlport, dev);
530         }
531 //      atadmamode(drive);      
532
533         if(DEBUG & DbgCONFIG){
534                 print("dev %2.2uX port %uX config %4.4uX capabilities %4.4uX",
535                         dev, cmdport, iconfig, drive->info[Icapabilities]);
536                 print(" mwdma %4.4uX", drive->info[Imwdma]);
537                 if(drive->info[Ivalid] & 0x04)
538                         print(" udma %4.4uX", drive->info[Iudma]);
539 //              print(" dma %8.8uX rwm %ud", drive->dma, drive->rwm);
540                 if(drive->flags&Lba48)
541                         print("\tLLBA sectors %lld", drive->sectors);
542                 print("\n");
543         }
544
545         return drive;
546 }
547
548 static void
549 atasrst(int ctlport)
550 {
551         /*
552          * Srst is a big stick and may cause problems if further
553          * commands are tried before the drives become ready again.
554          * Also, there will be problems here if overlapped commands
555          * are ever supported.
556          */
557         microdelay(5);
558         outb(ctlport+Dc, Srst);
559         microdelay(5);
560         outb(ctlport+Dc, 0);
561         microdelay(2*1000);
562 }
563
564 static SDev*
565 ataprobe(int cmdport, int ctlport, int irq)
566 {
567         Ctlr* ctlr;
568         SDev *sdev;
569         Drive *drive;
570         int dev, error, rhi, rlo;
571
572 //      if(ioalloc(cmdport, 8, 0, "atacmd") < 0)
573 //              return nil;
574 //      if(ioalloc(ctlport+As, 1, 0, "atactl") < 0){
575 //              iofree(cmdport);
576 //              return nil;
577 //      }
578
579         /*
580          * Try to detect a floating bus.
581          * Bsy should be cleared. If not, see if the cylinder registers
582          * are read/write capable.
583          * If the master fails, try the slave to catch slave-only
584          * configurations.
585          * There's no need to restore the tested registers as they will
586          * be reset on any detected drives by the Cedd command.
587          * All this indicates is that there is at least one drive on the
588          * controller; when the non-existent drive is selected in a
589          * single-drive configuration the registers of the existing drive
590          * are often seen, only command execution fails.
591          */
592         dev = Dev0;
593         if(inb(ctlport+As) & Bsy){
594                 outb(cmdport+Dh, dev);
595                 microdelay(1);
596 trydev1:
597                 atadebug(cmdport, ctlport, "ataprobe bsy");
598                 outb(cmdport+Cyllo, 0xAA);
599                 outb(cmdport+Cylhi, 0x55);
600                 outb(cmdport+Sector, 0xFF);
601                 rlo = inb(cmdport+Cyllo);
602                 rhi = inb(cmdport+Cylhi);
603                 if(rlo != 0xAA && (rlo == 0xFF || rhi != 0x55)){
604                         if(dev == Dev1){
605 release:
606                         //      iofree(cmdport);
607                         //      iofree(ctlport+As);
608                                 return nil;
609                         }
610                         dev = Dev1;
611                         if(ataready(cmdport, ctlport, dev, Bsy, 0, 20*1000) < 0)
612                                 goto trydev1;
613                 }
614         }
615
616         /*
617          * Disable interrupts on any detected controllers.
618          */
619         outb(ctlport+Dc, Nien);
620 tryedd1:
621         if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 105*1000) < 0){
622                 /*
623                  * There's something there, but it didn't come up clean,
624                  * so try hitting it with a big stick. The timing here is
625                  * wrong but this is a last-ditch effort and it sometimes
626                  * gets some marginal hardware back online.
627                  */
628                 atasrst(ctlport);
629                 if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 106*1000) < 0)
630                         goto release;
631         }
632
633         /*
634          * Can only get here if controller is not busy.
635          * If there are drives Bsy will be set within 400nS,
636          * must wait 2mS before testing Status.
637          * Wait for the command to complete (6 seconds max).
638          */
639         outb(cmdport+Command, Cedd);
640         delay(2);
641         if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 6*1000*1000) < 0)
642                 goto release;
643
644         /*
645          * If bit 0 of the error register is set then the selected drive
646          * exists. This is enough to detect single-drive configurations.
647          * However, if the master exists there is no way short of executing
648          * a command to determine if a slave is present.
649          * It appears possible to get here testing Dev0 although it doesn't
650          * exist and the EDD won't take, so try again with Dev1.
651          */
652         error = inb(cmdport+Error);
653         atadebug(cmdport, ctlport, "ataprobe: dev %uX", dev);
654         if((error & ~0x80) != 0x01){
655                 if(dev == Dev1)
656                         goto release;
657                 dev = Dev1;
658                 goto tryedd1;
659         }
660
661         /*
662          * At least one drive is known to exist, try to
663          * identify it. If that fails, don't bother checking
664          * any further.
665          * If the one drive found is Dev0 and the EDD command
666          * didn't indicate Dev1 doesn't exist, check for it.
667          */
668         if((drive = atadrive(cmdport, ctlport, dev)) == nil)
669                 goto release;
670         if((ctlr = malloc(sizeof(Ctlr))) == nil){
671                 free(drive);
672                 goto release;
673         }
674         if((sdev = malloc(sizeof(SDev))) == nil){
675                 free(ctlr);
676                 free(drive);
677                 goto release;
678         }
679         drive->ctlr = ctlr;
680         if(dev == Dev0){
681                 ctlr->drive[0] = drive;
682                 if(!(error & 0x80)){
683                         /*
684                          * Always leave Dh pointing to a valid drive,
685                          * otherwise a subsequent call to ataready on
686                          * this controller may try to test a bogus Status.
687                          * Ataprobe is the only place possibly invalid
688                          * drives should be selected.
689                          */
690                         drive = atadrive(cmdport, ctlport, Dev1);
691                         if(drive != nil){
692                                 drive->ctlr = ctlr;
693                                 ctlr->drive[1] = drive;
694                         }
695                         else{
696                                 outb(cmdport+Dh, Dev0);
697                                 microdelay(1);
698                         }
699                 }
700         }
701         else
702                 ctlr->drive[1] = drive;
703
704         ctlr->cmdport = cmdport;
705         ctlr->ctlport = ctlport;
706         ctlr->irq = irq;
707         ctlr->tbdf = BUSUNKNOWN;
708         ctlr->command = Cedd;           /* debugging */
709
710         sdev->ifc = &sdataifc;
711         sdev->ctlr = ctlr;
712         sdev->nunit = 2;
713         ctlr->sdev = sdev;
714
715         return sdev;
716 }
717
718 static int
719 atasetsense(Drive* drive, int status, int key, int asc, int ascq)
720 {
721         drive->sense[2] = key;
722         drive->sense[12] = asc;
723         drive->sense[13] = ascq;
724
725         return status;
726 }
727
728 static int
729 atamodesense(Drive* drive, uchar* cmd)
730 {
731         int len;
732
733         /*
734          * Fake a vendor-specific request with page code 0,
735          * return the drive info.
736          */
737         if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
738                 return atasetsense(drive, SDcheck, 0x05, 0x24, 0);
739         len = (cmd[7]<<8)|cmd[8];
740         if(len == 0)
741                 return SDok;
742         if(len < 8+sizeof(drive->info))
743                 return atasetsense(drive, SDcheck, 0x05, 0x1A, 0);
744         if(drive->data == nil || drive->dlen < len)
745                 return atasetsense(drive, SDcheck, 0x05, 0x20, 1);
746         memset(drive->data, 0, 8);
747         drive->data[0] = sizeof(drive->info)>>8;
748         drive->data[1] = sizeof(drive->info);
749         memmove(drive->data+8, drive->info, sizeof(drive->info));
750         drive->data += 8+sizeof(drive->info);
751
752         return SDok;
753 }
754
755 static void
756 atanop(Drive* drive, int subcommand)
757 {
758         Ctlr* ctlr;
759         int as, cmdport, ctlport, timeo;
760
761         /*
762          * Attempt to abort a command by using NOP.
763          * In response, the drive is supposed to set Abrt
764          * in the Error register, set (Drdy|Err) in Status
765          * and clear Bsy when done. However, some drives
766          * (e.g. ATAPI Zip) just go Bsy then clear Status
767          * when done, hence the timeout loop only on Bsy
768          * and the forced setting of drive->error.
769          */
770         ctlr = drive->ctlr;
771         cmdport = ctlr->cmdport;
772         outb(cmdport+Features, subcommand);
773         outb(cmdport+Dh, drive->dev);
774         ctlr->command = Cnop;           /* debugging */
775         outb(cmdport+Command, Cnop);
776
777         microdelay(1);
778         ctlport = ctlr->ctlport;
779         for(timeo = 0; timeo < 1000; timeo++){
780                 as = inb(ctlport+As);
781                 if(!(as & Bsy))
782                         break;
783                 microdelay(1);
784         }
785         drive->error |= Abrt;
786 }
787
788 static void
789 ataabort(Drive* drive, int dolock)
790 {
791         /*
792          * If NOP is available (packet commands) use it otherwise
793          * must try a software reset.
794          */
795         if(dolock)
796                 ilock(drive->ctlr);
797         if(atacsfenabled(drive, 0x0000000000004000LL))
798                 atanop(drive, 0);
799         else{
800                 atasrst(drive->ctlr->ctlport);
801                 drive->error |= Abrt;
802         }
803         if(dolock)
804                 iunlock(drive->ctlr);
805 }
806
807 static int
808 atapktiodone(void* arg)
809 {
810         return ((Ctlr*)arg)->done;
811 }
812
813 static void
814 atapktinterrupt(Drive* drive)
815 {
816         Ctlr* ctlr;
817         int cmdport, len;
818
819         ctlr = drive->ctlr;
820         cmdport = ctlr->cmdport;
821         switch(inb(cmdport+Ir) & (/*Rel|*/Io|Cd)){
822         case Cd:
823                 outss(cmdport+Data, drive->pktcmd, drive->pkt/2);
824                 break;
825
826         case 0:
827                 len = (inb(cmdport+Bytehi)<<8)|inb(cmdport+Bytelo);
828                 if(drive->data+len > drive->limit){
829                         atanop(drive, 0);
830                         break;
831                 }
832                 outss(cmdport+Data, drive->data, len/2);
833                 drive->data += len;
834                 break;
835
836         case Io:
837                 len = (inb(cmdport+Bytehi)<<8)|inb(cmdport+Bytelo);
838                 if(drive->data+len > drive->limit){
839                         atanop(drive, 0);
840                         break;
841                 }
842                 inss(cmdport+Data, drive->data, len/2);
843                 drive->data += len;
844                 break;
845
846         case Io|Cd:
847         //      if(drive->pktdma)
848         //              atadmainterrupt(drive, drive->dlen);
849         //      else
850                         ctlr->done = 1;
851                 break;
852         }
853 }
854
855 static int
856 atapktio(Drive* drive, uchar* cmd, int clen)
857 {
858         Ctlr *ctlr;
859         int as, cmdport, ctlport, len, r;
860
861         if(cmd[0] == 0x5A && (cmd[2] & 0x3F) == 0)
862                 return atamodesense(drive, cmd);
863
864         r = SDok;
865
866         drive->command = Cpkt;
867         memmove(drive->pktcmd, cmd, clen);
868         memset(drive->pktcmd+clen, 0, drive->pkt-clen);
869         drive->limit = drive->data+drive->dlen;
870
871         ctlr = drive->ctlr;
872         cmdport = ctlr->cmdport;
873         ctlport = ctlr->ctlport;
874
875         qlock(ctlr);
876
877         as = ataready(cmdport, ctlport, drive->dev, Bsy|Drq, Drdy, 107*1000);
878         if(as < 0 || (as&Chk)){
879                 qunlock(ctlr);
880                 return -1;
881         }
882
883         ilock(ctlr);
884 //      if(drive->dlen && drive->dmactl && !atadmasetup(drive, drive->dlen))
885 //              drive->pktdma = Dma;
886 //      else
887 //              drive->pktdma = 0;
888
889         outb(cmdport+Features, 0/*drive->pktdma*/);
890         outb(cmdport+Count, 0);
891         outb(cmdport+Sector, 0);
892         len = 16*drive->secsize;
893         outb(cmdport+Bytelo, len);
894         outb(cmdport+Bytehi, len>>8);
895         outb(cmdport+Dh, drive->dev);
896         ctlr->done = 0;
897         ctlr->curdrive = drive;
898         ctlr->command = Cpkt;           /* debugging */
899 //      if(drive->pktdma)
900 //              atadmastart(ctlr, drive->write);
901         outb(cmdport+Command, Cpkt);
902
903         if((drive->info[Iconfig] & 0x0060) != 0x0020){
904                 microdelay(1);
905                 as = ataready(cmdport, ctlport, 0, Bsy, Drq|Chk, 4*1000);
906                 if(as < 0 || (as & (Bsy|Chk))){
907                         drive->status = as<0 ? 0 : as;
908                         ctlr->curdrive = nil;
909                         ctlr->done = 1;
910                         r = SDtimeout;
911                 }else
912                         atapktinterrupt(drive);
913         }
914         iunlock(ctlr);
915
916         sleep(ctlr, atapktiodone, ctlr);
917
918         qunlock(ctlr);
919
920         if(drive->status & Chk)
921                 r = SDcheck;
922
923         return r;
924 }
925
926 static int
927 atageniodone(void* arg)
928 {
929         return ((Ctlr*)arg)->done;
930 }
931
932 static uchar cmd48[256] = {
933         [Crs]   Crs48,
934         [Crd]   Crd48,
935         [Crdq]  Crdq48,
936         [Crsm]  Crsm48,
937         [Cws]   Cws48,
938         [Cwd]   Cwd48,
939         [Cwdq]  Cwdq48,
940         [Cwsm]  Cwsm48,
941 };
942
943 static int
944 atageniostart(Drive* drive, vlong lba)
945 {
946         Ctlr *ctlr;
947         uchar cmd;
948         int as, c, cmdport, ctlport, h, len, s, use48;
949
950         use48 = 0;
951         if((drive->flags&Lba48always) || (lba>>28) || drive->count > 256){
952                 if(!(drive->flags & Lba48))
953                         return -1;
954                 use48 = 1;
955                 c = h = s = 0;
956         }else if(drive->dev & Lba){
957                 c = (lba>>8) & 0xFFFF;
958                 h = (lba>>24) & 0x0F;
959                 s = lba & 0xFF;
960         }
961         else{
962                 if (drive->s == 0 || drive->h == 0)
963                         panic("atageniostart: zero s or h");
964                 c = lba/(drive->s*drive->h);
965                 h = ((lba/drive->s) % drive->h);
966                 s = (lba % drive->s) + 1;
967         }
968
969         ctlr = drive->ctlr;
970         cmdport = ctlr->cmdport;
971         ctlport = ctlr->ctlport;
972         if(ataready(cmdport, ctlport, drive->dev, Bsy|Drq, Drdy, 101*1000) < 0)
973                 return -1;
974
975         ilock(ctlr);
976
977         drive->block = drive->secsize;
978         if(drive->write)
979                 drive->command = Cws;
980         else
981                 drive->command = Crs;
982
983         drive->limit = drive->data + drive->count*drive->secsize;
984         cmd = drive->command;
985         if(use48){
986                 outb(cmdport+Count, (drive->count>>8) & 0xFF);
987                 outb(cmdport+Count, drive->count & 0XFF);
988                 outb(cmdport+Lbalo, (lba>>24) & 0xFF);
989                 outb(cmdport+Lbalo, lba & 0xFF);
990                 outb(cmdport+Lbamid, (lba>>32) & 0xFF);
991                 outb(cmdport+Lbamid, (lba>>8) & 0xFF);
992                 outb(cmdport+Lbahi, (lba>>40) & 0xFF);
993                 outb(cmdport+Lbahi, (lba>>16) & 0xFF);
994                 outb(cmdport+Dh, drive->dev|Lba);
995                 cmd = cmd48[cmd];
996
997                 if(DEBUG & Dbg48BIT)
998                         print("using 48-bit commands\n");
999         }else{
1000                 outb(cmdport+Count, drive->count);
1001                 outb(cmdport+Sector, s);
1002                 outb(cmdport+Cyllo, c);
1003                 outb(cmdport+Cylhi, c>>8);
1004                 outb(cmdport+Dh, drive->dev|h);
1005         }
1006         ctlr->done = 0;
1007         ctlr->curdrive = drive;
1008         ctlr->command = drive->command; /* debugging */
1009         outb(cmdport+Command, cmd);
1010
1011         switch(drive->command){
1012         case Cws:
1013         case Cwsm:
1014                 microdelay(1);
1015                 as = ataready(cmdport, ctlport, 0, Bsy, Drq|Err, 1000);
1016                 if(as < 0 || (as & Err)){
1017                         iunlock(ctlr);
1018                         return -1;
1019                 }
1020                 len = drive->block;
1021                 if(drive->data+len > drive->limit)
1022                         len = drive->limit-drive->data;
1023                 outss(cmdport+Data, drive->data, len/2);
1024                 break;
1025
1026         case Crd:
1027         case Cwd:
1028         //      atadmastart(ctlr, drive->write);
1029                 break;
1030         }
1031         iunlock(ctlr);
1032
1033         return 0;
1034 }
1035
1036 static int
1037 atagenioretry(Drive* drive)
1038 {
1039         return atasetsense(drive, SDcheck, 4, 8, drive->error);
1040 }
1041
1042 static int
1043 atagenio(Drive* drive, uchar* cmd, int)
1044 {
1045         uchar *p;
1046         Ctlr *ctlr;
1047         int count, max;
1048         vlong lba, len;
1049
1050         /*
1051          * Map SCSI commands into ATA commands for discs.
1052          * Fail any command with a LUN except INQUIRY which
1053          * will return 'logical unit not supported'.
1054          */
1055         if((cmd[1]>>5) && cmd[0] != 0x12)
1056                 return atasetsense(drive, SDcheck, 0x05, 0x25, 0);
1057
1058         switch(cmd[0]){
1059         default:
1060                 return atasetsense(drive, SDcheck, 0x05, 0x20, 0);
1061
1062         case 0x00:                      /* test unit ready */
1063                 return SDok;
1064
1065         case 0x03:                      /* request sense */
1066                 if(cmd[4] < sizeof(drive->sense))
1067                         len = cmd[4];
1068                 else
1069                         len = sizeof(drive->sense);
1070                 if(drive->data && drive->dlen >= len){
1071                         memmove(drive->data, drive->sense, len);
1072                         drive->data += len;
1073                 }
1074                 return SDok;
1075
1076         case 0x12:                      /* inquiry */
1077                 if(cmd[4] < sizeof(drive->inquiry))
1078                         len = cmd[4];
1079                 else
1080                         len = sizeof(drive->inquiry);
1081                 if(drive->data && drive->dlen >= len){
1082                         memmove(drive->data, drive->inquiry, len);
1083                         drive->data += len;
1084                 }
1085                 return SDok;
1086
1087         case 0x1B:                      /* start/stop unit */
1088                 /*
1089                  * NOP for now, can use the power management feature
1090                  * set later.
1091                  */
1092                 return SDok;
1093
1094         case 0x25:                      /* read capacity */
1095                 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1096                         return atasetsense(drive, SDcheck, 0x05, 0x24, 0);
1097                 if(drive->data == nil || drive->dlen < 8)
1098                         return atasetsense(drive, SDcheck, 0x05, 0x20, 1);
1099                 /*
1100                  * Read capacity returns the LBA of the last sector.
1101                  */
1102                 len = drive->sectors-1;
1103                 p = drive->data;
1104                 *p++ = len>>24;
1105                 *p++ = len>>16;
1106                 *p++ = len>>8;
1107                 *p++ = len;
1108                 len = drive->secsize;
1109                 *p++ = len>>24;
1110                 *p++ = len>>16;
1111                 *p++ = len>>8;
1112                 *p++ = len;
1113                 drive->data = p;
1114                 return SDok;
1115
1116         case 0x9E:                      /* long read capacity */
1117                 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1118                         return atasetsense(drive, SDcheck, 0x05, 0x24, 0);
1119                 if(drive->data == nil || drive->dlen < 8)
1120                         return atasetsense(drive, SDcheck, 0x05, 0x20, 1);
1121                 /*
1122                  * Read capacity returns the LBA of the last sector.
1123                  */
1124                 len = drive->sectors-1;
1125                 p = drive->data;
1126                 *p++ = len>>56;
1127                 *p++ = len>>48;
1128                 *p++ = len>>40;
1129                 *p++ = len>>32;
1130                 *p++ = len>>24;
1131                 *p++ = len>>16;
1132                 *p++ = len>>8;
1133                 *p++ = len;
1134                 len = drive->secsize;
1135                 *p++ = len>>24;
1136                 *p++ = len>>16;
1137                 *p++ = len>>8;
1138                 *p++ = len;
1139                 drive->data = p;
1140                 return SDok;
1141
1142         case 0x28:                      /* read */
1143         case 0x2A:                      /* write */
1144                 break;
1145
1146         case 0x5A:
1147                 return atamodesense(drive, cmd);
1148         }
1149
1150         ctlr = drive->ctlr;
1151         lba = (cmd[2]<<24)|(cmd[3]<<16)|(cmd[4]<<8)|cmd[5];
1152         count = (cmd[7]<<8)|cmd[8];
1153         if(drive->data == nil)
1154                 return SDok;
1155         if (drive->secsize == 0)
1156                 panic("atagenio: zero sector size");
1157         if(drive->dlen < count*drive->secsize)
1158                 count = drive->dlen/drive->secsize;
1159         qlock(ctlr);
1160         while(count){
1161                 max = (drive->flags&Lba48) ? 65536 : 256;
1162                 if(count > max)
1163                         drive->count = max;
1164                 else
1165                         drive->count = count;
1166                 if(atageniostart(drive, lba)){
1167                         ilock(ctlr);
1168                         atanop(drive, 0);
1169                         iunlock(ctlr);
1170                         qunlock(ctlr);
1171                         return atagenioretry(drive);
1172                 }
1173
1174                 tsleep(ctlr, atageniodone, ctlr, 10*1000);
1175                 if(!ctlr->done){
1176                         /*
1177                          * What should the above timeout be? In
1178                          * standby and sleep modes it could take as
1179                          * long as 30 seconds for a drive to respond.
1180                          * Very hard to get out of this cleanly.
1181                          */
1182                 //      atadumpstate(drive, cmd, lba, count);
1183                         ataabort(drive, 1);
1184                         return atagenioretry(drive);
1185                 }
1186
1187                 if(drive->status & Err){
1188                         qunlock(ctlr);
1189                         return atasetsense(drive, SDcheck, 4, 8, drive->error);
1190                 }
1191                 count -= drive->count;
1192                 lba += drive->count;
1193         }
1194         qunlock(ctlr);
1195
1196         return SDok;
1197 }
1198
1199 static int
1200 atario(SDreq* r)
1201 {
1202         Ctlr *ctlr;
1203         Drive *drive;
1204         SDunit *unit;
1205         uchar cmd10[10], *cmdp, *p;
1206         int clen, reqstatus, status;
1207
1208         unit = r->unit;
1209         if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil){
1210                 r->status = SDtimeout;
1211                 return SDtimeout;
1212         }
1213         drive = ctlr->drive[unit->subno];
1214
1215         /*
1216          * Most SCSI commands can be passed unchanged except for
1217          * the padding on the end. The few which require munging
1218          * are not used internally. Mode select/sense(6) could be
1219          * converted to the 10-byte form but it's not worth the
1220          * effort. Read/write(6) are easy.
1221          */
1222         switch(r->cmd[0]){
1223         case 0x08:                      /* read */
1224         case 0x0A:                      /* write */
1225                 cmdp = cmd10;
1226                 memset(cmdp, 0, sizeof(cmd10));
1227                 cmdp[0] = r->cmd[0]|0x20;
1228                 cmdp[1] = r->cmd[1] & 0xE0;
1229                 cmdp[5] = r->cmd[3];
1230                 cmdp[4] = r->cmd[2];
1231                 cmdp[3] = r->cmd[1] & 0x0F;
1232                 cmdp[8] = r->cmd[4];
1233                 clen = sizeof(cmd10);
1234                 break;
1235
1236         default:
1237                 cmdp = r->cmd;
1238                 clen = r->clen;
1239                 break;
1240         }
1241
1242         qlock(drive);
1243         drive->write = r->write;
1244         drive->data = r->data;
1245         drive->dlen = r->dlen;
1246
1247         drive->status = 0;
1248         drive->error = 0;
1249         if(drive->pkt)
1250                 status = atapktio(drive, cmdp, clen);
1251         else
1252                 status = atagenio(drive, cmdp, clen);
1253         if(status == SDok){
1254                 atasetsense(drive, SDok, 0, 0, 0);
1255                 if(drive->data){
1256                         p = r->data;
1257                         r->rlen = drive->data - p;
1258                 }
1259                 else
1260                         r->rlen = 0;
1261         }
1262         else if(status == SDcheck && !(r->flags & SDnosense)){
1263                 drive->write = 0;
1264                 memset(cmd10, 0, sizeof(cmd10));
1265                 cmd10[0] = 0x03;
1266                 cmd10[1] = r->lun<<5;
1267                 cmd10[4] = sizeof(r->sense)-1;
1268                 drive->data = r->sense;
1269                 drive->dlen = sizeof(r->sense)-1;
1270                 drive->status = 0;
1271                 drive->error = 0;
1272                 if(drive->pkt)
1273                         reqstatus = atapktio(drive, cmd10, 6);
1274                 else
1275                         reqstatus = atagenio(drive, cmd10, 6);
1276                 if(reqstatus == SDok){
1277                         r->flags |= SDvalidsense;
1278                         atasetsense(drive, SDok, 0, 0, 0);
1279                 }
1280         }
1281         qunlock(drive);
1282         r->status = status;
1283         if(status != SDok)
1284                 return status;
1285
1286         /*
1287          * Fix up any results.
1288          * Many ATAPI CD-ROMs ignore the LUN field completely and
1289          * return valid INQUIRY data. Patch the response to indicate
1290          * 'logical unit not supported' if the LUN is non-zero.
1291          */
1292         switch(cmdp[0]){
1293         case 0x12:                      /* inquiry */
1294                 if((p = r->data) == nil)
1295                         break;
1296                 if((cmdp[1]>>5) && (!drive->pkt || (p[0] & 0x1F) == 0x05))
1297                         p[0] = 0x7F;
1298                 /*FALLTHROUGH*/
1299         default:
1300                 break;
1301         }
1302
1303         return SDok;
1304 }
1305
1306 static void
1307 atainterrupt(Ureg*, void* arg)
1308 {
1309         Ctlr *ctlr;
1310         Drive *drive;
1311         int cmdport, len, status;
1312
1313         ctlr = arg;
1314
1315         ilock(ctlr);
1316         if(inb(ctlr->ctlport+As) & Bsy){
1317                 iunlock(ctlr);
1318                 if(DEBUG & DbgBsy)
1319                         print("IBsy+");
1320                 return;
1321         }
1322         cmdport = ctlr->cmdport;
1323         status = inb(cmdport+Status);
1324         if((drive = ctlr->curdrive) == nil){
1325                 iunlock(ctlr);
1326                 if((DEBUG & DbgINL) && ctlr->command != Cedd)
1327                         print("Inil%2.2uX+", ctlr->command);
1328                 return;
1329         }
1330
1331         if(status & Err)
1332                 drive->error = inb(cmdport+Error);
1333         else switch(drive->command){
1334         default:
1335                 drive->error = Abrt;
1336                 break;
1337
1338         case Crs:
1339         case Crsm:
1340                 if(!(status & Drq)){
1341                         drive->error = Abrt;
1342                         break;
1343                 }
1344                 len = drive->block;
1345                 if(drive->data+len > drive->limit)
1346                         len = drive->limit-drive->data;
1347                 inss(cmdport+Data, drive->data, len/2);
1348                 drive->data += len;
1349                 if(drive->data >= drive->limit)
1350                         ctlr->done = 1;
1351                 break;
1352
1353         case Cws:
1354         case Cwsm:
1355                 len = drive->block;
1356                 if(drive->data+len > drive->limit)
1357                         len = drive->limit-drive->data;
1358                 drive->data += len;
1359                 if(drive->data >= drive->limit){
1360                         ctlr->done = 1;
1361                         break;
1362                 }
1363                 if(!(status & Drq)){
1364                         drive->error = Abrt;
1365                         break;
1366                 }
1367                 len = drive->block;
1368                 if(drive->data+len > drive->limit)
1369                         len = drive->limit-drive->data;
1370                 outss(cmdport+Data, drive->data, len/2);
1371                 break;
1372
1373         case Cpkt:
1374                 atapktinterrupt(drive);
1375                 break;
1376
1377         case Crd:
1378         case Cwd:
1379         //      atadmainterrupt(drive, drive->count*drive->secsize);
1380                 break;
1381         }
1382         iunlock(ctlr);
1383
1384         if(drive->error){
1385                 status |= Err;
1386                 ctlr->done = 1;
1387         }
1388
1389         if(ctlr->done){
1390                 ctlr->curdrive = nil;
1391                 drive->status = status;
1392                 wakeup(ctlr);
1393         }
1394 }
1395
1396 static SDev*
1397 atapnp(void)
1398 {
1399         Ctlr *ctlr;
1400         Pcidev *p;
1401         int channel, ispc87415, pi, r;
1402         SDev *legacy[2], *sdev, *head, *tail;
1403
1404         legacy[0] = legacy[1] = head = tail = nil;
1405
1406         /* native access to disks seems to interfere with bios loading */
1407         if (biosload)
1408                 return nil;
1409
1410         if(sdev = ataprobe(0x1F0, 0x3F4, IrqATA0)){
1411                 head = tail = sdev;
1412                 legacy[0] = sdev;
1413         }
1414         if(sdev = ataprobe(0x170, 0x374, IrqATA1)){
1415                 if(head != nil)
1416                         tail->next = sdev;
1417                 else
1418                         head = sdev;
1419                 tail = sdev;
1420                 legacy[1] = sdev;
1421         }
1422
1423         p = nil;
1424         while(p = pcimatch(p, 0, 0)){
1425                 /*
1426                  * Look for devices with the correct class and sub-class
1427                  * code and known device and vendor ID; add native-mode
1428                  * channels to the list to be probed, save info for the
1429                  * compatibility mode channels.
1430                  * Note that the legacy devices should not be considered
1431                  * PCI devices by the interrupt controller.
1432                  * For both native and legacy, save info for busmastering
1433                  * if capable.
1434                  * Promise Ultra ATA/66 (PDC20262) appears to
1435                  * 1) give a sub-class of 'other mass storage controller'
1436                  *    instead of 'IDE controller', regardless of whether it's
1437                  *    the only controller or not;
1438                  * 2) put 0 in the programming interface byte (probably
1439                  *    as a consequence of 1) above).
1440                  * Sub-class code 0x04 is 'RAID controller', e.g. VIA VT8237.
1441                  */
1442                 if(p->ccrb != 0x01)
1443                         continue;
1444                 if(p->ccru != 0x01 && p->ccru != 0x04 && p->ccru != 0x80)
1445                         continue;
1446                 pi = p->ccrp;
1447                 ispc87415 = 0;
1448
1449                 switch((p->did<<16)|p->vid){
1450                 default:
1451                         continue;
1452
1453                 case (0x0002<<16)|0x100B:       /* NS PC87415 */
1454                         /*
1455                          * Disable interrupts on both channels until
1456                          * after they are probed for drives.
1457                          * This must be called before interrupts are
1458                          * enabled because the IRQ may be shared.
1459                          */
1460                         ispc87415 = 1;
1461                         pcicfgw32(p, 0x40, 0x00000300);
1462                         break;
1463                 case (0x1000<<16)|0x1042:       /* PC-Tech RZ1000 */
1464                         /*
1465                          * Turn off prefetch. Overkill, but cheap.
1466                          */
1467                         r = pcicfgr32(p, 0x40);
1468                         r &= ~0x2000;
1469                         pcicfgw32(p, 0x40, r);
1470                         break;
1471                 case (0x4D38<<16)|0x105A:       /* Promise PDC20262 */
1472                 case (0x4D30<<16)|0x105A:       /* Promise PDC202xx */
1473                 case (0x4D68<<16)|0x105A:       /* Promise PDC20268 */
1474                 case (0x4D69<<16)|0x105A:       /* Promise Ultra/133 TX2 */
1475                 case (0x3373<<16)|0x105A:       /* Promise 20378 RAID */
1476                 case (0x3149<<16)|0x1106:       /* VIA VT8237 SATA/RAID */
1477                 case (0x0680<<16)|0x1095:       /* SiI 0680/680A PATA133 ATAPI/RAID */
1478                 case (0x3112<<16)|0x1095:       /* SiL 3112 SATA (DMA busted?) */
1479                 case (0x3114<<16)|0x1095:       /* SiL 3114 SATA/RAID */
1480                         pi = 0x85;
1481                         break;
1482                 case (0x0004<<16)|0x1103:       /* HighPoint HPT-370 */
1483                         pi = 0x85;
1484                         /*
1485                          * Turn off fast interrupt prediction.
1486                          */
1487                         if((r = pcicfgr8(p, 0x51)) & 0x80)
1488                                 pcicfgw8(p, 0x51, r & ~0x80);
1489                         if((r = pcicfgr8(p, 0x55)) & 0x80)
1490                                 pcicfgw8(p, 0x55, r & ~0x80);
1491                         break;
1492                 case (0x0640<<16)|0x1095:       /* CMD 640B */
1493                         /*
1494                          * Bugfix code here...
1495                          */
1496                         break;
1497                 case (0x7441<<16)|0x1022:       /* AMD 768 */
1498                         /*
1499                          * Set:
1500                          *      0x41    prefetch, postwrite;
1501                          *      0x43    FIFO configuration 1/2 and 1/2;
1502                          *      0x44    status register read retry;
1503                          *      0x46    DMA read and end of sector flush.
1504                          */
1505                         r = pcicfgr8(p, 0x41);
1506                         pcicfgw8(p, 0x41, r|0xF0);
1507                         r = pcicfgr8(p, 0x43);
1508                         pcicfgw8(p, 0x43, (r & 0x90)|0x2A);
1509                         r = pcicfgr8(p, 0x44);
1510                         pcicfgw8(p, 0x44, r|0x08);
1511                         r = pcicfgr8(p, 0x46);
1512                         pcicfgw8(p, 0x46, (r & 0x0C)|0xF0);
1513                         /*FALLTHROUGH*/
1514                 case (0x7469<<16)|0x1022:       /* AMD 3111 */
1515                 case (0x4376<<16)|0x1002:       /* ATI SB400 PATA */
1516                 case (0x4379<<16)|0x1002:       /* ATI SB400 SATA */
1517                 case (0x437a<<16)|0x1002:       /* ATI SB400 SATA */
1518                         /*
1519                          * This can probably be lumped in with the 768 above.
1520                          */
1521                         /*FALLTHROUGH*/
1522                 case (0x209A<<16)|0x1022:       /* AMD CS5536 */
1523                 case (0x01BC<<16)|0x10DE:       /* nVidia nForce1 */
1524                 case (0x0065<<16)|0x10DE:       /* nVidia nForce2 */
1525                 case (0x0085<<16)|0x10DE:       /* nVidia nForce2 MCP */
1526                 case (0x00E3<<16)|0x10DE:       /* nVidia nForce2 250 SATA */
1527                 case (0x00D5<<16)|0x10DE:       /* nVidia nForce3 */
1528                 case (0x00E5<<16)|0x10DE:       /* nVidia nForce3 Pro */
1529                 case (0x00EE<<16)|0x10DE:       /* nVidia nForce3 250 SATA */
1530                 case (0x0035<<16)|0x10DE:       /* nVidia nForce3 MCP */
1531                 case (0x0053<<16)|0x10DE:       /* nVidia nForce4 */
1532                 case (0x0054<<16)|0x10DE:       /* nVidia nForce4 SATA */
1533                 case (0x0055<<16)|0x10DE:       /* nVidia nForce4 SATA */
1534                         /*
1535                          * Ditto, although it may have a different base
1536                          * address for the registers (0x50?).
1537                          */
1538                         break;
1539                 case (0x0646<<16)|0x1095:       /* CMD 646 */
1540                 case (0x0571<<16)|0x1106:       /* VIA 82C686 */
1541                 case (0x0211<<16)|0x1166:       /* ServerWorks IB6566 */
1542                 case (0x2363<<16)|0x197b:       /* JMicron SATA */
1543                 case (0x1230<<16)|0x8086:       /* 82371FB (PIIX) */
1544                 case (0x7010<<16)|0x8086:       /* 82371SB (PIIX3) */
1545                 case (0x7111<<16)|0x8086:       /* 82371[AE]B (PIIX4[E]) */
1546                 case (0x2411<<16)|0x8086:       /* 82801AA (ICH) */
1547                 case (0x2421<<16)|0x8086:       /* 82801AB (ICH0) */
1548                 case (0x244A<<16)|0x8086:       /* 82801BA (ICH2, Mobile) */
1549                 case (0x244B<<16)|0x8086:       /* 82801BA (ICH2, High-End) */
1550                 case (0x248A<<16)|0x8086:       /* 82801CA (ICH3, Mobile) */
1551                 case (0x248B<<16)|0x8086:       /* 82801CA (ICH3, High-End) */
1552                 case (0x24CA<<16)|0x8086:       /* 82801DBM (ICH4, Mobile) */
1553                 case (0x24CB<<16)|0x8086:       /* 82801DB (ICH4, High-End) */
1554                 case (0x24DB<<16)|0x8086:       /* 82801EB (ICH5) */
1555                 case (0x25A3<<16)|0x8086:       /* 6300ESB (E7210) */
1556                 case (0x266F<<16)|0x8086:       /* 82801FB (ICH6) */
1557                 case (0x27DF<<16)|0x8086:       /* 82801G SATA (ICH7) */
1558                 case (0x27C0<<16)|0x8086:       /* 82801GB SATA AHCI (ICH7) */
1559 //              case (0x27C4<<16)|0x8086:       /* 82801GBM SATA (ICH7) */
1560                 case (0x27C5<<16)|0x8086:       /* 82801GBM SATA AHCI (ICH7) */
1561                 case (0x2920<<16)|0x8086:       /* 82801(IB)/IR/IH/IO SATA IDE (ICH9) */
1562                 case (0x3a20<<16)|0x8086:       /* 82801JI (ICH10) */
1563                 case (0x3a26<<16)|0x8086:       /* 82801JI (ICH10) */
1564                         break;
1565                 }
1566
1567                 for(channel = 0; channel < 2; channel++){
1568                         if(pi & (1<<(2*channel))){
1569                                 sdev = ataprobe(p->mem[0+2*channel].bar & ~0x01,
1570                                                 p->mem[1+2*channel].bar & ~0x01,
1571                                                 p->intl);
1572                                 if(sdev == nil)
1573                                         continue;
1574
1575                                 ctlr = sdev->ctlr;
1576                                 if(ispc87415)
1577                                         ctlr->ienable = pc87415ienable;
1578
1579                                 if(head != nil)
1580                                         tail->next = sdev;
1581                                 else
1582                                         head = sdev;
1583                                 tail = sdev;
1584                                 ctlr->tbdf = p->tbdf;
1585                         }
1586                         else if((sdev = legacy[channel]) == nil)
1587                                 continue;
1588                         else
1589                                 ctlr = sdev->ctlr;
1590
1591                         ctlr->pcidev = p;
1592                 }
1593         }
1594
1595         return head;
1596 }
1597
1598 static SDev*
1599 atalegacy(int port, int irq)
1600 {
1601         return ataprobe(port, port+0x204, irq);
1602 }
1603
1604 static SDev*
1605 ataid(SDev* sdev)
1606 {
1607         int i;
1608         Ctlr *ctlr;
1609
1610         /*
1611          * Legacy controllers are always 'C' and 'D' and if
1612          * they exist and have drives will be first in the list.
1613          * If there are no active legacy controllers, native
1614          * controllers start at 'C'.
1615          */
1616         if(sdev == nil)
1617                 return nil;
1618         ctlr = sdev->ctlr;
1619         if(ctlr->cmdport == 0x1F0 || ctlr->cmdport == 0x170)
1620                 i = 2;
1621         else
1622                 i = 0;
1623         while(sdev){
1624                 if(sdev->ifc == &sdataifc){
1625                         ctlr = sdev->ctlr;
1626                         if(ctlr->cmdport == 0x1F0)
1627                                 sdev->idno = 'C';
1628                         else if(ctlr->cmdport == 0x170)
1629                                 sdev->idno = 'D';
1630                         else{
1631                                 sdev->idno = 'C'+i;
1632                                 i++;
1633                         }
1634                 //      snprint(sdev->name, NAMELEN, "sd%c", sdev->idno);
1635                 }
1636                 sdev = sdev->next;
1637         }
1638
1639         return nil;
1640 }
1641
1642 static int
1643 ataenable(SDev* sdev)
1644 {
1645         Ctlr *ctlr;
1646
1647         ctlr = sdev->ctlr;
1648
1649         setvec(ctlr->irq+VectorPIC, atainterrupt, ctlr);
1650         outb(ctlr->ctlport+Dc, 0);
1651         if(ctlr->ienable)
1652                 ctlr->ienable(ctlr);
1653
1654         return 1;
1655 }
1656
1657 SDifc sdataifc = {
1658         "ata",                          /* name */
1659
1660         atapnp,                         /* pnp */
1661         atalegacy,                      /* legacy */
1662         ataid,                          /* id */
1663         ataenable,                      /* enable */
1664         nil,                            /* disable */
1665
1666         scsiverify,                     /* verify */
1667         scsionline,                     /* online */
1668         atario,                         /* rio */
1669         nil,                    /* rctl */
1670         nil,                    /* wctl */
1671
1672         scsibio,                        /* bio */
1673 };