2009-06-21 Robert Millan <rmh.grub@aybabtu.com>
[grub2/phcoder/solaris.git] / disk / ata.c
blob78d396526c757206e01a8686e035874ca116b32a
1 /* ata.c - ATA disk access. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/ata.h>
21 #include <grub/dl.h>
22 #include <grub/disk.h>
23 #include <grub/mm.h>
24 #include <grub/time.h>
25 #include <grub/pci.h>
26 #include <grub/scsi.h>
28 /* At the moment, only two IDE ports are supported. */
29 static const int grub_ata_ioaddress[] = { 0x1f0, 0x170 };
30 static const int grub_ata_ioaddress2[] = { 0x3f6, 0x376 };
32 static struct grub_ata_device *grub_ata_devices;
34 /* Wait for !BSY. */
35 grub_err_t
36 grub_ata_wait_not_busy (struct grub_ata_device *dev, int milliseconds)
38 /* ATA requires 400ns (after a write to CMD register) or
39 1 PIO cycle (after a DRQ block transfer) before
40 first check of BSY. */
41 grub_millisleep (1);
43 int i = 1;
44 grub_uint8_t sts;
45 while ((sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS))
46 & GRUB_ATA_STATUS_BUSY)
48 if (i >= milliseconds)
50 grub_dprintf ("ata", "timeout: %dms, status=0x%x\n",
51 milliseconds, sts);
52 return grub_error (GRUB_ERR_TIMEOUT, "ATA timeout");
55 grub_millisleep (1);
56 i++;
59 return GRUB_ERR_NONE;
62 static inline void
63 grub_ata_wait (void)
65 grub_millisleep (50);
68 /* Wait for !BSY, DRQ. */
69 grub_err_t
70 grub_ata_wait_drq (struct grub_ata_device *dev, int rw,
71 int milliseconds)
73 if (grub_ata_wait_not_busy (dev, milliseconds))
74 return grub_errno;
76 /* !DRQ implies error condition. */
77 grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
78 if ((sts & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
79 != GRUB_ATA_STATUS_DRQ)
81 grub_dprintf ("ata", "ata error: status=0x%x, error=0x%x\n",
82 sts, grub_ata_regget (dev, GRUB_ATA_REG_ERROR));
83 if (! rw)
84 return grub_error (GRUB_ERR_READ_ERROR, "ATA read error");
85 else
86 return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error");
89 return GRUB_ERR_NONE;
92 /* Byteorder has to be changed before strings can be read. */
93 static void
94 grub_ata_strncpy (char *dst, char *src, grub_size_t len)
96 grub_uint16_t *src16 = (grub_uint16_t *) src;
97 grub_uint16_t *dst16 = (grub_uint16_t *) dst;
98 unsigned int i;
100 for (i = 0; i < len / 2; i++)
101 *(dst16++) = grub_be_to_cpu16 (*(src16++));
102 dst[len] = '\0';
105 void
106 grub_ata_pio_read (struct grub_ata_device *dev, char *buf, grub_size_t size)
108 grub_uint16_t *buf16 = (grub_uint16_t *) buf;
109 unsigned int i;
111 /* Read in the data, word by word. */
112 for (i = 0; i < size / 2; i++)
113 buf16[i] = grub_le_to_cpu16 (grub_inw(dev->ioaddress + GRUB_ATA_REG_DATA));
116 static void
117 grub_ata_pio_write (struct grub_ata_device *dev, char *buf, grub_size_t size)
119 grub_uint16_t *buf16 = (grub_uint16_t *) buf;
120 unsigned int i;
122 /* Write the data, word by word. */
123 for (i = 0; i < size / 2; i++)
124 grub_outw(grub_cpu_to_le16 (buf16[i]), dev->ioaddress + GRUB_ATA_REG_DATA);
127 static void
128 grub_ata_dumpinfo (struct grub_ata_device *dev, char *info)
130 char text[41];
132 /* The device information was read, dump it for debugging. */
133 grub_ata_strncpy (text, info + 20, 20);
134 grub_dprintf ("ata", "Serial: %s\n", text);
135 grub_ata_strncpy (text, info + 46, 8);
136 grub_dprintf ("ata", "Firmware: %s\n", text);
137 grub_ata_strncpy (text, info + 54, 40);
138 grub_dprintf ("ata", "Model: %s\n", text);
140 if (! dev->atapi)
142 grub_dprintf ("ata", "Addressing: %d\n", dev->addr);
143 grub_dprintf ("ata", "Sectors: %lld\n", dev->size);
147 static grub_err_t
148 grub_atapi_identify (struct grub_ata_device *dev)
150 char *info;
152 info = grub_malloc (GRUB_DISK_SECTOR_SIZE);
153 if (! info)
154 return grub_errno;
156 grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
157 grub_ata_wait ();
158 if (grub_ata_check_ready (dev))
160 grub_free (info);
161 return grub_errno;
164 grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE);
165 grub_ata_wait ();
167 if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD))
169 grub_free (info);
170 return grub_errno;
172 grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE);
174 dev->atapi = 1;
176 grub_ata_dumpinfo (dev, info);
178 grub_free (info);
180 return GRUB_ERR_NONE;
183 static grub_err_t
184 grub_atapi_wait_drq (struct grub_ata_device *dev,
185 grub_uint8_t ireason,
186 int milliseconds)
188 /* Wait for !BSY, DRQ, ireason */
189 if (grub_ata_wait_not_busy (dev, milliseconds))
190 return grub_errno;
192 grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
193 grub_uint8_t irs = grub_ata_regget (dev, GRUB_ATAPI_REG_IREASON);
195 /* OK if DRQ is asserted and interrupt reason is as expected. */
196 if ((sts & GRUB_ATA_STATUS_DRQ)
197 && (irs & GRUB_ATAPI_IREASON_MASK) == ireason)
198 return GRUB_ERR_NONE;
200 /* !DRQ implies error condition. */
201 grub_dprintf ("ata", "atapi error: status=0x%x, ireason=0x%x, error=0x%x\n",
202 sts, irs, grub_ata_regget (dev, GRUB_ATA_REG_ERROR));
204 if (! (sts & GRUB_ATA_STATUS_DRQ)
205 && (irs & GRUB_ATAPI_IREASON_MASK) == GRUB_ATAPI_IREASON_ERROR)
207 if (ireason == GRUB_ATAPI_IREASON_CMD_OUT)
208 return grub_error (GRUB_ERR_READ_ERROR, "ATA PACKET command error");
209 else
210 return grub_error (GRUB_ERR_READ_ERROR, "ATAPI read error");
213 return grub_error (GRUB_ERR_READ_ERROR, "ATAPI protocol error");
216 static grub_err_t
217 grub_atapi_packet (struct grub_ata_device *dev, char *packet,
218 grub_size_t size)
220 grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
221 if (grub_ata_check_ready (dev))
222 return grub_errno;
224 /* Send ATA PACKET command. */
225 grub_ata_regset (dev, GRUB_ATA_REG_FEATURES, 0);
226 grub_ata_regset (dev, GRUB_ATAPI_REG_IREASON, 0);
227 grub_ata_regset (dev, GRUB_ATAPI_REG_CNTHIGH, size >> 8);
228 grub_ata_regset (dev, GRUB_ATAPI_REG_CNTLOW, size & 0xFF);
230 grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_PACKET);
232 /* Wait for !BSY, DRQ, !I/O, C/D. */
233 if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_CMD_OUT, GRUB_ATA_TOUT_STD))
234 return grub_errno;
236 /* Write the packet. */
237 grub_ata_pio_write (dev, packet, 12);
239 return GRUB_ERR_NONE;
242 static grub_err_t
243 grub_ata_identify (struct grub_ata_device *dev)
245 char *info;
246 grub_uint16_t *info16;
248 info = grub_malloc (GRUB_DISK_SECTOR_SIZE);
249 if (! info)
250 return grub_errno;
252 info16 = (grub_uint16_t *) info;
254 grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
255 grub_ata_wait ();
256 if (grub_ata_check_ready (dev))
258 grub_free (info);
259 return grub_errno;
262 grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_DEVICE);
263 grub_ata_wait ();
265 if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD))
267 grub_free (info);
268 grub_errno = GRUB_ERR_NONE;
269 grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
271 if ((sts & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ
272 | GRUB_ATA_STATUS_ERR)) == GRUB_ATA_STATUS_ERR
273 && (grub_ata_regget (dev, GRUB_ATA_REG_ERROR) & 0x04 /* ABRT */))
274 /* Device without ATA IDENTIFY, try ATAPI. */
275 return grub_atapi_identify (dev);
277 else if (sts == 0x00)
278 /* No device, return error but don't print message. */
279 return GRUB_ERR_UNKNOWN_DEVICE;
281 else
282 /* Other Error. */
283 return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
284 "device can not be identified");
287 grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE);
289 /* Re-check status to avoid bogus identify data due to stuck DRQ. */
290 grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
291 if (sts & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
293 grub_dprintf ("ata", "bad status=0x%x\n", sts);
294 grub_free (info);
295 /* No device, return error but don't print message. */
296 grub_errno = GRUB_ERR_NONE;
297 return GRUB_ERR_UNKNOWN_DEVICE;
300 /* Now it is certain that this is not an ATAPI device. */
301 dev->atapi = 0;
303 /* CHS is always supported. */
304 dev->addr = GRUB_ATA_CHS;
306 /* Check if LBA is supported. */
307 if (info16[49] & (1 << 9))
309 /* Check if LBA48 is supported. */
310 if (info16[83] & (1 << 10))
311 dev->addr = GRUB_ATA_LBA48;
312 else
313 dev->addr = GRUB_ATA_LBA;
316 /* Determine the amount of sectors. */
317 if (dev->addr != GRUB_ATA_LBA48)
318 dev->size = grub_le_to_cpu32(*((grub_uint32_t *) &info16[60]));
319 else
320 dev->size = grub_le_to_cpu64(*((grub_uint64_t *) &info16[100]));
322 /* Read CHS information. */
323 dev->cylinders = info16[1];
324 dev->heads = info16[3];
325 dev->sectors_per_track = info16[6];
327 grub_ata_dumpinfo (dev, info);
329 grub_free(info);
331 return 0;
334 static grub_err_t
335 grub_ata_device_initialize (int port, int device, int addr, int addr2)
337 struct grub_ata_device *dev;
338 struct grub_ata_device **devp;
340 grub_dprintf ("ata", "detecting device %d,%d (0x%x, 0x%x)\n",
341 port, device, addr, addr2);
343 dev = grub_malloc (sizeof(*dev));
344 if (! dev)
345 return grub_errno;
347 /* Setup the device information. */
348 dev->port = port;
349 dev->device = device;
350 dev->ioaddress = addr;
351 dev->ioaddress2 = addr2;
352 dev->next = NULL;
354 grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
355 grub_ata_wait ();
357 /* Try to detect if the port is in use by writing to it,
358 waiting for a while and reading it again. If the value
359 was preserved, there is a device connected. */
360 grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A);
361 grub_ata_wait ();
362 grub_uint8_t sec = grub_ata_regget (dev, GRUB_ATA_REG_SECTORS);
363 grub_dprintf ("ata", "sectors=0x%x\n", sec);
364 if (sec != 0x5A)
366 grub_free(dev);
367 return 0;
370 /* The above test may detect a second (slave) device
371 connected to a SATA controller which supports only one
372 (master) device. It is not safe to use the status register
373 READY bit to check for controller channel existence. Some
374 ATAPI commands (RESET, DIAGNOSTIC) may clear this bit. */
376 /* Use the IDENTIFY DEVICE command to query the device. */
377 if (grub_ata_identify (dev))
379 grub_free (dev);
380 return 0;
383 /* Register the device. */
384 for (devp = &grub_ata_devices; *devp; devp = &(*devp)->next);
385 *devp = dev;
387 return 0;
390 static int NESTED_FUNC_ATTR
391 grub_ata_pciinit (int bus, int device, int func,
392 grub_pci_id_t pciid __attribute__((unused)))
394 static int compat_use[2] = { 0 };
395 grub_pci_address_t addr;
396 grub_uint32_t class;
397 grub_uint32_t bar1;
398 grub_uint32_t bar2;
399 int rega;
400 int regb;
401 int i;
402 static int controller = 0;
404 /* Read class. */
405 addr = grub_pci_make_address (bus, device, func, 2);
406 class = grub_pci_read (addr);
408 /* Check if this class ID matches that of a PCI IDE Controller. */
409 if (class >> 16 != 0x0101)
410 return 0;
412 for (i = 0; i < 2; i++)
414 /* Set to 0 when the channel operated in compatibility mode. */
415 int compat = (class >> (8 + 2 * i)) & 1;
417 rega = 0;
418 regb = 0;
420 /* If the channel is in compatibility mode, just assign the
421 default registers. */
422 if (compat == 0 && !compat_use[i])
424 rega = grub_ata_ioaddress[i];
425 regb = grub_ata_ioaddress2[i];
426 compat_use[i] = 1;
428 else if (compat)
430 /* Read the BARs, which either contain a mmapped IO address
431 or the IO port address. */
432 addr = grub_pci_make_address (bus, device, func, 4 + 2 * i);
433 bar1 = grub_pci_read (addr);
434 addr = grub_pci_make_address (bus, device, func, 5 + 2 * i);
435 bar2 = grub_pci_read (addr);
437 /* Check if the BARs describe an IO region. */
438 if ((bar1 & 1) && (bar2 & 1))
440 rega = bar1 & ~3;
441 regb = bar2 & ~3;
445 grub_dprintf ("ata",
446 "PCI dev (%d,%d,%d) compat=%d rega=0x%x regb=0x%x\n",
447 bus, device, func, compat, rega, regb);
449 if (rega && regb)
451 grub_errno = GRUB_ERR_NONE;
452 grub_ata_device_initialize (controller * 2 + i, 0, rega, regb);
454 /* Most errors raised by grub_ata_device_initialize() are harmless.
455 They just indicate this particular drive is not responding, most
456 likely because it doesn't exist. We might want to ignore specific
457 error types here, instead of printing them. */
458 if (grub_errno)
460 grub_print_error ();
461 grub_errno = GRUB_ERR_NONE;
464 grub_ata_device_initialize (controller * 2 + i, 1, rega, regb);
466 /* Likewise. */
467 if (grub_errno)
469 grub_print_error ();
470 grub_errno = GRUB_ERR_NONE;
475 controller++;
477 return 0;
480 static grub_err_t
481 grub_ata_initialize (void)
483 grub_pci_iterate (grub_ata_pciinit);
484 return 0;
488 static void
489 grub_ata_setlba (struct grub_ata_device *dev, grub_disk_addr_t sector,
490 grub_size_t size)
492 grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, size);
493 grub_ata_regset (dev, GRUB_ATA_REG_LBALOW, sector & 0xFF);
494 grub_ata_regset (dev, GRUB_ATA_REG_LBAMID, (sector >> 8) & 0xFF);
495 grub_ata_regset (dev, GRUB_ATA_REG_LBAHIGH, (sector >> 16) & 0xFF);
498 static grub_err_t
499 grub_ata_setaddress (struct grub_ata_device *dev,
500 grub_ata_addressing_t addressing,
501 grub_disk_addr_t sector,
502 grub_size_t size)
504 switch (addressing)
506 case GRUB_ATA_CHS:
508 unsigned int cylinder;
509 unsigned int head;
510 unsigned int sect;
512 /* Calculate the sector, cylinder and head to use. */
513 sect = ((grub_uint32_t) sector % dev->sectors_per_track) + 1;
514 cylinder = (((grub_uint32_t) sector / dev->sectors_per_track)
515 / dev->heads);
516 head = ((grub_uint32_t) sector / dev->sectors_per_track) % dev->heads;
518 if (sect > dev->sectors_per_track
519 || cylinder > dev->cylinders
520 || head > dev->heads)
521 return grub_error (GRUB_ERR_OUT_OF_RANGE,
522 "sector %d can not be addressed "
523 "using CHS addressing", sector);
525 grub_ata_regset (dev, GRUB_ATA_REG_DISK, (dev->device << 4) | head);
526 if (grub_ata_check_ready (dev))
527 return grub_errno;
529 grub_ata_regset (dev, GRUB_ATA_REG_SECTNUM, sect);
530 grub_ata_regset (dev, GRUB_ATA_REG_CYLLSB, cylinder & 0xFF);
531 grub_ata_regset (dev, GRUB_ATA_REG_CYLMSB, cylinder >> 8);
533 break;
536 case GRUB_ATA_LBA:
537 if (size == 256)
538 size = 0;
539 grub_ata_regset (dev, GRUB_ATA_REG_DISK,
540 0xE0 | (dev->device << 4) | ((sector >> 24) & 0x0F));
541 if (grub_ata_check_ready (dev))
542 return grub_errno;
544 grub_ata_setlba (dev, sector, size);
545 break;
547 case GRUB_ATA_LBA48:
548 if (size == 65536)
549 size = 0;
551 grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | (dev->device << 4));
552 if (grub_ata_check_ready (dev))
553 return grub_errno;
555 /* Set "Previous". */
556 grub_ata_setlba (dev, sector >> 24, size >> 8);
557 /* Set "Current". */
558 grub_ata_setlba (dev, sector, size);
560 break;
563 return GRUB_ERR_NONE;
566 static grub_err_t
567 grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector,
568 grub_size_t size, char *buf, int rw)
570 struct grub_ata_device *dev = (struct grub_ata_device *) disk->data;
572 grub_dprintf("ata", "grub_ata_readwrite (size=%u, rw=%d)\n", size, rw);
574 grub_ata_addressing_t addressing = dev->addr;
575 grub_size_t batch;
576 int cmd, cmd_write;
578 if (addressing == GRUB_ATA_LBA48 && ((sector + size) >> 28) != 0)
580 batch = 65536;
581 cmd = GRUB_ATA_CMD_READ_SECTORS_EXT;
582 cmd_write = GRUB_ATA_CMD_WRITE_SECTORS_EXT;
584 else
586 if (addressing == GRUB_ATA_LBA48)
587 addressing = GRUB_ATA_LBA;
588 batch = 256;
589 cmd = GRUB_ATA_CMD_READ_SECTORS;
590 cmd_write = GRUB_ATA_CMD_WRITE_SECTORS;
593 grub_size_t nsectors = 0;
594 while (nsectors < size)
596 if (size - nsectors < batch)
597 batch = size - nsectors;
599 grub_dprintf("ata", "rw=%d, sector=%llu, batch=%u\n", rw, sector, batch);
601 /* Send read/write command. */
602 if (grub_ata_setaddress (dev, addressing, sector, batch))
603 return grub_errno;
605 grub_ata_regset (dev, GRUB_ATA_REG_CMD, (! rw ? cmd : cmd_write));
607 unsigned sect;
608 for (sect = 0; sect < batch; sect++)
610 /* Wait for !BSY, DRQ. */
611 if (grub_ata_wait_drq (dev, rw, GRUB_ATA_TOUT_DATA))
612 return grub_errno;
614 /* Transfer data. */
615 if (! rw)
616 grub_ata_pio_read (dev, buf, GRUB_DISK_SECTOR_SIZE);
617 else
618 grub_ata_pio_write (dev, buf, GRUB_DISK_SECTOR_SIZE);
620 buf += GRUB_DISK_SECTOR_SIZE;
623 if (rw)
625 /* Check for write error. */
626 if (grub_ata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA))
627 return grub_errno;
629 if (grub_ata_regget (dev, GRUB_ATA_REG_STATUS)
630 & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
631 return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error");
634 sector += batch;
635 nsectors += batch;
638 return GRUB_ERR_NONE;
643 static int
644 grub_ata_iterate (int (*hook) (const char *name))
646 struct grub_ata_device *dev;
648 for (dev = grub_ata_devices; dev; dev = dev->next)
650 char devname[5];
651 grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
653 if (dev->atapi)
654 continue;
656 if (hook (devname))
657 return 1;
660 return 0;
663 static grub_err_t
664 grub_ata_open (const char *name, grub_disk_t disk)
666 struct grub_ata_device *dev;
668 for (dev = grub_ata_devices; dev; dev = dev->next)
670 char devname[5];
671 grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
672 if (grub_strcmp (name, devname) == 0)
673 break;
676 if (! dev)
677 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device");
679 if (dev->atapi)
680 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk");
682 disk->total_sectors = dev->size;
684 disk->id = (unsigned long) dev;
686 disk->has_partitions = 1;
687 disk->data = dev;
689 return 0;
692 static void
693 grub_ata_close (grub_disk_t disk __attribute__((unused)))
698 static grub_err_t
699 grub_ata_read (grub_disk_t disk, grub_disk_addr_t sector,
700 grub_size_t size, char *buf)
702 return grub_ata_readwrite (disk, sector, size, buf, 0);
705 static grub_err_t
706 grub_ata_write (grub_disk_t disk,
707 grub_disk_addr_t sector,
708 grub_size_t size,
709 const char *buf)
711 return grub_ata_readwrite (disk, sector, size, (char *) buf, 1);
714 static struct grub_disk_dev grub_atadisk_dev =
716 .name = "ATA",
717 .id = GRUB_DISK_DEVICE_ATA_ID,
718 .iterate = grub_ata_iterate,
719 .open = grub_ata_open,
720 .close = grub_ata_close,
721 .read = grub_ata_read,
722 .write = grub_ata_write,
723 .next = 0
728 /* ATAPI code. */
730 static int
731 grub_atapi_iterate (int (*hook) (const char *name, int luns))
733 struct grub_ata_device *dev;
735 for (dev = grub_ata_devices; dev; dev = dev->next)
737 char devname[7];
738 grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
740 if (! dev->atapi)
741 continue;
743 if (hook (devname, 1))
744 return 1;
747 return 0;
751 static grub_err_t
752 grub_atapi_read (struct grub_scsi *scsi,
753 grub_size_t cmdsize __attribute__((unused)),
754 char *cmd, grub_size_t size, char *buf)
756 struct grub_ata_device *dev = (struct grub_ata_device *) scsi->data;
758 grub_dprintf("ata", "grub_atapi_read (size=%u)\n", size);
760 if (grub_atapi_packet (dev, cmd, size))
761 return grub_errno;
763 grub_size_t nread = 0;
764 while (nread < size)
766 /* Wait for !BSY, DRQ, I/O, !C/D. */
767 if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_DATA_IN, GRUB_ATA_TOUT_DATA))
768 return grub_errno;
770 /* Get byte count for this DRQ assertion. */
771 unsigned cnt = grub_ata_regget (dev, GRUB_ATAPI_REG_CNTHIGH) << 8
772 | grub_ata_regget (dev, GRUB_ATAPI_REG_CNTLOW);
773 grub_dprintf("ata", "DRQ count=%u\n", cnt);
775 /* Count of last transfer may be uneven. */
776 if (! (0 < cnt && cnt <= size - nread && (! (cnt & 1) || cnt == size - nread)))
777 return grub_error (GRUB_ERR_READ_ERROR, "Invalid ATAPI transfer count");
779 /* Read the data. */
780 grub_ata_pio_read (dev, buf + nread, cnt);
782 if (cnt & 1)
783 buf[nread + cnt - 1] = (char) grub_le_to_cpu16 (grub_inw (dev->ioaddress + GRUB_ATA_REG_DATA));
785 nread += cnt;
788 return GRUB_ERR_NONE;
791 static grub_err_t
792 grub_atapi_write (struct grub_scsi *scsi __attribute__((unused)),
793 grub_size_t cmdsize __attribute__((unused)),
794 char *cmd __attribute__((unused)),
795 grub_size_t size __attribute__((unused)),
796 char *buf __attribute__((unused)))
798 // XXX: scsi.mod does not use write yet.
799 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "ATAPI write not implemented");
802 static grub_err_t
803 grub_atapi_open (const char *name, struct grub_scsi *scsi)
805 struct grub_ata_device *dev;
806 struct grub_ata_device *devfnd = 0;
808 for (dev = grub_ata_devices; dev; dev = dev->next)
810 char devname[7];
811 grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
813 if (!grub_strcmp (devname, name))
815 devfnd = dev;
816 break;
820 grub_dprintf ("ata", "opening ATAPI dev `%s'\n", name);
822 if (! devfnd)
823 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such ATAPI device");
825 scsi->data = devfnd;
827 return GRUB_ERR_NONE;
830 static void
831 grub_atapi_close (struct grub_scsi *scsi)
833 grub_free (scsi->name);
836 static struct grub_scsi_dev grub_atapi_dev =
838 .name = "ATAPI",
839 .iterate = grub_atapi_iterate,
840 .open = grub_atapi_open,
841 .close = grub_atapi_close,
842 .read = grub_atapi_read,
843 .write = grub_atapi_write
848 GRUB_MOD_INIT(ata)
850 /* To prevent two drivers operating on the same disks. */
851 grub_disk_firmware_is_tainted = 1;
852 if (grub_disk_firmware_fini)
854 grub_disk_firmware_fini ();
855 grub_disk_firmware_fini = NULL;
858 /* ATA initialization. */
859 grub_ata_initialize ();
861 grub_disk_dev_register (&grub_atadisk_dev);
863 /* ATAPI devices are handled by scsi.mod. */
864 grub_scsi_dev_register (&grub_atapi_dev);
867 GRUB_MOD_FINI(ata)
869 grub_scsi_dev_unregister (&grub_atapi_dev);
870 grub_disk_dev_unregister (&grub_atadisk_dev);