3818fb61f837f38db3f460504f9fcf0d6b9af507
[people/mcb30/legacybios.git] / src / ata.c
1 #include "ata.h" // ATA_*
2 #include "types.h" // u8
3 #include "ioport.h" // inb
4 #include "util.h" // BX_INFO
5
6 #define TIMEOUT 0
7 #define BSY 1
8 #define NOT_BSY 2
9 #define NOT_BSY_DRQ 3
10 #define NOT_BSY_NOT_DRQ 4
11 #define NOT_BSY_RDY 5
12
13 #define IDE_TIMEOUT 32000u //32 seconds max for IDE ops
14
15 #define BX_DEBUG_ATA BX_INFO
16
17 static int
18 await_ide(u8 when_done, u16 base, u16 timeout)
19 {
20     u32 time=0,last=0;
21     // for the times you're supposed to throw one away
22     u16 status = inb(base + ATA_CB_STAT);
23     for (;;) {
24         status = inb(base+ATA_CB_STAT);
25         time++;
26         u8 result;
27         if (when_done == BSY)
28             result = status & ATA_CB_STAT_BSY;
29         else if (when_done == NOT_BSY)
30             result = !(status & ATA_CB_STAT_BSY);
31         else if (when_done == NOT_BSY_DRQ)
32             result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_DRQ);
33         else if (when_done == NOT_BSY_NOT_DRQ)
34             result = !(status & ATA_CB_STAT_BSY) && !(status & ATA_CB_STAT_DRQ);
35         else if (when_done == NOT_BSY_RDY)
36             result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_RDY);
37         else if (when_done == TIMEOUT)
38             result = 0;
39
40         if (result)
41             return 0;
42         // mod 2048 each 16 ms
43         if (time>>16 != last) {
44             last = time >>16;
45             BX_DEBUG_ATA("await_ide: (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %d timeout= %d\n",when_done,time>>11, timeout);
46         }
47         if (status & ATA_CB_STAT_ERR) {
48             BX_DEBUG_ATA("await_ide: ERROR (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %d timeout= %d\n",when_done,time>>11, timeout);
49             return -1;
50         }
51         if ((timeout == 0) || ((time>>11) > timeout))
52             break;
53     }
54     BX_INFO("IDE time out\n");
55     return -1;
56 }
57
58
59 // ---------------------------------------------------------------------------
60 // ATA/ATAPI driver : software reset
61 // ---------------------------------------------------------------------------
62 // ATA-3
63 // 8.2.1 Software reset - Device 0
64
65 void
66 ata_reset(u16 device)
67 {
68     u16 iobase1, iobase2;
69     u8  channel, slave, sn, sc;
70     u8  type;
71
72     channel = device / 2;
73     slave = device % 2;
74
75     iobase1 = GET_EBDA(ata.channels[channel].iobase1);
76     iobase2 = GET_EBDA(ata.channels[channel].iobase2);
77
78     // Reset
79
80     // 8.2.1 (a) -- set SRST in DC
81     outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST, iobase2+ATA_CB_DC);
82
83     // 8.2.1 (b) -- wait for BSY
84     await_ide(BSY, iobase1, 20);
85
86     // 8.2.1 (f) -- clear SRST
87     outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2+ATA_CB_DC);
88
89     type=GET_EBDA(ata.devices[device].type);
90     if (type != ATA_TYPE_NONE) {
91
92         // 8.2.1 (g) -- check for sc==sn==0x01
93         // select device
94         outb(slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0, iobase1+ATA_CB_DH);
95         sc = inb(iobase1+ATA_CB_SC);
96         sn = inb(iobase1+ATA_CB_SN);
97
98         if ( (sc==0x01) && (sn==0x01) ) {
99             if (type == ATA_TYPE_ATA) //ATA
100                 await_ide(NOT_BSY_RDY, iobase1, IDE_TIMEOUT);
101             else //ATAPI
102                 await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
103         }
104
105         // 8.2.1 (h) -- wait for not BSY
106         await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
107     }
108
109     // Enable interrupts
110     outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
111 }
112
113 static void
114 insw(u16 port, u16 segment, u16 offset, u16 count)
115 {
116     u16 i;
117     for (i=0; i<count; i++) {
118         u16 d = inw(port);
119         SET_FARVAR(segment, *(u16*)(offset + i), d);
120     }
121 }
122
123 static void
124 insl(u16 port, u16 segment, u16 offset, u16 count)
125 {
126     u16 i;
127     for (i=0; i<count; i++) {
128         u32 d = inl(port);
129         SET_FARVAR(segment, *(u32*)(offset + i), d);
130     }
131 }
132
133 static void
134 outsw(u16 port, u16 segment, u16 offset, u16 count)
135 {
136     u16 i;
137     for (i=0; i<count; i++) {
138         u16 d = GET_FARVAR(segment, *(u16*)(offset + i));
139         outw(d, port);
140     }
141 }
142
143 static void
144 outsl(u16 port, u16 segment, u16 offset, u16 count)
145 {
146     u16 i;
147     for (i=0; i<count; i++) {
148         u32 d = GET_FARVAR(segment, *(u32*)(offset + i));
149         outl(d, port);
150     }
151 }
152
153
154 // ---------------------------------------------------------------------------
155 // ATA/ATAPI driver : execute a data-in command
156 // ---------------------------------------------------------------------------
157       // returns
158       // 0 : no error
159       // 1 : BUSY bit set
160       // 2 : read error
161       // 3 : expected DRQ=1
162       // 4 : no sectors left to read/verify
163       // 5 : more sectors to read/verify
164       // 6 : no sectors left to write
165       // 7 : more sectors to write
166 u16
167 ata_cmd_data_in(u16 device, u16 command, u16 count, u16 cylinder
168                 , u16 head, u16 sector, u32 lba, u16 segment, u16 offset)
169 {
170     u16 iobase1, iobase2, blksize;
171     u8  channel, slave;
172     u8  status, current, mode;
173
174     channel = device / 2;
175     slave   = device % 2;
176
177     iobase1 = GET_EBDA(ata.channels[channel].iobase1);
178     iobase2 = GET_EBDA(ata.channels[channel].iobase2);
179     mode    = GET_EBDA(ata.devices[device].mode);
180     blksize = 0x200;
181     if (mode == ATA_MODE_PIO32) blksize>>=2;
182     else blksize>>=1;
183
184     // Reset count of transferred data
185     SET_EBDA(ata.trsfsectors,0);
186     SET_EBDA(ata.trsfbytes,0L);
187     current = 0;
188
189     status = inb(iobase1 + ATA_CB_STAT);
190     if (status & ATA_CB_STAT_BSY)
191         return 1;
192
193     outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC);
194
195     // sector will be 0 only on lba access. Convert to lba-chs
196     if (sector == 0) {
197         if ((count >= 1 << 8) || (lba + count >= 1UL << 28)) {
198             outb(0x00, iobase1 + ATA_CB_FR);
199             outb((count >> 8) & 0xff, iobase1 + ATA_CB_SC);
200             outb(lba >> 24, iobase1 + ATA_CB_SN);
201             outb(0, iobase1 + ATA_CB_CL);
202             outb(0, iobase1 + ATA_CB_CH);
203             command |= 0x04;
204             count &= (1UL << 8) - 1;
205             lba &= (1UL << 24) - 1;
206         }
207         sector = (u16) (lba & 0x000000ffL);
208         cylinder = (u16) ((lba>>8) & 0x0000ffffL);
209         head = ((u16) ((lba>>24) & 0x0000000fL)) | ATA_CB_DH_LBA;
210     }
211
212     outb(0x00, iobase1 + ATA_CB_FR);
213     outb(count, iobase1 + ATA_CB_SC);
214     outb(sector, iobase1 + ATA_CB_SN);
215     outb(cylinder & 0x00ff, iobase1 + ATA_CB_CL);
216     outb(cylinder >> 8, iobase1 + ATA_CB_CH);
217     outb((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (u8) head
218          , iobase1 + ATA_CB_DH);
219     outb(command, iobase1 + ATA_CB_CMD);
220
221     await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
222     status = inb(iobase1 + ATA_CB_STAT);
223
224     if (status & ATA_CB_STAT_ERR) {
225         BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
226         return 2;
227     } else if ( !(status & ATA_CB_STAT_DRQ) ) {
228         BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n"
229                      , (unsigned) status);
230         return 3;
231     }
232
233     // FIXME : move seg/off translation here
234
235     irq_enable();
236
237     while (1) {
238
239         if (offset > 0xf800) {
240             offset -= 0x800;
241             segment += 0x80;
242         }
243
244         if (mode == ATA_MODE_PIO32)
245             insw(iobase1, segment, offset, blksize);
246         else
247             insl(iobase1, segment, offset, blksize);
248
249         current++;
250         SET_EBDA(ata.trsfsectors,current);
251         count--;
252         await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
253         status = inb(iobase1 + ATA_CB_STAT);
254         if (count == 0) {
255             if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ
256                             | ATA_CB_STAT_ERR) )
257                  != ATA_CB_STAT_RDY ) {
258                 BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n"
259                              , (unsigned) status);
260                 return 4;
261             }
262             break;
263         }
264         else {
265             if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ
266                             | ATA_CB_STAT_ERR) )
267                  != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
268                 BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n"
269                              , (unsigned) status);
270                 return 5;
271             }
272             continue;
273         }
274     }
275     // Enable interrupts
276     outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
277     return 0;
278 }
279
280 // ---------------------------------------------------------------------------
281 // ATA/ATAPI driver : execute a data-out command
282 // ---------------------------------------------------------------------------
283       // returns
284       // 0 : no error
285       // 1 : BUSY bit set
286       // 2 : read error
287       // 3 : expected DRQ=1
288       // 4 : no sectors left to read/verify
289       // 5 : more sectors to read/verify
290       // 6 : no sectors left to write
291       // 7 : more sectors to write
292 u16
293 ata_cmd_data_out(u16 device, u16 command, u16 count, u16 cylinder
294                  , u16 head, u16 sector, u32 lba, u16 segment, u16 offset)
295 {
296     u16 iobase1, iobase2, blksize;
297     u8  channel, slave;
298     u8  status, current, mode;
299
300     channel = device / 2;
301     slave   = device % 2;
302
303     iobase1 = GET_EBDA(ata.channels[channel].iobase1);
304     iobase2 = GET_EBDA(ata.channels[channel].iobase2);
305     mode    = GET_EBDA(ata.devices[device].mode);
306     blksize = 0x200;
307     if (mode == ATA_MODE_PIO32)
308         blksize>>=2;
309     else
310         blksize>>=1;
311
312     // Reset count of transferred data
313     SET_EBDA(ata.trsfsectors,0);
314     SET_EBDA(ata.trsfbytes,0L);
315     current = 0;
316
317     status = inb(iobase1 + ATA_CB_STAT);
318     if (status & ATA_CB_STAT_BSY)
319         return 1;
320
321     outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC);
322
323     // sector will be 0 only on lba access. Convert to lba-chs
324     if (sector == 0) {
325         if ((count >= 1 << 8) || (lba + count >= 1UL << 28)) {
326             outb(0x00, iobase1 + ATA_CB_FR);
327             outb((count >> 8) & 0xff, iobase1 + ATA_CB_SC);
328             outb(lba >> 24, iobase1 + ATA_CB_SN);
329             outb(0, iobase1 + ATA_CB_CL);
330             outb(0, iobase1 + ATA_CB_CH);
331             command |= 0x04;
332             count &= (1UL << 8) - 1;
333             lba &= (1UL << 24) - 1;
334         }
335         sector = (u16) (lba & 0x000000ffL);
336         cylinder = (u16) ((lba>>8) & 0x0000ffffL);
337         head = ((u16) ((lba>>24) & 0x0000000fL)) | ATA_CB_DH_LBA;
338     }
339
340     outb(0x00, iobase1 + ATA_CB_FR);
341     outb(count, iobase1 + ATA_CB_SC);
342     outb(sector, iobase1 + ATA_CB_SN);
343     outb(cylinder & 0x00ff, iobase1 + ATA_CB_CL);
344     outb(cylinder >> 8, iobase1 + ATA_CB_CH);
345     outb((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (u8) head
346          , iobase1 + ATA_CB_DH);
347     outb(command, iobase1 + ATA_CB_CMD);
348
349     await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
350     status = inb(iobase1 + ATA_CB_STAT);
351
352     if (status & ATA_CB_STAT_ERR) {
353         BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
354         return 2;
355     } else if ( !(status & ATA_CB_STAT_DRQ) ) {
356         BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n"
357                      , (unsigned) status);
358         return 3;
359     }
360
361     // FIXME : move seg/off translation here
362
363     irq_enable();
364
365     while (1) {
366
367         if (offset > 0xf800) {
368             offset -= 0x800;
369             segment += 0x80;
370         }
371
372         if (mode == ATA_MODE_PIO32)
373             outsw(iobase1, segment, offset, blksize);
374         else
375             outsl(iobase1, segment, offset, blksize);
376
377         current++;
378         SET_EBDA(ata.trsfsectors,current);
379         count--;
380         status = inb(iobase1 + ATA_CB_STAT);
381         if (count == 0) {
382             if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF
383                             | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
384                  != ATA_CB_STAT_RDY ) {
385                 BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n"
386                              , (unsigned) status);
387                 return 6;
388             }
389             break;
390         } else {
391             if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ
392                             | ATA_CB_STAT_ERR) )
393                  != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
394                 BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n"
395                              , (unsigned) status);
396                 return 7;
397             }
398             continue;
399         }
400     }
401     // Enable interrupts
402     outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
403     return 0;
404 }
405
406 // ---------------------------------------------------------------------------
407 // ATA/ATAPI driver : execute a packet command
408 // ---------------------------------------------------------------------------
409       // returns
410       // 0 : no error
411       // 1 : error in parameters
412       // 2 : BUSY bit set
413       // 3 : error
414       // 4 : not ready
415 u16
416 ata_cmd_packet(u16 device, u8 cmdlen, u16 cmdseg, u16 cmdoff, u16 header
417                , u32 length, u8 inout, u16 bufseg, u16 bufoff)
418 {
419     u16 iobase1, iobase2;
420     u16 lcount, lbefore, lafter, count;
421     u8  channel, slave;
422     u8  status, mode, lmode;
423     u32 transfer;
424
425     channel = device / 2;
426     slave = device % 2;
427
428     // Data out is not supported yet
429     if (inout == ATA_DATA_OUT) {
430         BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
431         return 1;
432     }
433
434     // The header length must be even
435     if (header & 1) {
436         BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
437         return 1;
438     }
439
440     iobase1 = GET_EBDA(ata.channels[channel].iobase1);
441     iobase2 = GET_EBDA(ata.channels[channel].iobase2);
442     mode    = GET_EBDA(ata.devices[device].mode);
443     transfer= 0L;
444
445     if (cmdlen < 12)
446         cmdlen=12;
447     if (cmdlen > 12)
448         cmdlen=16;
449     cmdlen>>=1;
450
451     // Reset count of transferred data
452     SET_EBDA(ata.trsfsectors,0);
453     SET_EBDA(ata.trsfbytes,0L);
454
455     status = inb(iobase1 + ATA_CB_STAT);
456     if (status & ATA_CB_STAT_BSY)
457         return 2;
458
459     outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC);
460     outb(0x00, iobase1 + ATA_CB_FR);
461     outb(0x00, iobase1 + ATA_CB_SC);
462     outb(0x00, iobase1 + ATA_CB_SN);
463     outb(0xfff0 & 0x00ff, iobase1 + ATA_CB_CL);
464     outb(0xfff0 >> 8, iobase1 + ATA_CB_CH);
465     outb(slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0, iobase1 + ATA_CB_DH);
466     outb(ATA_CMD_PACKET, iobase1 + ATA_CB_CMD);
467
468     // Device should ok to receive command
469     await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
470     status = inb(iobase1 + ATA_CB_STAT);
471
472     if (status & ATA_CB_STAT_ERR) {
473         BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
474         return 3;
475     } else if ( !(status & ATA_CB_STAT_DRQ) ) {
476         BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n"
477                      , (unsigned) status);
478         return 4;
479     }
480
481     // Normalize address
482     cmdseg += (cmdoff / 16);
483     cmdoff %= 16;
484
485     // Send command to device
486     irq_enable();
487
488     outsw(iobase1, cmdseg, cmdoff, cmdlen);
489
490     if (inout == ATA_DATA_NO) {
491         await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
492         status = inb(iobase1 + ATA_CB_STAT);
493     }
494     else {
495         u16 loops = 0;
496         u8 sc;
497         while (1) {
498
499             if (loops == 0) {//first time through
500                 status = inb(iobase2 + ATA_CB_ASTAT);
501                 await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
502             }
503             else
504                 await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
505             loops++;
506
507             status = inb(iobase1 + ATA_CB_STAT);
508             sc = inb(iobase1 + ATA_CB_SC);
509
510             // Check if command completed
511             if(((inb(iobase1 + ATA_CB_SC)&0x7)==0x3) &&
512                ((status & (ATA_CB_STAT_RDY | ATA_CB_STAT_ERR)) == ATA_CB_STAT_RDY))
513                 break;
514
515             if (status & ATA_CB_STAT_ERR) {
516                 BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
517                 return 3;
518             }
519
520             // Normalize address
521             bufseg += (bufoff / 16);
522             bufoff %= 16;
523
524             // Get the byte count
525             lcount =  ((u16)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
526
527             // adjust to read what we want
528             if(header>lcount) {
529                 lbefore=lcount;
530                 header-=lcount;
531                 lcount=0;
532             }
533             else {
534                 lbefore=header;
535                 header=0;
536                 lcount-=lbefore;
537             }
538
539             if(lcount>length) {
540                 lafter=lcount-length;
541                 lcount=length;
542                 length=0;
543             }
544             else {
545                 lafter=0;
546                 length-=lcount;
547             }
548
549             // Save byte count
550             count = lcount;
551
552             BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) "
553                          ,lbefore+lcount+lafter,lbefore,lcount,lafter);
554             BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
555
556             // If counts not dividable by 4, use 16bits mode
557             lmode = mode;
558             if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
559             if (lcount  & 0x03) lmode=ATA_MODE_PIO16;
560             if (lafter  & 0x03) lmode=ATA_MODE_PIO16;
561
562             // adds an extra byte if count are odd. before is always even
563             if (lcount & 0x01) {
564                 lcount+=1;
565                 if ((lafter > 0) && (lafter & 0x01)) {
566                     lafter-=1;
567                 }
568             }
569
570             if (lmode == ATA_MODE_PIO32) {
571                 lcount>>=2; lbefore>>=2; lafter>>=2;
572             }
573             else {
574                 lcount>>=1; lbefore>>=1; lafter>>=1;
575             }
576
577             int i;
578             for (i=0; i<lbefore; i++)
579                 if (lmode == ATA_MODE_PIO32)
580                     inl(iobase1);
581                 else
582                     inw(iobase1);
583
584             if (lmode == ATA_MODE_PIO32)
585                 insl(iobase1, bufoff, bufseg, lcount);
586             else
587                 insw(iobase1, bufoff, bufseg, lcount);
588
589             for (i=0; i<lafter; i++)
590                 if (lmode == ATA_MODE_PIO32)
591                     inl(iobase1);
592                 else
593                     inw(iobase1);
594
595             // Compute new buffer address
596             bufoff += count;
597
598             // Save transferred bytes count
599             transfer += count;
600             SET_EBDA(ata.trsfbytes,transfer);
601         }
602     }
603
604     // Final check, device must be ready
605     if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF
606                     | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
607          != ATA_CB_STAT_RDY ) {
608         BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n"
609                      , (unsigned) status);
610         return 4;
611     }
612
613     // Enable interrupts
614     outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
615     return 0;
616 }