2009-03-18 Robert Millan <rmh@aybabtu.com>
[grub2/phcoder/solaris.git] / disk / ata.c
blobed98b0b878ad411bb7229e3292fb988e5b1d297c
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 while (grub_ata_regget (dev, GRUB_ATA_REG_STATUS) & GRUB_ATA_STATUS_BUSY)
46 if (i >= milliseconds)
48 grub_dprintf ("ata", "timeout: %dms\n", milliseconds);
49 return grub_error (GRUB_ERR_TIMEOUT, "ATA timeout");
52 grub_millisleep (1);
53 i++;
56 return GRUB_ERR_NONE;
59 static inline void
60 grub_ata_wait (void)
62 grub_millisleep (50);
65 /* Wait for !BSY, DRQ. */
66 grub_err_t
67 grub_ata_wait_drq (struct grub_ata_device *dev, int rw,
68 int milliseconds)
70 if (grub_ata_wait_not_busy (dev, milliseconds))
71 return grub_errno;
73 /* !DRQ implies error condition. */
74 grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
75 if ((sts & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
76 != GRUB_ATA_STATUS_DRQ)
78 grub_dprintf ("ata", "ata error: status=0x%x, error=0x%x\n",
79 sts, grub_ata_regget (dev, GRUB_ATA_REG_ERROR));
80 if (! rw)
81 return grub_error (GRUB_ERR_READ_ERROR, "ATA read error");
82 else
83 return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error");
86 return GRUB_ERR_NONE;
89 /* Byteorder has to be changed before strings can be read. */
90 static void
91 grub_ata_strncpy (char *dst, char *src, grub_size_t len)
93 grub_uint16_t *src16 = (grub_uint16_t *) src;
94 grub_uint16_t *dst16 = (grub_uint16_t *) dst;
95 unsigned int i;
97 for (i = 0; i < len / 2; i++)
98 *(dst16++) = grub_be_to_cpu16 (*(src16++));
99 dst[len] = '\0';
102 void
103 grub_ata_pio_read (struct grub_ata_device *dev, char *buf, grub_size_t size)
105 grub_uint16_t *buf16 = (grub_uint16_t *) buf;
106 unsigned int i;
108 /* Read in the data, word by word. */
109 for (i = 0; i < size / 2; i++)
110 buf16[i] = grub_le_to_cpu16 (grub_inw(dev->ioaddress + GRUB_ATA_REG_DATA));
113 static void
114 grub_ata_pio_write (struct grub_ata_device *dev, char *buf, grub_size_t size)
116 grub_uint16_t *buf16 = (grub_uint16_t *) buf;
117 unsigned int i;
119 /* Write the data, word by word. */
120 for (i = 0; i < size / 2; i++)
121 grub_outw(grub_cpu_to_le16 (buf16[i]), dev->ioaddress + GRUB_ATA_REG_DATA);
124 static void
125 grub_ata_dumpinfo (struct grub_ata_device *dev, char *info)
127 char text[41];
129 /* The device information was read, dump it for debugging. */
130 grub_ata_strncpy (text, info + 20, 20);
131 grub_dprintf ("ata", "Serial: %s\n", text);
132 grub_ata_strncpy (text, info + 46, 8);
133 grub_dprintf ("ata", "Firmware: %s\n", text);
134 grub_ata_strncpy (text, info + 54, 40);
135 grub_dprintf ("ata", "Model: %s\n", text);
137 if (! dev->atapi)
139 grub_dprintf ("ata", "Addressing: %d\n", dev->addr);
140 grub_dprintf ("ata", "Sectors: %lld\n", dev->size);
144 static grub_err_t
145 grub_atapi_identify (struct grub_ata_device *dev)
147 char *info;
149 info = grub_malloc (GRUB_DISK_SECTOR_SIZE);
150 if (! info)
151 return grub_errno;
153 grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
154 if (grub_ata_check_ready (dev))
156 grub_free (info);
157 return grub_errno;
160 grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE);
161 grub_ata_wait ();
163 if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD))
165 grub_free (info);
166 return grub_errno;
168 grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE);
170 dev->atapi = 1;
172 grub_ata_dumpinfo (dev, info);
174 grub_free (info);
176 return GRUB_ERR_NONE;
179 static grub_err_t
180 grub_atapi_wait_drq (struct grub_ata_device *dev,
181 grub_uint8_t ireason,
182 int milliseconds)
184 /* Wait for !BSY, DRQ, ireason */
185 if (grub_ata_wait_not_busy (dev, milliseconds))
186 return grub_errno;
188 grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
189 grub_uint8_t irs = grub_ata_regget (dev, GRUB_ATAPI_REG_IREASON);
191 /* OK if DRQ is asserted and interrupt reason is as expected. */
192 if ((sts & GRUB_ATA_STATUS_DRQ)
193 && (irs & GRUB_ATAPI_IREASON_MASK) == ireason)
194 return GRUB_ERR_NONE;
196 /* !DRQ implies error condition. */
197 grub_dprintf ("ata", "atapi error: status=0x%x, ireason=0x%x, error=0x%x\n",
198 sts, irs, grub_ata_regget (dev, GRUB_ATA_REG_ERROR));
200 if (! (sts & GRUB_ATA_STATUS_DRQ)
201 && (irs & GRUB_ATAPI_IREASON_MASK) == GRUB_ATAPI_IREASON_ERROR)
203 if (ireason == GRUB_ATAPI_IREASON_CMD_OUT)
204 return grub_error (GRUB_ERR_READ_ERROR, "ATA PACKET command error");
205 else
206 return grub_error (GRUB_ERR_READ_ERROR, "ATAPI read error");
209 return grub_error (GRUB_ERR_READ_ERROR, "ATAPI protocol error");
212 static grub_err_t
213 grub_atapi_packet (struct grub_ata_device *dev, char *packet,
214 grub_size_t size)
216 grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
217 if (grub_ata_check_ready (dev))
218 return grub_errno;
220 /* Send ATA PACKET command. */
221 grub_ata_regset (dev, GRUB_ATA_REG_FEATURES, 0);
222 grub_ata_regset (dev, GRUB_ATAPI_REG_IREASON, 0);
223 grub_ata_regset (dev, GRUB_ATAPI_REG_CNTHIGH, size >> 8);
224 grub_ata_regset (dev, GRUB_ATAPI_REG_CNTLOW, size & 0xFF);
226 grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_PACKET);
228 /* Wait for !BSY, DRQ, !I/O, C/D. */
229 if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_CMD_OUT, GRUB_ATA_TOUT_STD))
230 return grub_errno;
232 /* Write the packet. */
233 grub_ata_pio_write (dev, packet, 12);
235 return GRUB_ERR_NONE;
238 static grub_err_t
239 grub_ata_identify (struct grub_ata_device *dev)
241 char *info;
242 grub_uint16_t *info16;
244 info = grub_malloc (GRUB_DISK_SECTOR_SIZE);
245 if (! info)
246 return grub_errno;
248 info16 = (grub_uint16_t *) info;
250 grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
251 if (grub_ata_check_ready (dev))
253 grub_free (info);
254 return grub_errno;
257 grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_DEVICE);
258 grub_ata_wait ();
260 if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD))
262 if (grub_ata_regget (dev, GRUB_ATA_REG_ERROR) & 0x04) /* ABRT */
264 /* Device without ATA IDENTIFY, try ATAPI. */
265 grub_free(info);
266 grub_errno = GRUB_ERR_NONE;
267 return grub_atapi_identify (dev);
269 else
271 /* Error. */
272 grub_free(info);
273 return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
274 "device can not be identified");
278 grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE);
280 /* Now it is certain that this is not an ATAPI device. */
281 dev->atapi = 0;
283 /* CHS is always supported. */
284 dev->addr = GRUB_ATA_CHS;
286 /* Check if LBA is supported. */
287 if (info16[49] & (1 << 9))
289 /* Check if LBA48 is supported. */
290 if (info16[83] & (1 << 10))
291 dev->addr = GRUB_ATA_LBA48;
292 else
293 dev->addr = GRUB_ATA_LBA;
296 /* Determine the amount of sectors. */
297 if (dev->addr != GRUB_ATA_LBA48)
298 dev->size = grub_le_to_cpu32(*((grub_uint32_t *) &info16[60]));
299 else
300 dev->size = grub_le_to_cpu64(*((grub_uint64_t *) &info16[100]));
302 /* Read CHS information. */
303 dev->cylinders = info16[1];
304 dev->heads = info16[3];
305 dev->sectors_per_track = info16[6];
307 grub_ata_dumpinfo (dev, info);
309 grub_free(info);
311 return 0;
314 static grub_err_t
315 grub_ata_device_initialize (int port, int device, int addr, int addr2)
317 struct grub_ata_device *dev;
318 struct grub_ata_device **devp;
320 grub_dprintf ("ata", "detecting device %d,%d (0x%x, 0x%x)\n",
321 port, device, addr, addr2);
323 dev = grub_malloc (sizeof(*dev));
324 if (! dev)
325 return grub_errno;
327 /* Setup the device information. */
328 dev->port = port;
329 dev->device = device;
330 dev->ioaddress = addr;
331 dev->ioaddress2 = addr2;
332 dev->next = NULL;
334 grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
335 grub_ata_wait ();
337 /* If status is 0x00, it is safe to assume that there
338 is no device (or only a !READY) device connected. */
339 grub_int8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
340 grub_dprintf ("ata", "status=0x%x\n", sts);
341 if (sts == 0x00)
343 grub_free(dev);
344 return 0;
347 /* Try to detect if the port is in use by writing to it,
348 waiting for a while and reading it again. If the value
349 was preserved, there is a device connected.
350 But this tests often detects a second (slave) device
351 connected to a SATA controller which supports only one
352 (master) device. In this case, the status register
353 check above usually works. */
354 grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A);
355 grub_ata_wait ();
356 grub_int8_t sec = grub_ata_regget (dev, GRUB_ATA_REG_SECTORS);
357 grub_dprintf ("ata", "sectors=0x%x\n", sec);
358 if (sec != 0x5A)
360 grub_free(dev);
361 return 0;
364 /* Use the IDENTIFY DEVICE command to query the device. */
365 if (grub_ata_identify (dev))
367 grub_free (dev);
368 return 0;
371 /* Register the device. */
372 for (devp = &grub_ata_devices; *devp; devp = &(*devp)->next);
373 *devp = dev;
375 return 0;
378 static int
379 grub_ata_pciinit (int bus, int device, int func,
380 grub_pci_id_t pciid __attribute__((unused)))
382 static int compat_use[2] = { 0 };
383 grub_pci_address_t addr;
384 grub_uint32_t class;
385 grub_uint32_t bar1;
386 grub_uint32_t bar2;
387 int rega;
388 int regb;
389 int i;
390 static int controller = 0;
392 /* Read class. */
393 addr = grub_pci_make_address (bus, device, func, 2);
394 class = grub_pci_read (addr);
396 /* Check if this class ID matches that of a PCI IDE Controller. */
397 if (class >> 16 != 0x0101)
398 return 0;
400 for (i = 0; i < 2; i++)
402 /* Set to 0 when the channel operated in compatibility mode. */
403 int compat = (class >> (8 + 2 * i)) & 1;
405 rega = 0;
406 regb = 0;
408 /* If the channel is in compatibility mode, just assign the
409 default registers. */
410 if (compat == 0 && !compat_use[i])
412 rega = grub_ata_ioaddress[i];
413 regb = grub_ata_ioaddress2[i];
414 compat_use[i] = 1;
416 else if (compat)
418 /* Read the BARs, which either contain a mmapped IO address
419 or the IO port address. */
420 addr = grub_pci_make_address (bus, device, func, 4 + 2 * i);
421 bar1 = grub_pci_read (addr);
422 addr = grub_pci_make_address (bus, device, func, 5 + 2 * i);
423 bar2 = grub_pci_read (addr);
425 /* Check if the BARs describe an IO region. */
426 if ((bar1 & 1) && (bar2 & 1))
428 rega = bar1 & ~3;
429 regb = bar2 & ~3;
433 grub_dprintf ("ata",
434 "PCI dev (%d,%d,%d) compat=%d rega=0x%x regb=0x%x\n",
435 bus, device, func, compat, rega, regb);
437 if (rega && regb)
439 grub_errno = GRUB_ERR_NONE;
440 grub_ata_device_initialize (controller * 2 + i, 0, rega, regb);
442 /* Most errors rised by grub_ata_device_initialize() are harmless.
443 They just indicate this particular drive is not responding, most
444 likely because it doesn't exist. We might want to ignore specific
445 error types here, instead of printing them. */
446 if (grub_errno)
448 grub_print_error ();
449 grub_errno = GRUB_ERR_NONE;
452 grub_ata_device_initialize (controller * 2 + i, 1, rega, regb);
454 /* Likewise. */
455 if (grub_errno)
457 grub_print_error ();
458 grub_errno = GRUB_ERR_NONE;
463 controller++;
465 return 0;
468 static grub_err_t
469 grub_ata_initialize (void)
471 grub_pci_iterate (grub_ata_pciinit);
472 return 0;
476 static void
477 grub_ata_setlba (struct grub_ata_device *dev, grub_disk_addr_t sector,
478 grub_size_t size)
480 grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, size);
481 grub_ata_regset (dev, GRUB_ATA_REG_LBALOW, sector & 0xFF);
482 grub_ata_regset (dev, GRUB_ATA_REG_LBAMID, (sector >> 8) & 0xFF);
483 grub_ata_regset (dev, GRUB_ATA_REG_LBAHIGH, (sector >> 16) & 0xFF);
486 static grub_err_t
487 grub_ata_setaddress (struct grub_ata_device *dev,
488 grub_ata_addressing_t addressing,
489 grub_disk_addr_t sector,
490 grub_size_t size)
492 switch (addressing)
494 case GRUB_ATA_CHS:
496 unsigned int cylinder;
497 unsigned int head;
498 unsigned int sect;
500 /* Calculate the sector, cylinder and head to use. */
501 sect = ((grub_uint32_t) sector % dev->sectors_per_track) + 1;
502 cylinder = (((grub_uint32_t) sector / dev->sectors_per_track)
503 / dev->heads);
504 head = ((grub_uint32_t) sector / dev->sectors_per_track) % dev->heads;
506 if (sect > dev->sectors_per_track
507 || cylinder > dev->cylinders
508 || head > dev->heads)
509 return grub_error (GRUB_ERR_OUT_OF_RANGE,
510 "sector %d can not be addressed "
511 "using CHS addressing", sector);
513 grub_ata_regset (dev, GRUB_ATA_REG_DISK, (dev->device << 4) | head);
514 if (grub_ata_check_ready (dev))
515 return grub_errno;
517 grub_ata_regset (dev, GRUB_ATA_REG_SECTNUM, sect);
518 grub_ata_regset (dev, GRUB_ATA_REG_CYLLSB, cylinder & 0xFF);
519 grub_ata_regset (dev, GRUB_ATA_REG_CYLMSB, cylinder >> 8);
521 break;
524 case GRUB_ATA_LBA:
525 if (size == 256)
526 size = 0;
527 grub_ata_regset (dev, GRUB_ATA_REG_DISK,
528 0xE0 | (dev->device << 4) | ((sector >> 24) & 0x0F));
529 if (grub_ata_check_ready (dev))
530 return grub_errno;
532 grub_ata_setlba (dev, sector, size);
533 break;
535 case GRUB_ATA_LBA48:
536 if (size == 65536)
537 size = 0;
539 grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | (dev->device << 4));
540 if (grub_ata_check_ready (dev))
541 return grub_errno;
543 /* Set "Previous". */
544 grub_ata_setlba (dev, sector >> 24, size >> 8);
545 /* Set "Current". */
546 grub_ata_setlba (dev, sector, size);
548 break;
551 return GRUB_ERR_NONE;
554 static grub_err_t
555 grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector,
556 grub_size_t size, char *buf, int rw)
558 struct grub_ata_device *dev = (struct grub_ata_device *) disk->data;
560 grub_dprintf("ata", "grub_ata_readwrite (size=%u, rw=%d)\n", size, rw);
562 grub_ata_addressing_t addressing = dev->addr;
563 grub_size_t batch;
564 int cmd, cmd_write;
566 if (addressing == GRUB_ATA_LBA48 && ((sector + size) >> 28) != 0)
568 batch = 65536;
569 cmd = GRUB_ATA_CMD_READ_SECTORS_EXT;
570 cmd_write = GRUB_ATA_CMD_WRITE_SECTORS_EXT;
572 else
574 if (addressing == GRUB_ATA_LBA48)
575 addressing = GRUB_ATA_LBA;
576 batch = 256;
577 cmd = GRUB_ATA_CMD_READ_SECTORS;
578 cmd_write = GRUB_ATA_CMD_WRITE_SECTORS;
581 grub_size_t nsectors = 0;
582 while (nsectors < size)
584 if (size - nsectors < batch)
585 batch = size - nsectors;
587 grub_dprintf("ata", "rw=%d, sector=%llu, batch=%u\n", rw, sector, batch);
589 /* Send read/write commmand. */
590 if (grub_ata_setaddress (dev, addressing, sector, batch))
591 return grub_errno;
593 grub_ata_regset (dev, GRUB_ATA_REG_CMD, (! rw ? cmd : cmd_write));
595 unsigned sect;
596 for (sect = 0; sect < batch; sect++)
598 /* Wait for !BSY, DRQ. */
599 if (grub_ata_wait_drq (dev, rw, GRUB_ATA_TOUT_DATA))
600 return grub_errno;
602 /* Transfer data. */
603 if (! rw)
604 grub_ata_pio_read (dev, buf, GRUB_DISK_SECTOR_SIZE);
605 else
606 grub_ata_pio_write (dev, buf, GRUB_DISK_SECTOR_SIZE);
608 buf += GRUB_DISK_SECTOR_SIZE;
611 if (rw)
613 /* Check for write error. */
614 if (grub_ata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA))
615 return grub_errno;
617 if (grub_ata_regget (dev, GRUB_ATA_REG_STATUS)
618 & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
619 return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error");
622 sector += batch;
623 nsectors += batch;
626 return GRUB_ERR_NONE;
631 static int
632 grub_ata_iterate (int (*hook) (const char *name))
634 struct grub_ata_device *dev;
636 for (dev = grub_ata_devices; dev; dev = dev->next)
638 char devname[5];
639 grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
641 if (dev->atapi)
642 continue;
644 if (hook (devname))
645 return 1;
648 return 0;
651 static grub_err_t
652 grub_ata_open (const char *name, grub_disk_t disk)
654 struct grub_ata_device *dev;
656 for (dev = grub_ata_devices; dev; dev = dev->next)
658 char devname[5];
659 grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
660 if (grub_strcmp (name, devname) == 0)
661 break;
664 if (! dev)
665 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device");
667 if (dev->atapi)
668 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk");
670 disk->total_sectors = dev->size;
672 disk->id = (unsigned long) dev;
674 disk->has_partitions = 1;
675 disk->data = dev;
677 return 0;
680 static void
681 grub_ata_close (grub_disk_t disk __attribute__((unused)))
686 static grub_err_t
687 grub_ata_read (grub_disk_t disk, grub_disk_addr_t sector,
688 grub_size_t size, char *buf)
690 return grub_ata_readwrite (disk, sector, size, buf, 0);
693 static grub_err_t
694 grub_ata_write (grub_disk_t disk,
695 grub_disk_addr_t sector,
696 grub_size_t size,
697 const char *buf)
699 return grub_ata_readwrite (disk, sector, size, (char *) buf, 1);
702 static struct grub_disk_dev grub_atadisk_dev =
704 .name = "ATA",
705 .id = GRUB_DISK_DEVICE_ATA_ID,
706 .iterate = grub_ata_iterate,
707 .open = grub_ata_open,
708 .close = grub_ata_close,
709 .read = grub_ata_read,
710 .write = grub_ata_write,
711 .next = 0
716 /* ATAPI code. */
718 static int
719 grub_atapi_iterate (int (*hook) (const char *name, int luns))
721 struct grub_ata_device *dev;
723 for (dev = grub_ata_devices; dev; dev = dev->next)
725 char devname[7];
726 grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
728 if (! dev->atapi)
729 continue;
731 if (hook (devname, 1))
732 return 1;
735 return 0;
739 static grub_err_t
740 grub_atapi_read (struct grub_scsi *scsi,
741 grub_size_t cmdsize __attribute__((unused)),
742 char *cmd, grub_size_t size, char *buf)
744 struct grub_ata_device *dev = (struct grub_ata_device *) scsi->data;
746 grub_dprintf("ata", "grub_atapi_read (size=%u)\n", size);
748 if (grub_atapi_packet (dev, cmd, size))
749 return grub_errno;
751 grub_size_t nread = 0;
752 while (nread < size)
754 /* Wait for !BSY, DRQ, I/O, !C/D. */
755 if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_DATA_IN, GRUB_ATA_TOUT_DATA))
756 return grub_errno;
758 /* Get byte count for this DRQ assertion. */
759 unsigned cnt = grub_ata_regget (dev, GRUB_ATAPI_REG_CNTHIGH) << 8
760 | grub_ata_regget (dev, GRUB_ATAPI_REG_CNTLOW);
761 grub_dprintf("ata", "DRQ count=%u\n", cnt);
763 /* Count of last transfer may be uneven. */
764 if (! (0 < cnt && cnt <= size - nread && (! (cnt & 1) || cnt == size - nread)))
765 return grub_error (GRUB_ERR_READ_ERROR, "Invalid ATAPI transfer count");
767 /* Read the data. */
768 grub_ata_pio_read (dev, buf + nread, cnt);
770 if (cnt & 1)
771 buf[nread + cnt - 1] = (char) grub_le_to_cpu16 (grub_inw (dev->ioaddress + GRUB_ATA_REG_DATA));
773 nread += cnt;
776 return GRUB_ERR_NONE;
779 static grub_err_t
780 grub_atapi_write (struct grub_scsi *scsi __attribute__((unused)),
781 grub_size_t cmdsize __attribute__((unused)),
782 char *cmd __attribute__((unused)),
783 grub_size_t size __attribute__((unused)),
784 char *buf __attribute__((unused)))
786 // XXX: scsi.mod does not use write yet.
787 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "ATAPI write not implemented");
790 static grub_err_t
791 grub_atapi_open (const char *name, struct grub_scsi *scsi)
793 struct grub_ata_device *dev;
794 struct grub_ata_device *devfnd = 0;
796 for (dev = grub_ata_devices; dev; dev = dev->next)
798 char devname[7];
799 grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
801 if (!grub_strcmp (devname, name))
803 devfnd = dev;
804 break;
808 grub_dprintf ("ata", "opening ATAPI dev `%s'\n", name);
810 if (! devfnd)
811 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such ATAPI device");
813 scsi->data = devfnd;
815 return GRUB_ERR_NONE;
818 static void
819 grub_atapi_close (struct grub_scsi *scsi)
821 grub_free (scsi->name);
824 static struct grub_scsi_dev grub_atapi_dev =
826 .name = "ATAPI",
827 .iterate = grub_atapi_iterate,
828 .open = grub_atapi_open,
829 .close = grub_atapi_close,
830 .read = grub_atapi_read,
831 .write = grub_atapi_write
836 GRUB_MOD_INIT(ata)
838 (void) mod; /* To stop warning. */
840 /* To prevent two drivers operating on the same disks. */
841 grub_disk_firmware_is_tainted = 1;
842 if (grub_disk_firmware_fini)
844 grub_disk_firmware_fini ();
845 grub_disk_firmware_fini = NULL;
848 /* ATA initialization. */
849 grub_ata_initialize ();
851 grub_disk_dev_register (&grub_atadisk_dev);
853 /* ATAPI devices are handled by scsi.mod. */
854 grub_scsi_dev_register (&grub_atapi_dev);
857 GRUB_MOD_FINI(ata)
859 grub_scsi_dev_unregister (&grub_atapi_dev);
860 grub_disk_dev_unregister (&grub_atadisk_dev);