2 ** Copyright 2001, Travis Geiselbrecht. All rights reserved.
3 ** Copyright 2001-2002, Rob Judd <judd@ob-wan.com>
4 ** Distributed under the terms of the NewOS License.
6 ** With acknowledgements to Hale Landis <hlandis@ibm.net>
7 ** who wrote the reference implementation.
10 #include <kernel/arch/cpu.h>
11 #include <kernel/sem.h>
12 #include <kernel/debug.h>
16 #include "ide_private.h"
20 // Waste some time by reading the alternate status a few times.
21 // This gives the drive time to set BUSY in the status register on
22 // really fast systems. If we don't do this, a slow drive on a fast
23 // system may not set BUSY fast enough and we would think it had
24 // completed the command when it really had not even started yet.
25 #define DELAY400NS { pio_inbyte(CB_ASTAT); pio_inbyte(CB_ASTAT); \
26 pio_inbyte(CB_ASTAT); pio_inbyte(CB_ASTAT); }
28 // Standard ide base addresses. For pc-card (pcmcia) drives, use
29 // unused contiguous address block { 100H < (base1=base2) < 3F0H }
30 // Non-standard addresses also exist. For ATA via sound cards try:
31 // pio_base2 = 168/368, irq 9 or 10
32 // pio_base3 = 1e8/3e8, irq 11 or 12
33 unsigned int pio_base0_addr1
= 0x1f0; // Command block, ide bus 0
34 unsigned int pio_base0_addr2
= 0x3f0; // Control block, ide bus 0
35 unsigned int pio_base1_addr1
= 0x170; // Command block, ide bus 1
36 unsigned int pio_base1_addr2
= 0x370; // Control block, ide bus 1
38 unsigned int pio_memory_seg
= 0;
39 unsigned int pio_reg_addrs
[10];
40 unsigned char pio_last_read
[10];
41 unsigned char pio_last_write
[10];
44 static uint8
pio_inbyte(uint16 port
)
46 // dprintf("inb 0x%x\n", pio_reg_addrs[port]);
47 return in8(pio_reg_addrs
[port
]);
50 static uint16
pio_inword(uint16 port
)
52 // dprintf("inw 0x%x\n", pio_reg_addrs[port]);
53 return in16(pio_reg_addrs
[port
]);
56 static void pio_outbyte(uint16 port
, uint8 data
)
58 // dprintf("outb 0x%x, 0x%x\n", pio_reg_addrs[port], data);
59 out8(data
, pio_reg_addrs
[port
]);
62 static void pio_rep_inword(uint16 port
, uint16
*addr
, unsigned long count
)
66 "rep ; insw" : "=D" (addr
), "=c" (count
) : "d" (pio_reg_addrs
[port
]),
67 "0" (addr
), "1" (count
)
71 static void pio_rep_outword(uint16 port
, uint16
*addr
, unsigned long count
)
75 "rep ; outsw" : "=S" (addr
), "=c" (count
) : "d" (pio_reg_addrs
[port
]),
76 "0" (addr
), "1" (count
)
80 static void ide_reg_poll()
84 if ((pio_inbyte(CB_ASTAT
) & CB_STAT_BSY
) == 0)
89 static bool ide_wait_busy()
93 for(i
=0; i
<100000; i
++)
96 dprintf("CB_ASTAT = 0x%x\n", pio_inbyte(CB_ASTAT
));
97 if ((pio_inbyte(CB_ASTAT
) & CB_STAT_BSY
) == 0)
103 static int ide_select_device(int bus
, int device
)
107 ide_device ide
= devices
[(bus
*2) + device
];
110 // test for a known, valid device
111 if(ide
.device_type
== (NO_DEVICE
| UNKNOWN_DEVICE
))
114 // See if we can get it's attention
115 if(ide_wait_busy() == false)
116 return ERR_DEV_TIMED_OUT
;
117 // Select required device
118 pio_outbyte(CB_DH
, device
? CB_DH_DEV1
: CB_DH_DEV0
);
120 for(i
=0; i
<10000; i
++)
122 // read the device status
123 status
= pio_inbyte(CB_STAT
);
124 dprintf("0c status 0x%x\n", status
);
125 if (ide
.device_type
== ATA_DEVICE
) {
126 if ((status
& (CB_STAT_BSY
| CB_STAT_RDY
| CB_STAT_SKC
))
127 == (CB_STAT_RDY
| CB_STAT_SKC
))
130 if ((status
& CB_STAT_BSY
) == 0)
136 return ERR_DEV_TIMED_OUT
;
139 static void ide_delay(int bus
, int device
)
141 ide_device ide
= devices
[(bus
*2) + device
];
143 if(ide
.device_type
== ATAPI_DEVICE
)
144 thread_snooze(1000000);
149 static int reg_pio_data_in(int bus
, int dev
, int cmd
, int fr
, int sc
,
150 unsigned int cyl
, int head
, int sect
, uint8
*output
,
151 uint16 numSect
, unsigned int multiCnt
)
153 unsigned char devHead
;
154 unsigned char devCtrl
;
155 unsigned char cylLow
;
156 unsigned char cylHigh
;
157 unsigned char status
;
158 uint16
*buffer
= (uint16
*)output
;
160 dprintf("reg_pio_data_in: bus %d dev %d cmd %d fr %d sc %d cyl %d head %d sect %d numSect %d multiCnt %d\n",
161 bus
, dev
, cmd
, fr
, sc
, cyl
, head
, sect
, numSect
, multiCnt
);
163 devCtrl
= CB_DC_HD15
| CB_DC_NIEN
;
164 devHead
= dev
? CB_DH_DEV1
: CB_DH_DEV0
;
165 devHead
= devHead
| (head
& 0x4f);
166 cylLow
= cyl
& 0x00ff;
167 cylHigh
= (cyl
& 0xff00) >> 8;
168 // these commands transfer only 1 sector
169 if(cmd
== (CMD_IDENTIFY_DEVICE
| CMD_IDENTIFY_DEVICE_PACKET
| CMD_READ_BUFFER
))
171 // multiCnt = 1 unless CMD_READ_MULTIPLE true
172 if(cmd
!= CMD_READ_MULTIPLE
|| !multiCnt
)
175 if(ide_select_device(bus
, dev
) == ERR_DEV_TIMED_OUT
)
176 return ERR_DEV_TIMED_OUT
;
177 // set up the registers
178 pio_outbyte(CB_DC
, devCtrl
);
179 pio_outbyte(CB_FR
, fr
);
180 pio_outbyte(CB_SC
, sc
);
181 pio_outbyte(CB_SN
, sect
);
182 pio_outbyte(CB_CL
, cylLow
);
183 pio_outbyte(CB_CH
, cylHigh
);
184 pio_outbyte(CB_DH
, devHead
);
185 // Start the command. The drive should immediately set BUSY status.
186 pio_outbyte(CB_CMD
, cmd
);
191 // ensure drive isn't still busy
193 // check status once only per read
194 status
= pio_inbyte(CB_STAT
);
195 if((numSect
< 1) && (status
& CB_STAT_DRQ
))
199 if((status
& (CB_STAT_BSY
| CB_STAT_DRQ
)) == CB_STAT_DRQ
)
201 unsigned int wordCnt
= multiCnt
> numSect
? numSect
: multiCnt
;
202 wordCnt
= wordCnt
* 256;
203 pio_rep_inword(CB_DATA
, buffer
, wordCnt
);
205 numSect
= numSect
- multiCnt
;
208 // catch all possible fault conditions
209 if(status
& CB_STAT_BSY
)
211 if(status
& CB_STAT_DF
)
213 if(status
& CB_STAT_ERR
)
214 return ERR_DEV_HARDWARE_ERROR
;
215 if((status
& CB_STAT_DRQ
) == 0)
221 static int reg_pio_data_out(int bus
, int dev
, int cmd
, int fr
, int sc
,
222 unsigned int cyl
, int head
, int sect
, const uint8
*output
,
223 uint16 numSect
, unsigned int multiCnt
)
225 unsigned char devHead
;
226 unsigned char devCtrl
;
227 unsigned char cylLow
;
228 unsigned char cylHigh
;
229 unsigned char status
;
230 uint16
*buffer
= (uint16
*)output
;
232 devCtrl
= CB_DC_HD15
| CB_DC_NIEN
;
233 devHead
= dev
? CB_DH_DEV1
: CB_DH_DEV0
;
234 devHead
= devHead
| (head
& 0x4f);
235 cylLow
= cyl
& 0x00ff;
236 cylHigh
= (cyl
& 0xff00) >> 8;
237 if (cmd
== CMD_WRITE_BUFFER
)
239 // only Write Multiple and CFA Write Multiple W/O Erase uses multCnt
240 if ((cmd
!= CMD_WRITE_MULTIPLE
) && (cmd
!= CMD_CFA_WRITE_MULTIPLE_WO_ERASE
))
243 if (ide_select_device(bus
, dev
) != NO_ERROR
)
244 return ERR_DEV_TIMED_OUT
;
246 // set up the registers
247 pio_outbyte(CB_DC
, devCtrl
);
248 pio_outbyte(CB_FR
, fr
);
249 pio_outbyte(CB_SC
, sc
);
250 pio_outbyte(CB_SN
, sect
);
251 pio_outbyte(CB_CL
, cylLow
);
252 pio_outbyte(CB_CH
, cylHigh
);
253 pio_outbyte(CB_DH
, devHead
);
254 // Start the command. The drive should immediately set BUSY status.
255 pio_outbyte(CB_CMD
, cmd
);
257 if (ide_wait_busy() == false)
258 return ERR_DEV_TIMED_OUT
;
260 status
= pio_inbyte(CB_STAT
);
263 if ((status
& (CB_STAT_BSY
| CB_STAT_DRQ
)) == CB_STAT_DRQ
)
265 unsigned int wordCnt
= multiCnt
> numSect
? numSect
: multiCnt
;
266 wordCnt
= wordCnt
* 256;
267 pio_rep_outword(CB_DATA
, buffer
, wordCnt
);
269 numSect
= numSect
- multiCnt
;
272 dprintf("3 status 0x%x\n", status
);
274 // check all possible fault conditions
275 if(status
& CB_STAT_BSY
)
277 if(status
& CB_STAT_DF
)
279 if(status
& CB_STAT_ERR
)
280 return ERR_DEV_HARDWARE_ERROR
;
281 if ((status
& CB_STAT_DRQ
) == 0)
284 // ensure drive isn't still busy
286 if(numSect
< 1 && status
& (CB_STAT_BSY
| CB_STAT_DF
| CB_STAT_ERR
))
288 dprintf("reg_pio_data_out(): status = 0x%x\n", status
);
296 static void ata_block_to_chs(uint32 block
, ide_device
*device
, int *cylinder
, int *head
, int *sect
)
298 *sect
= (block
% device
->hardware_device
.sectors
) + 1;
299 block
/= device
->hardware_device
.sectors
;
300 *head
= (block
% device
->hardware_device
.heads
);
301 block
/= device
->hardware_device
.heads
;
302 *cylinder
= block
& 0xFFFF;
303 dprintf("ata_block_to_chs(): block %d -> cyl %d head %d sect %d\n", block
, *cylinder
, *head
, *sect
);
306 static void ata_block_to_lba(uint32 block
, ide_device
*device
, int *cylinder
, int *head
, int *sect
)
308 *sect
= block
& 0xFF;
309 *cylinder
= (block
>> 8) & 0xFFFF;
310 *head
= ((block
>> 24) & 0xF) | CB_DH_LBA
;
311 dprintf("ata_block_to_lba(): block %d -> cyl %d head %d sect %d\n", block
, *cylinder
, *head
, *sect
);
314 int ata_read_sector(ide_device
*device
, char *data
, uint32 sector
, uint16 numSectors
)
318 dprintf("ata_read_sector: dev %p, data %p, block 0x%x, sectors 0x%x\n", device
, data
, sector
, numSectors
);
320 if(device
->lba_supported
)
321 ata_block_to_lba(sector
, device
, &cyl
, &head
, §
);
323 ata_block_to_chs(sector
, device
, &cyl
, &head
, §
);
325 return reg_pio_data_in(device
->bus
, device
->device
, CMD_READ_SECTORS
,
326 0, numSectors
, cyl
, head
, sect
, data
, numSectors
, 2);
329 int ata_write_sector(ide_device
*device
, const char *data
, uint32 sector
, uint16 numSectors
)
333 dprintf("ata_write_sector: dev %p, data %p, block 0x%x, sectors 0x%x\n", device
, data
, sector
, numSectors
);
335 if(device
->lba_supported
)
336 ata_block_to_lba(sector
, device
, &cyl
, &head
, §
);
338 ata_block_to_chs(sector
, device
, &cyl
, &head
, §
);
340 return reg_pio_data_out(device
->bus
, device
->device
, CMD_WRITE_SECTORS
,
341 0, numSectors
, cyl
, head
, sect
, data
, numSectors
, 2);
344 static void ide_string_conv(char *str
, int len
)
349 for (i
=0; i
<len
/sizeof(unsigned short); i
++)
352 str
[i
*2+1] = str
[i
*2];
357 for (j
=len
-1; j
>=0 && str
[j
]==' '; j
--)
361 // execute a software reset
364 unsigned char devCtrl
= CB_DC_HD15
| CB_DC_NIEN
;
366 // Set and then reset the soft reset bit in the Device
367 // Control register. This causes device 0 be selected
368 pio_outbyte(CB_DC
, devCtrl
| CB_DC_SRST
);
370 pio_outbyte(CB_DC
, devCtrl
);
373 return (ide_wait_busy() ? true : false);
376 // check devices actually exist on bus, and if so what type
377 static uint8
ide_drive_present(int bus
, int device
)
380 unsigned char devCtrl
= CB_DC_HD15
| CB_DC_NIEN
;
381 uint8 sc
, sn
, ch
=0, cl
=0, st
=0;
383 // set up the device control register
384 pio_outbyte(CB_DC
, devCtrl
);
385 pio_outbyte(CB_DH
, device
? CB_DH_DEV1
: CB_DH_DEV0
);
387 pio_outbyte(CB_SC
, 0x55);
388 pio_outbyte(CB_SN
, 0xaa);
389 pio_outbyte(CB_SC
, 0xaa);
390 pio_outbyte(CB_SN
, 0x55);
391 pio_outbyte(CB_SC
, 0x55);
392 pio_outbyte(CB_SN
, 0xaa);
393 sc
= pio_inbyte(CB_SC
);
394 sn
= pio_inbyte(CB_SN
);
395 // ensure a device exists
396 if(sc
== 0x55 && sn
== 0xaa)
397 ret
= UNKNOWN_DEVICE
;
398 // issue a soft bus reset
399 pio_outbyte(CB_DH
, CB_DH_DEV0
);
401 if(ide_reset() == false)
402 dprintf("ide_reset() failed!\n");
404 pio_outbyte(CB_DH
, device
? CB_DH_DEV1
: CB_DH_DEV0
);
406 // test for type of device
407 sc
= pio_inbyte(CB_SC
);
408 sn
= pio_inbyte(CB_SN
);
409 if((sc
== 0x01) && (sn
== 0x01))
411 ret
= UNKNOWN_DEVICE
;
412 cl
= pio_inbyte(CB_CL
);
413 ch
= pio_inbyte(CB_CH
);
414 st
= pio_inbyte(CB_STAT
);
415 if ((cl
== 0x14) && (ch
== 0xeb))
417 if ((cl
== 0x00) && (ch
== 0x00) && (st
!= 0x00))
421 dprintf("ide_drive_present: sector count = %d, sector number = %d, "
422 "cl = %x, ch = %x, st = %x, return = %d\n", sc
, sn
, cl
, ch
, st
, ret
);
424 return (ret
? ret
: NO_DEVICE
);
427 uint8
ata_cmd(int bus
, int device
, int cmd
, uint8
* buffer
)
429 return reg_pio_data_in(bus
, device
, cmd
, 1, 0, 0, 0, 0, buffer
, 1, 0);
432 uint8
ide_identify_device(int bus
, int device
)
434 uint8
*buffer
= NULL
;
435 ide_device
*ide
= &devices
[(bus
*2) + device
];
437 ide
->device_type
= ide_drive_present(bus
, device
);
439 ide
->device
= device
;
441 // dprintf("ide_identify_device: type %d, bus %d, device %d\n",
442 // ide->device_type, bus, device);
444 switch (ide
->device_type
) {
451 // try for more debug data with optional `identify' command
452 buffer
= (uint8
*)&ide
->hardware_device
;
453 if(ata_cmd(bus
, device
, CMD_IDENTIFY_DEVICE_PACKET
, buffer
) == NO_ERROR
)
455 ide_string_conv(ide
->hardware_device
.model
, 40);
456 ide_string_conv(ide
->hardware_device
.serial
, 20);
457 ide_string_conv(ide
->hardware_device
.firmware
, 8);
459 dprintf("ide: cd-rom at bus %d, device %d, model = %s\n", bus
, device
,
460 ide
->hardware_device
.model
);
461 dprintf("ide: cd-rom serial number = %s firmware revision = %s\n",
462 ide
->hardware_device
.serial
, ide
->hardware_device
.firmware
);
468 // try for more debug data with optional `identify' command
469 buffer
= (uint8
*)&ide
->hardware_device
;
470 if(ata_cmd(bus
, device
, CMD_IDENTIFY_DEVICE
, buffer
) == NO_ERROR
) {
471 ide
->device_type
= ATA_DEVICE
;
472 ide_string_conv(ide
->hardware_device
.model
, 40);
473 ide_string_conv(ide
->hardware_device
.serial
, 20);
474 ide_string_conv(ide
->hardware_device
.firmware
, 8);
475 ide
->sector_count
= ide
->hardware_device
.curr_cyls
476 * ide
->hardware_device
.curr_heads
477 * ide
->hardware_device
.curr_sectors
;
478 ide
->bytes_per_sector
= 512;
479 ide
->lba_supported
= ide
->hardware_device
.capabilities
& DRIVE_SUPPORT_LBA
;
480 ide
->start_block
= 0;
481 ide
->end_block
= ide
->sector_count
; // - ide->start_block;
483 dprintf("ide %p: disk at bus %d, device %d, model = %s\n",
484 ide
, bus
, device
, ide
->hardware_device
.model
);
485 dprintf("ide: disk serial number = %s firmware revision = %s\n",
486 ide
->hardware_device
.serial
, ide
->hardware_device
.firmware
);
487 dprintf("ide/%d/%d: %dMB; %d cyl, %d head, %d sec, %d bytes/sec (LBA=%d)\n",
488 bus
, device
, ide
->sector_count
* ide
->bytes_per_sector
/ (1000 * 1000),
489 ide
->hardware_device
.curr_cyls
, ide
->hardware_device
.curr_heads
,
490 ide
->hardware_device
.curr_sectors
, ide
->bytes_per_sector
, ide
->lba_supported
);
497 return (ide
->device_type
);
500 // set the pio base addresses
501 void ide_raw_init(unsigned int base1
, unsigned int base2
)
503 pio_reg_addrs
[CB_DATA
] = base1
+ 0; // 0
504 pio_reg_addrs
[CB_FR
] = base1
+ 1; // 1
505 pio_reg_addrs
[CB_SC
] = base1
+ 2; // 2
506 pio_reg_addrs
[CB_SN
] = base1
+ 3; // 3
507 pio_reg_addrs
[CB_CL
] = base1
+ 4; // 4
508 pio_reg_addrs
[CB_CH
] = base1
+ 5; // 5
509 pio_reg_addrs
[CB_DH
] = base1
+ 6; // 6
510 pio_reg_addrs
[CB_CMD
] = base1
+ 7; // 7
512 pio_reg_addrs
[CB_DC
] = base2
+ 6; // 8
513 pio_reg_addrs
[CB_DA
] = base2
+ 7; // 9
517 static bool ata_get_partition_info(ide_device
*device
, tPartition
*partition
, uint32 position
)
520 uint8
* partitionBuffer
= buffer
;
522 if (ata_read_sector(device
, buffer
, position
, 1) != NO_ERROR
) {
524 dprintf("ata_get_partition_info(): unable to read partition table\n");
529 if ((partitionBuffer
[PART_IDENT_OFFSET
] != 0x55) ||
530 (partitionBuffer
[PART_IDENT_OFFSET
+1] != 0xaa)) {
532 dprintf("ata_get_partition_info(): partition table signature is incorrect\n");
537 memcpy(partition
, partitionBuffer
+ PARTITION_OFFSET
, sizeof(tPartition
) * NUM_PARTITIONS
);
542 bool ata_get_partitions(ide_device
*device
)
546 memset(&device
->partitions
, 0, sizeof(tPartition
) * MAX_PARTITIONS
);
547 if(ata_get_partition_info(device
, device
->partitions
, 0) == false)
550 dprintf("Primary Partition Table\n");
551 for (i
= 0; i
< NUM_PARTITIONS
; i
++)
553 dprintf(" %d: flags:%x type:%x start:cy%d hd%d sc%d end:cy%d hd%d sc%d lba:%d len:%d\n",
555 device
->partitions
[i
].boot_flags
,
556 device
->partitions
[i
].partition_type
,
557 device
->partitions
[i
].starting_cylinder
,
558 device
->partitions
[i
].starting_head
,
559 device
->partitions
[i
].starting_sector
,
560 device
->partitions
[i
].ending_cylinder
,
561 device
->partitions
[i
].ending_head
,
562 device
->partitions
[i
].ending_sector
,
563 device
->partitions
[i
].starting_block
,
564 device
->partitions
[i
].sector_count
);
569 if((device
->partitions
[j
].partition_type
== PTDosExtended
) ||
570 (device
->partitions
[j
].partition_type
== PTWin95ExtendedLBA
) ||
571 (device
->partitions
[j
].partition_type
== PTLinuxExtended
))
573 int extOffset
= device
->partitions
[j
].starting_block
;
574 if(ata_get_partition_info(device
, &device
->partitions
[4], extOffset
) == false)
576 dprintf("Extended Partition Table\n");
577 for (i
=NUM_PARTITIONS
; i
<MAX_PARTITIONS
; i
++)
579 device
->partitions
[i
].starting_block
+= extOffset
;
580 dprintf(" %d: flags:%x type:%x start:cy%d hd%d sc%d end:cy%d hd%d sc%d lba:%d len:%d\n",
582 device
->partitions
[i
].boot_flags
,
583 device
->partitions
[i
].partition_type
,
584 device
->partitions
[i
].starting_cylinder
,
585 device
->partitions
[i
].starting_head
,
586 device
->partitions
[i
].starting_sector
,
587 device
->partitions
[i
].ending_cylinder
,
588 device
->partitions
[i
].ending_head
,
589 device
->partitions
[i
].ending_sector
,
590 device
->partitions
[i
].starting_block
,
591 device
->partitions
[i
].sector_count
);