Merge branch 'makefile' into haiku
[grub2/phcoder.git] / disk / ata.c
blob86b6010212b3cbcd46e22e709e592116b5ec47a5
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 int i = 1;
39 grub_uint8_t sts;
41 /* ATA requires 400ns (after a write to CMD register) or
42 1 PIO cycle (after a DRQ block transfer) before
43 first check of BSY. */
44 grub_millisleep (1);
46 while ((sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS))
47 & GRUB_ATA_STATUS_BUSY)
49 if (i >= milliseconds)
51 grub_dprintf ("ata", "timeout: %dms, status=0x%x\n",
52 milliseconds, sts);
53 return grub_error (GRUB_ERR_TIMEOUT, "ATA timeout");
56 grub_millisleep (1);
57 i++;
60 return GRUB_ERR_NONE;
63 static inline void
64 grub_ata_wait (void)
66 grub_millisleep (50);
69 /* Wait for !BSY, DRQ. */
70 grub_err_t
71 grub_ata_wait_drq (struct grub_ata_device *dev, int rw,
72 int milliseconds)
74 grub_uint8_t sts;
76 if (grub_ata_wait_not_busy (dev, milliseconds))
77 return grub_errno;
79 /* !DRQ implies error condition. */
80 sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
81 if ((sts & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
82 != GRUB_ATA_STATUS_DRQ)
84 grub_dprintf ("ata", "ata error: status=0x%x, error=0x%x\n",
85 sts, grub_ata_regget (dev, GRUB_ATA_REG_ERROR));
86 if (! rw)
87 return grub_error (GRUB_ERR_READ_ERROR, "ATA read error");
88 else
89 return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error");
92 return GRUB_ERR_NONE;
95 /* Byteorder has to be changed before strings can be read. */
96 static void
97 grub_ata_strncpy (char *dst, char *src, grub_size_t len)
99 grub_uint16_t *src16 = (grub_uint16_t *) src;
100 grub_uint16_t *dst16 = (grub_uint16_t *) dst;
101 unsigned int i;
103 for (i = 0; i < len / 2; i++)
104 *(dst16++) = grub_be_to_cpu16 (*(src16++));
105 dst[len] = '\0';
108 void
109 grub_ata_pio_read (struct grub_ata_device *dev, char *buf, grub_size_t size)
111 grub_uint16_t *buf16 = (grub_uint16_t *) buf;
112 unsigned int i;
114 /* Read in the data, word by word. */
115 for (i = 0; i < size / 2; i++)
116 buf16[i] = grub_le_to_cpu16 (grub_inw(dev->ioaddress + GRUB_ATA_REG_DATA));
119 static void
120 grub_ata_pio_write (struct grub_ata_device *dev, char *buf, grub_size_t size)
122 grub_uint16_t *buf16 = (grub_uint16_t *) buf;
123 unsigned int i;
125 /* Write the data, word by word. */
126 for (i = 0; i < size / 2; i++)
127 grub_outw(grub_cpu_to_le16 (buf16[i]), dev->ioaddress + GRUB_ATA_REG_DATA);
130 static void
131 grub_ata_dumpinfo (struct grub_ata_device *dev, char *info)
133 char text[41];
135 /* The device information was read, dump it for debugging. */
136 grub_ata_strncpy (text, info + 20, 20);
137 grub_dprintf ("ata", "Serial: %s\n", text);
138 grub_ata_strncpy (text, info + 46, 8);
139 grub_dprintf ("ata", "Firmware: %s\n", text);
140 grub_ata_strncpy (text, info + 54, 40);
141 grub_dprintf ("ata", "Model: %s\n", text);
143 if (! dev->atapi)
145 grub_dprintf ("ata", "Addressing: %d\n", dev->addr);
146 grub_dprintf ("ata", "Sectors: %lld\n", dev->size);
150 static grub_err_t
151 grub_atapi_identify (struct grub_ata_device *dev)
153 char *info;
155 info = grub_malloc (GRUB_DISK_SECTOR_SIZE);
156 if (! info)
157 return grub_errno;
159 grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
160 grub_ata_wait ();
161 if (grub_ata_check_ready (dev))
163 grub_free (info);
164 return grub_errno;
167 grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE);
168 grub_ata_wait ();
170 if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD))
172 grub_free (info);
173 return grub_errno;
175 grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE);
177 dev->atapi = 1;
179 grub_ata_dumpinfo (dev, info);
181 grub_free (info);
183 return GRUB_ERR_NONE;
186 static grub_err_t
187 grub_atapi_wait_drq (struct grub_ata_device *dev,
188 grub_uint8_t ireason,
189 int milliseconds)
191 grub_uint8_t sts;
192 grub_uint8_t irs;
194 /* Wait for !BSY, DRQ, ireason */
195 if (grub_ata_wait_not_busy (dev, milliseconds))
196 return grub_errno;
198 sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
199 irs = grub_ata_regget (dev, GRUB_ATAPI_REG_IREASON);
201 /* OK if DRQ is asserted and interrupt reason is as expected. */
202 if ((sts & GRUB_ATA_STATUS_DRQ)
203 && (irs & GRUB_ATAPI_IREASON_MASK) == ireason)
204 return GRUB_ERR_NONE;
206 /* !DRQ implies error condition. */
207 grub_dprintf ("ata", "atapi error: status=0x%x, ireason=0x%x, error=0x%x\n",
208 sts, irs, grub_ata_regget (dev, GRUB_ATA_REG_ERROR));
210 if (! (sts & GRUB_ATA_STATUS_DRQ)
211 && (irs & GRUB_ATAPI_IREASON_MASK) == GRUB_ATAPI_IREASON_ERROR)
213 if (ireason == GRUB_ATAPI_IREASON_CMD_OUT)
214 return grub_error (GRUB_ERR_READ_ERROR, "ATA PACKET command error");
215 else
216 return grub_error (GRUB_ERR_READ_ERROR, "ATAPI read error");
219 return grub_error (GRUB_ERR_READ_ERROR, "ATAPI protocol error");
222 static grub_err_t
223 grub_atapi_packet (struct grub_ata_device *dev, char *packet,
224 grub_size_t size)
226 grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
227 if (grub_ata_check_ready (dev))
228 return grub_errno;
230 /* Send ATA PACKET command. */
231 grub_ata_regset (dev, GRUB_ATA_REG_FEATURES, 0);
232 grub_ata_regset (dev, GRUB_ATAPI_REG_IREASON, 0);
233 grub_ata_regset (dev, GRUB_ATAPI_REG_CNTHIGH, size >> 8);
234 grub_ata_regset (dev, GRUB_ATAPI_REG_CNTLOW, size & 0xFF);
236 grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_PACKET);
238 /* Wait for !BSY, DRQ, !I/O, C/D. */
239 if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_CMD_OUT, GRUB_ATA_TOUT_STD))
240 return grub_errno;
242 /* Write the packet. */
243 grub_ata_pio_write (dev, packet, 12);
245 return GRUB_ERR_NONE;
248 static grub_err_t
249 grub_ata_identify (struct grub_ata_device *dev)
251 char *info;
252 grub_uint16_t *info16;
253 grub_uint8_t sts;
255 info = grub_malloc (GRUB_DISK_SECTOR_SIZE);
256 if (! info)
257 return grub_errno;
259 info16 = (grub_uint16_t *) info;
261 grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
262 grub_ata_wait ();
263 if (grub_ata_check_ready (dev))
265 grub_free (info);
266 return grub_errno;
269 grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_DEVICE);
270 grub_ata_wait ();
272 if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD))
274 sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
276 grub_free (info);
277 grub_errno = GRUB_ERR_NONE;
279 if ((sts & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ
280 | GRUB_ATA_STATUS_ERR)) == GRUB_ATA_STATUS_ERR
281 && (grub_ata_regget (dev, GRUB_ATA_REG_ERROR) & 0x04 /* ABRT */))
282 /* Device without ATA IDENTIFY, try ATAPI. */
283 return grub_atapi_identify (dev);
285 else if (sts == 0x00)
286 /* No device, return error but don't print message. */
287 return GRUB_ERR_UNKNOWN_DEVICE;
289 else
290 /* Other Error. */
291 return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
292 "device can not be identified");
295 grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE);
297 /* Re-check status to avoid bogus identify data due to stuck DRQ. */
298 sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
299 if (sts & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
301 grub_dprintf ("ata", "bad status=0x%x\n", sts);
302 grub_free (info);
303 /* No device, return error but don't print message. */
304 grub_errno = GRUB_ERR_NONE;
305 return GRUB_ERR_UNKNOWN_DEVICE;
308 /* Now it is certain that this is not an ATAPI device. */
309 dev->atapi = 0;
311 /* CHS is always supported. */
312 dev->addr = GRUB_ATA_CHS;
314 /* Check if LBA is supported. */
315 if (info16[49] & (1 << 9))
317 /* Check if LBA48 is supported. */
318 if (info16[83] & (1 << 10))
319 dev->addr = GRUB_ATA_LBA48;
320 else
321 dev->addr = GRUB_ATA_LBA;
324 /* Determine the amount of sectors. */
325 if (dev->addr != GRUB_ATA_LBA48)
326 dev->size = grub_le_to_cpu32(*((grub_uint32_t *) &info16[60]));
327 else
328 dev->size = grub_le_to_cpu64(*((grub_uint64_t *) &info16[100]));
330 /* Read CHS information. */
331 dev->cylinders = info16[1];
332 dev->heads = info16[3];
333 dev->sectors_per_track = info16[6];
335 grub_ata_dumpinfo (dev, info);
337 grub_free(info);
339 return 0;
342 static grub_err_t
343 grub_ata_device_initialize (int port, int device, int addr, int addr2)
345 struct grub_ata_device *dev;
346 struct grub_ata_device **devp;
347 grub_uint8_t sec;
349 grub_dprintf ("ata", "detecting device %d,%d (0x%x, 0x%x)\n",
350 port, device, addr, addr2);
352 dev = grub_malloc (sizeof(*dev));
353 if (! dev)
354 return grub_errno;
356 /* Setup the device information. */
357 dev->port = port;
358 dev->device = device;
359 dev->ioaddress = addr;
360 dev->ioaddress2 = addr2;
361 dev->next = NULL;
363 grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
364 grub_ata_wait ();
366 /* Try to detect if the port is in use by writing to it,
367 waiting for a while and reading it again. If the value
368 was preserved, there is a device connected. */
369 grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A);
370 grub_ata_wait ();
371 sec = grub_ata_regget (dev, GRUB_ATA_REG_SECTORS);
372 grub_dprintf ("ata", "sectors=0x%x\n", sec);
373 if (sec != 0x5A)
375 grub_free(dev);
376 return 0;
379 /* The above test may detect a second (slave) device
380 connected to a SATA controller which supports only one
381 (master) device. It is not safe to use the status register
382 READY bit to check for controller channel existence. Some
383 ATAPI commands (RESET, DIAGNOSTIC) may clear this bit. */
385 /* Use the IDENTIFY DEVICE command to query the device. */
386 if (grub_ata_identify (dev))
388 grub_free (dev);
389 return 0;
392 /* Register the device. */
393 for (devp = &grub_ata_devices; *devp; devp = &(*devp)->next);
394 *devp = dev;
396 return 0;
399 static int NESTED_FUNC_ATTR
400 grub_ata_pciinit (int bus, int device, int func,
401 grub_pci_id_t pciid __attribute__((unused)))
403 static int compat_use[2] = { 0 };
404 grub_pci_address_t addr;
405 grub_uint32_t class;
406 grub_uint32_t bar1;
407 grub_uint32_t bar2;
408 int rega;
409 int regb;
410 int i;
411 static int controller = 0;
413 /* Read class. */
414 addr = grub_pci_make_address (bus, device, func, 2);
415 class = grub_pci_read (addr);
417 /* Check if this class ID matches that of a PCI IDE Controller. */
418 if (class >> 16 != 0x0101)
419 return 0;
421 for (i = 0; i < 2; i++)
423 /* Set to 0 when the channel operated in compatibility mode. */
424 int compat = (class >> (8 + 2 * i)) & 1;
426 rega = 0;
427 regb = 0;
429 /* If the channel is in compatibility mode, just assign the
430 default registers. */
431 if (compat == 0 && !compat_use[i])
433 rega = grub_ata_ioaddress[i];
434 regb = grub_ata_ioaddress2[i];
435 compat_use[i] = 1;
437 else if (compat)
439 /* Read the BARs, which either contain a mmapped IO address
440 or the IO port address. */
441 addr = grub_pci_make_address (bus, device, func, 4 + 2 * i);
442 bar1 = grub_pci_read (addr);
443 addr = grub_pci_make_address (bus, device, func, 5 + 2 * i);
444 bar2 = grub_pci_read (addr);
446 /* Check if the BARs describe an IO region. */
447 if ((bar1 & 1) && (bar2 & 1))
449 rega = bar1 & ~3;
450 regb = bar2 & ~3;
454 grub_dprintf ("ata",
455 "PCI dev (%d,%d,%d) compat=%d rega=0x%x regb=0x%x\n",
456 bus, device, func, compat, rega, regb);
458 if (rega && regb)
460 grub_errno = GRUB_ERR_NONE;
461 grub_ata_device_initialize (controller * 2 + i, 0, rega, regb);
463 /* Most errors raised by grub_ata_device_initialize() are harmless.
464 They just indicate this particular drive is not responding, most
465 likely because it doesn't exist. We might want to ignore specific
466 error types here, instead of printing them. */
467 if (grub_errno)
469 grub_print_error ();
470 grub_errno = GRUB_ERR_NONE;
473 grub_ata_device_initialize (controller * 2 + i, 1, rega, regb);
475 /* Likewise. */
476 if (grub_errno)
478 grub_print_error ();
479 grub_errno = GRUB_ERR_NONE;
484 controller++;
486 return 0;
489 static grub_err_t
490 grub_ata_initialize (void)
492 grub_pci_iterate (grub_ata_pciinit);
493 return 0;
497 static void
498 grub_ata_setlba (struct grub_ata_device *dev, grub_disk_addr_t sector,
499 grub_size_t size)
501 grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, size);
502 grub_ata_regset (dev, GRUB_ATA_REG_LBALOW, sector & 0xFF);
503 grub_ata_regset (dev, GRUB_ATA_REG_LBAMID, (sector >> 8) & 0xFF);
504 grub_ata_regset (dev, GRUB_ATA_REG_LBAHIGH, (sector >> 16) & 0xFF);
507 static grub_err_t
508 grub_ata_setaddress (struct grub_ata_device *dev,
509 grub_ata_addressing_t addressing,
510 grub_disk_addr_t sector,
511 grub_size_t size)
513 switch (addressing)
515 case GRUB_ATA_CHS:
517 unsigned int cylinder;
518 unsigned int head;
519 unsigned int sect;
521 /* Calculate the sector, cylinder and head to use. */
522 sect = ((grub_uint32_t) sector % dev->sectors_per_track) + 1;
523 cylinder = (((grub_uint32_t) sector / dev->sectors_per_track)
524 / dev->heads);
525 head = ((grub_uint32_t) sector / dev->sectors_per_track) % dev->heads;
527 if (sect > dev->sectors_per_track
528 || cylinder > dev->cylinders
529 || head > dev->heads)
530 return grub_error (GRUB_ERR_OUT_OF_RANGE,
531 "sector %d can not be addressed "
532 "using CHS addressing", sector);
534 grub_ata_regset (dev, GRUB_ATA_REG_DISK, (dev->device << 4) | head);
535 if (grub_ata_check_ready (dev))
536 return grub_errno;
538 grub_ata_regset (dev, GRUB_ATA_REG_SECTNUM, sect);
539 grub_ata_regset (dev, GRUB_ATA_REG_CYLLSB, cylinder & 0xFF);
540 grub_ata_regset (dev, GRUB_ATA_REG_CYLMSB, cylinder >> 8);
542 break;
545 case GRUB_ATA_LBA:
546 if (size == 256)
547 size = 0;
548 grub_ata_regset (dev, GRUB_ATA_REG_DISK,
549 0xE0 | (dev->device << 4) | ((sector >> 24) & 0x0F));
550 if (grub_ata_check_ready (dev))
551 return grub_errno;
553 grub_ata_setlba (dev, sector, size);
554 break;
556 case GRUB_ATA_LBA48:
557 if (size == 65536)
558 size = 0;
560 grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | (dev->device << 4));
561 if (grub_ata_check_ready (dev))
562 return grub_errno;
564 /* Set "Previous". */
565 grub_ata_setlba (dev, sector >> 24, size >> 8);
566 /* Set "Current". */
567 grub_ata_setlba (dev, sector, size);
569 break;
572 return GRUB_ERR_NONE;
575 static grub_err_t
576 grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector,
577 grub_size_t size, char *buf, int rw)
579 struct grub_ata_device *dev = (struct grub_ata_device *) disk->data;
580 grub_ata_addressing_t addressing = dev->addr;
581 grub_size_t batch;
582 int cmd, cmd_write;
583 grub_size_t nsectors = 0;
585 grub_dprintf("ata", "grub_ata_readwrite (size=%u, rw=%d)\n", size, rw);
587 if (addressing == GRUB_ATA_LBA48 && ((sector + size) >> 28) != 0)
589 batch = 65536;
590 cmd = GRUB_ATA_CMD_READ_SECTORS_EXT;
591 cmd_write = GRUB_ATA_CMD_WRITE_SECTORS_EXT;
593 else
595 if (addressing == GRUB_ATA_LBA48)
596 addressing = GRUB_ATA_LBA;
597 batch = 256;
598 cmd = GRUB_ATA_CMD_READ_SECTORS;
599 cmd_write = GRUB_ATA_CMD_WRITE_SECTORS;
602 while (nsectors < size)
604 unsigned sect;
606 if (size - nsectors < batch)
607 batch = size - nsectors;
609 grub_dprintf("ata", "rw=%d, sector=%llu, batch=%u\n", rw, sector, batch);
611 /* Send read/write command. */
612 if (grub_ata_setaddress (dev, addressing, sector, batch))
613 return grub_errno;
615 grub_ata_regset (dev, GRUB_ATA_REG_CMD, (! rw ? cmd : cmd_write));
617 for (sect = 0; sect < batch; sect++)
619 /* Wait for !BSY, DRQ. */
620 if (grub_ata_wait_drq (dev, rw, GRUB_ATA_TOUT_DATA))
621 return grub_errno;
623 /* Transfer data. */
624 if (! rw)
625 grub_ata_pio_read (dev, buf, GRUB_DISK_SECTOR_SIZE);
626 else
627 grub_ata_pio_write (dev, buf, GRUB_DISK_SECTOR_SIZE);
629 buf += GRUB_DISK_SECTOR_SIZE;
632 if (rw)
634 /* Check for write error. */
635 if (grub_ata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA))
636 return grub_errno;
638 if (grub_ata_regget (dev, GRUB_ATA_REG_STATUS)
639 & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
640 return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error");
643 sector += batch;
644 nsectors += batch;
647 return GRUB_ERR_NONE;
652 static int
653 grub_ata_iterate (int (*hook) (const char *name))
655 struct grub_ata_device *dev;
657 for (dev = grub_ata_devices; dev; dev = dev->next)
659 char devname[5];
660 grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
662 if (dev->atapi)
663 continue;
665 if (hook (devname))
666 return 1;
669 return 0;
672 static grub_err_t
673 grub_ata_open (const char *name, grub_disk_t disk)
675 struct grub_ata_device *dev;
677 for (dev = grub_ata_devices; dev; dev = dev->next)
679 char devname[5];
680 grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
681 if (grub_strcmp (name, devname) == 0)
682 break;
685 if (! dev)
686 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device");
688 if (dev->atapi)
689 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk");
691 disk->total_sectors = dev->size;
693 disk->id = (unsigned long) dev;
695 disk->has_partitions = 1;
696 disk->data = dev;
698 return 0;
701 static void
702 grub_ata_close (grub_disk_t disk __attribute__((unused)))
707 static grub_err_t
708 grub_ata_read (grub_disk_t disk, grub_disk_addr_t sector,
709 grub_size_t size, char *buf)
711 return grub_ata_readwrite (disk, sector, size, buf, 0);
714 static grub_err_t
715 grub_ata_write (grub_disk_t disk,
716 grub_disk_addr_t sector,
717 grub_size_t size,
718 const char *buf)
720 return grub_ata_readwrite (disk, sector, size, (char *) buf, 1);
723 static struct grub_disk_dev grub_atadisk_dev =
725 .name = "ATA",
726 .id = GRUB_DISK_DEVICE_ATA_ID,
727 .iterate = grub_ata_iterate,
728 .open = grub_ata_open,
729 .close = grub_ata_close,
730 .read = grub_ata_read,
731 .write = grub_ata_write,
732 .next = 0
737 /* ATAPI code. */
739 static int
740 grub_atapi_iterate (int (*hook) (const char *name, int luns))
742 struct grub_ata_device *dev;
744 for (dev = grub_ata_devices; dev; dev = dev->next)
746 char devname[7];
747 grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
749 if (! dev->atapi)
750 continue;
752 if (hook (devname, 1))
753 return 1;
756 return 0;
760 static grub_err_t
761 grub_atapi_read (struct grub_scsi *scsi,
762 grub_size_t cmdsize __attribute__((unused)),
763 char *cmd, grub_size_t size, char *buf)
765 struct grub_ata_device *dev = (struct grub_ata_device *) scsi->data;
766 grub_size_t nread = 0;
768 grub_dprintf("ata", "grub_atapi_read (size=%u)\n", size);
770 if (grub_atapi_packet (dev, cmd, size))
771 return grub_errno;
773 while (nread < size)
775 unsigned cnt;
777 /* Wait for !BSY, DRQ, I/O, !C/D. */
778 if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_DATA_IN, GRUB_ATA_TOUT_DATA))
779 return grub_errno;
781 /* Get byte count for this DRQ assertion. */
782 cnt = grub_ata_regget (dev, GRUB_ATAPI_REG_CNTHIGH) << 8
783 | grub_ata_regget (dev, GRUB_ATAPI_REG_CNTLOW);
784 grub_dprintf("ata", "DRQ count=%u\n", cnt);
786 /* Count of last transfer may be uneven. */
787 if (! (0 < cnt && cnt <= size - nread && (! (cnt & 1) || cnt == size - nread)))
788 return grub_error (GRUB_ERR_READ_ERROR, "Invalid ATAPI transfer count");
790 /* Read the data. */
791 grub_ata_pio_read (dev, buf + nread, cnt);
793 if (cnt & 1)
794 buf[nread + cnt - 1] = (char) grub_le_to_cpu16 (grub_inw (dev->ioaddress + GRUB_ATA_REG_DATA));
796 nread += cnt;
799 return GRUB_ERR_NONE;
802 static grub_err_t
803 grub_atapi_write (struct grub_scsi *scsi __attribute__((unused)),
804 grub_size_t cmdsize __attribute__((unused)),
805 char *cmd __attribute__((unused)),
806 grub_size_t size __attribute__((unused)),
807 char *buf __attribute__((unused)))
809 // XXX: scsi.mod does not use write yet.
810 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "ATAPI write not implemented");
813 static grub_err_t
814 grub_atapi_open (const char *name, struct grub_scsi *scsi)
816 struct grub_ata_device *dev;
817 struct grub_ata_device *devfnd = 0;
819 for (dev = grub_ata_devices; dev; dev = dev->next)
821 char devname[7];
822 grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device);
824 if (!grub_strcmp (devname, name))
826 devfnd = dev;
827 break;
831 grub_dprintf ("ata", "opening ATAPI dev `%s'\n", name);
833 if (! devfnd)
834 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such ATAPI device");
836 scsi->data = devfnd;
838 return GRUB_ERR_NONE;
841 static void
842 grub_atapi_close (struct grub_scsi *scsi)
844 grub_free (scsi->name);
847 static struct grub_scsi_dev grub_atapi_dev =
849 .name = "ATAPI",
850 .iterate = grub_atapi_iterate,
851 .open = grub_atapi_open,
852 .close = grub_atapi_close,
853 .read = grub_atapi_read,
854 .write = grub_atapi_write
859 GRUB_MOD_INIT(ata)
861 /* To prevent two drivers operating on the same disks. */
862 grub_disk_firmware_is_tainted = 1;
863 if (grub_disk_firmware_fini)
865 grub_disk_firmware_fini ();
866 grub_disk_firmware_fini = NULL;
869 /* ATA initialization. */
870 grub_ata_initialize ();
872 grub_disk_dev_register (&grub_atadisk_dev);
874 /* ATAPI devices are handled by scsi.mod. */
875 grub_scsi_dev_register (&grub_atapi_dev);
878 GRUB_MOD_FINI(ata)
880 grub_scsi_dev_unregister (&grub_atapi_dev);
881 grub_disk_dev_unregister (&grub_atadisk_dev);