a bunch of old work on the ide3 driver. doesn't work right, but kind of there.
[newos.git] / kernel / addons / dev / arch / i386 / ide3 / ide_raw.c
blob96e6f7973066d8811f29e3fc9c5f8f4149045063
1 /*
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.
5 **
6 ** With acknowledgements to Hale Landis <hlandis@ibm.net>
7 ** who wrote the reference implementation.
8 */
10 #include <kernel/arch/cpu.h>
11 #include <kernel/sem.h>
12 #include <kernel/debug.h>
14 #include <string.h>
16 #include "ide_private.h"
17 #include "ide_raw.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)
64 __asm__ __volatile__
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)
73 __asm__ __volatile__
75 "rep ; outsw" : "=S" (addr), "=c" (count) : "d" (pio_reg_addrs[port]),
76 "0" (addr), "1" (count)
80 static void ide_reg_poll()
82 while(1)
84 if ((pio_inbyte(CB_ASTAT) & CB_STAT_BSY) == 0)
85 break;
89 static bool ide_wait_busy()
91 int i;
93 for(i=0; i<100000; i++)
95 if((i % 10000) == 0)
96 dprintf("CB_ASTAT = 0x%x\n", pio_inbyte(CB_ASTAT));
97 if ((pio_inbyte(CB_ASTAT) & CB_STAT_BSY) == 0)
98 return true;
100 return false;
103 static int ide_select_device(int bus, int device)
105 uint8 status;
106 int i;
107 ide_device ide = devices[(bus*2) + device];
109 dprintf("0a\n");
110 // test for a known, valid device
111 if(ide.device_type == (NO_DEVICE | UNKNOWN_DEVICE))
112 return NO_ERROR;
113 dprintf("0b\n");
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);
119 DELAY400NS;
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))
128 return NO_ERROR;
129 } else {
130 if ((status & CB_STAT_BSY) == 0)
131 return NO_ERROR;
134 dprintf("0d\n");
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);
146 return;
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))
170 numSect = 1;
171 // multiCnt = 1 unless CMD_READ_MULTIPLE true
172 if(cmd != CMD_READ_MULTIPLE || !multiCnt)
173 multiCnt = 1;
174 // select the drive
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);
187 DELAY400NS;
188 while(1)
190 ide_delay(bus, dev);
191 // ensure drive isn't still busy
192 ide_reg_poll();
193 // check status once only per read
194 status = pio_inbyte(CB_STAT);
195 if((numSect < 1) && (status & CB_STAT_DRQ))
196 return ERR_DEV_BUSY;
197 if (numSect < 1)
198 break;
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);
204 DELAY400NS;
205 numSect = numSect - multiCnt;
206 buffer += wordCnt;
208 // catch all possible fault conditions
209 if(status & CB_STAT_BSY)
210 return ERR_DEV_BUSY;
211 if(status & CB_STAT_DF)
212 return ERR_DEV_BUSY;
213 if(status & CB_STAT_ERR)
214 return ERR_DEV_HARDWARE_ERROR;
215 if((status & CB_STAT_DRQ) == 0)
216 return ERR_DEV_BUSY;
218 return NO_ERROR;
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)
238 numSect = 1;
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))
241 multiCnt = 1;
242 // select the drive
243 if (ide_select_device(bus, dev) != NO_ERROR)
244 return ERR_DEV_TIMED_OUT;
245 dprintf("1\n");
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);
256 DELAY400NS;
257 if (ide_wait_busy() == false)
258 return ERR_DEV_TIMED_OUT;
259 dprintf("2\n");
260 status = pio_inbyte(CB_STAT);
261 while (1)
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);
268 DELAY400NS;
269 numSect = numSect - multiCnt;
270 buffer += wordCnt;
272 dprintf("3 status 0x%x\n", status);
274 // check all possible fault conditions
275 if(status & CB_STAT_BSY)
276 return ERR_DEV_BUSY;
277 if(status & CB_STAT_DF)
278 return ERR_DEV_BUSY;
279 if(status & CB_STAT_ERR)
280 return ERR_DEV_HARDWARE_ERROR;
281 if ((status & CB_STAT_DRQ) == 0)
282 return ERR_DEV_BUSY;
283 ide_delay(bus, dev);
284 // ensure drive isn't still busy
285 ide_reg_poll();
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);
289 return ERR_DEV_BUSY;
292 dprintf("4\n");
293 return NO_ERROR;
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)
316 int cyl, head, sect;
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, &sect);
322 else
323 ata_block_to_chs(sector, device, &cyl, &head, &sect);
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)
331 int cyl, head, sect;
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, &sect);
337 else
338 ata_block_to_chs(sector, device, &cyl, &head, &sect);
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)
346 unsigned int i;
347 int j;
349 for (i=0; i<len/sizeof(unsigned short); i++)
351 char c = str[i*2+1];
352 str[i*2+1] = str[i*2];
353 str[i*2] = c;
356 str[len - 1] = 0;
357 for (j=len-1; j>=0 && str[j]==' '; j--)
358 str[j] = 0;
361 // execute a software reset
362 bool ide_reset(void)
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);
369 DELAY400NS;
370 pio_outbyte(CB_DC, devCtrl);
371 DELAY400NS;
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)
379 int ret = NO_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);
386 DELAY400NS;
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);
400 DELAY400NS;
401 if(ide_reset() == false)
402 dprintf("ide_reset() failed!\n");
403 // re-select device
404 pio_outbyte(CB_DH, device ? CB_DH_DEV1 : CB_DH_DEV0);
405 DELAY400NS;
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))
416 ret = ATAPI_DEVICE;
417 if ((cl == 0x00) && (ch == 0x00) && (st != 0x00))
418 ret = ATA_DEVICE;
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);
438 ide->bus = bus;
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) {
446 case NO_DEVICE:
447 case UNKNOWN_DEVICE:
448 break;
450 case ATAPI_DEVICE:
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);
465 break;
467 case ATA_DEVICE:
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);
494 default:
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
516 #if 0
517 static bool ata_get_partition_info(ide_device *device, tPartition *partition, uint32 position)
519 char buffer[512];
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");
526 return false;
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");
534 return false;
537 memcpy(partition, partitionBuffer + PARTITION_OFFSET, sizeof(tPartition) * NUM_PARTITIONS);
539 return true;
542 bool ata_get_partitions(ide_device *device)
544 uint8 i, j;
546 memset(&device->partitions, 0, sizeof(tPartition) * MAX_PARTITIONS);
547 if(ata_get_partition_info(device, device->partitions, 0) == false)
548 return 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);
567 for(j=0; j<4; j++)
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)
575 return 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);
595 return true;
597 #endif