Upgraded GRUB2 to 2.00 release.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / disk / ata.c
blobc0d378c1ac1bcb672dfa02c9cb06659e811210ba
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/scsi.h>
26 GRUB_MOD_LICENSE ("GPLv3+");
28 static grub_ata_dev_t grub_ata_dev_list;
30 /* Byteorder has to be changed before strings can be read. */
31 static void
32 grub_ata_strncpy (grub_uint16_t *dst16, grub_uint16_t *src16, grub_size_t len)
34 unsigned int i;
36 for (i = 0; i < len / 2; i++)
37 *(dst16++) = grub_swap_bytes16 (*(src16++));
38 *dst16 = 0;
41 static void
42 grub_ata_dumpinfo (struct grub_ata *dev, grub_uint16_t *info)
44 grub_uint16_t text[21];
46 /* The device information was read, dump it for debugging. */
47 grub_ata_strncpy (text, info + 10, 20);
48 grub_dprintf ("ata", "Serial: %s\n", (char *) text);
49 grub_ata_strncpy (text, info + 23, 8);
50 grub_dprintf ("ata", "Firmware: %s\n", (char *) text);
51 grub_ata_strncpy (text, info + 27, 40);
52 grub_dprintf ("ata", "Model: %s\n", (char *) text);
54 if (! dev->atapi)
56 grub_dprintf ("ata", "Addressing: %d\n", dev->addr);
57 grub_dprintf ("ata", "Sectors: %lld\n", (unsigned long long) dev->size);
58 grub_dprintf ("ata", "Sector size: %u\n", 1U << dev->log_sector_size);
62 static grub_err_t
63 grub_atapi_identify (struct grub_ata *dev)
65 struct grub_disk_ata_pass_through_parms parms;
66 grub_uint16_t *info;
67 grub_err_t err;
69 info = grub_malloc (GRUB_DISK_SECTOR_SIZE);
70 if (! info)
71 return grub_errno;
73 grub_memset (&parms, 0, sizeof (parms));
74 parms.taskfile.disk = 0xE0;
75 parms.taskfile.cmd = GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE;
76 parms.size = GRUB_DISK_SECTOR_SIZE;
77 parms.buffer = info;
79 err = dev->dev->readwrite (dev, &parms, *dev->present);
80 if (err)
82 *dev->present = 0;
83 return err;
86 if (parms.size != GRUB_DISK_SECTOR_SIZE)
88 *dev->present = 0;
89 return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
90 "device cannot be identified");
93 dev->atapi = 1;
95 grub_ata_dumpinfo (dev, info);
97 grub_free (info);
99 return GRUB_ERR_NONE;
102 static grub_err_t
103 grub_ata_identify (struct grub_ata *dev)
105 struct grub_disk_ata_pass_through_parms parms;
106 grub_uint64_t *info64;
107 grub_uint32_t *info32;
108 grub_uint16_t *info16;
109 grub_err_t err;
111 info64 = grub_malloc (GRUB_DISK_SECTOR_SIZE);
112 info32 = (grub_uint32_t *) info64;
113 info16 = (grub_uint16_t *) info64;
114 if (! info16)
115 return grub_errno;
117 grub_memset (&parms, 0, sizeof (parms));
118 parms.buffer = info16;
119 parms.size = GRUB_DISK_SECTOR_SIZE;
120 parms.taskfile.disk = 0xE0;
122 parms.taskfile.cmd = GRUB_ATA_CMD_IDENTIFY_DEVICE;
124 err = dev->dev->readwrite (dev, &parms, *dev->present);
126 if (err || parms.size != GRUB_DISK_SECTOR_SIZE)
128 grub_uint8_t sts = parms.taskfile.status;
129 grub_free (info16);
130 grub_errno = GRUB_ERR_NONE;
131 if ((sts & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ
132 | GRUB_ATA_STATUS_ERR)) == GRUB_ATA_STATUS_ERR
133 && (parms.taskfile.error & 0x04 /* ABRT */))
134 /* Device without ATA IDENTIFY, try ATAPI. */
135 return grub_atapi_identify (dev);
137 else if (sts == 0x00)
139 *dev->present = 0;
140 /* No device, return error but don't print message. */
141 return GRUB_ERR_UNKNOWN_DEVICE;
143 else
145 *dev->present = 0;
146 /* Other Error. */
147 return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
148 "device cannot be identified");
152 /* Now it is certain that this is not an ATAPI device. */
153 dev->atapi = 0;
155 /* CHS is always supported. */
156 dev->addr = GRUB_ATA_CHS;
158 /* Check if LBA is supported. */
159 if (info16[49] & grub_cpu_to_le16_compile_time ((1 << 9)))
161 /* Check if LBA48 is supported. */
162 if (info16[83] & grub_cpu_to_le16_compile_time ((1 << 10)))
163 dev->addr = GRUB_ATA_LBA48;
164 else
165 dev->addr = GRUB_ATA_LBA;
168 /* Determine the amount of sectors. */
169 if (dev->addr != GRUB_ATA_LBA48)
170 dev->size = grub_le_to_cpu32 (info32[30]);
171 else
172 dev->size = grub_le_to_cpu64 (info64[25]);
174 if (info16[106] & grub_cpu_to_le16_compile_time ((1 << 12)))
176 grub_uint32_t secsize;
177 secsize = grub_le_to_cpu32 (grub_get_unaligned32 (&info16[117]));
178 if (secsize & (secsize - 1) || !secsize
179 || secsize > 1048576)
180 secsize = 256;
181 for (dev->log_sector_size = 0;
182 (1U << dev->log_sector_size) < secsize;
183 dev->log_sector_size++);
184 dev->log_sector_size++;
186 else
187 dev->log_sector_size = 9;
189 /* Read CHS information. */
190 dev->cylinders = grub_le_to_cpu16 (info16[1]);
191 dev->heads = grub_le_to_cpu16 (info16[3]);
192 dev->sectors_per_track = grub_le_to_cpu16 (info16[6]);
194 grub_ata_dumpinfo (dev, info16);
196 grub_free (info16);
198 return 0;
201 static grub_err_t
202 grub_ata_setaddress (struct grub_ata *dev,
203 struct grub_disk_ata_pass_through_parms *parms,
204 grub_disk_addr_t sector,
205 grub_size_t size,
206 grub_ata_addressing_t addressing)
208 switch (addressing)
210 case GRUB_ATA_CHS:
212 unsigned int cylinder;
213 unsigned int head;
214 unsigned int sect;
216 /* Calculate the sector, cylinder and head to use. */
217 sect = ((grub_uint32_t) sector % dev->sectors_per_track) + 1;
218 cylinder = (((grub_uint32_t) sector / dev->sectors_per_track)
219 / dev->heads);
220 head = ((grub_uint32_t) sector / dev->sectors_per_track) % dev->heads;
222 if (sect > dev->sectors_per_track
223 || cylinder > dev->cylinders
224 || head > dev->heads)
225 return grub_error (GRUB_ERR_OUT_OF_RANGE,
226 "sector %d cannot be addressed "
227 "using CHS addressing", sector);
229 parms->taskfile.disk = 0xE0 | head;
230 parms->taskfile.sectnum = sect;
231 parms->taskfile.cyllsb = cylinder & 0xFF;
232 parms->taskfile.cylmsb = cylinder >> 8;
234 break;
237 case GRUB_ATA_LBA:
238 if (size == 256)
239 size = 0;
240 parms->taskfile.disk = 0xE0 | ((sector >> 24) & 0x0F);
242 parms->taskfile.sectors = size;
243 parms->taskfile.lba_low = sector & 0xFF;
244 parms->taskfile.lba_mid = (sector >> 8) & 0xFF;
245 parms->taskfile.lba_high = (sector >> 16) & 0xFF;
246 break;
248 case GRUB_ATA_LBA48:
249 if (size == 65536)
250 size = 0;
252 parms->taskfile.disk = 0xE0;
254 /* Set "Previous". */
255 parms->taskfile.sectors = size & 0xFF;
256 parms->taskfile.lba_low = sector & 0xFF;
257 parms->taskfile.lba_mid = (sector >> 8) & 0xFF;
258 parms->taskfile.lba_high = (sector >> 16) & 0xFF;
260 /* Set "Current". */
261 parms->taskfile.sectors48 = (size >> 8) & 0xFF;
262 parms->taskfile.lba48_low = (sector >> 24) & 0xFF;
263 parms->taskfile.lba48_mid = (sector >> 32) & 0xFF;
264 parms->taskfile.lba48_high = (sector >> 40) & 0xFF;
266 break;
269 return GRUB_ERR_NONE;
272 static grub_err_t
273 grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector,
274 grub_size_t size, char *buf, int rw)
276 struct grub_ata *ata = disk->data;
278 grub_ata_addressing_t addressing = ata->addr;
279 grub_size_t batch;
280 int cmd, cmd_write;
281 grub_size_t nsectors = 0;
283 grub_dprintf("ata", "grub_ata_readwrite (size=%llu, rw=%d)\n",
284 (unsigned long long) size, rw);
286 if (addressing == GRUB_ATA_LBA48 && ((sector + size) >> 28) != 0)
288 batch = 65536;
289 if (ata->dma)
291 cmd = GRUB_ATA_CMD_READ_SECTORS_DMA_EXT;
292 cmd_write = GRUB_ATA_CMD_WRITE_SECTORS_DMA_EXT;
294 else
296 cmd = GRUB_ATA_CMD_READ_SECTORS_EXT;
297 cmd_write = GRUB_ATA_CMD_WRITE_SECTORS_EXT;
300 else
302 if (addressing == GRUB_ATA_LBA48)
303 addressing = GRUB_ATA_LBA;
304 if (addressing != GRUB_ATA_CHS)
305 batch = 256;
306 else
307 batch = 1;
308 if (ata->dma)
310 cmd = GRUB_ATA_CMD_READ_SECTORS_DMA;
311 cmd_write = GRUB_ATA_CMD_WRITE_SECTORS_DMA;
313 else
315 cmd = GRUB_ATA_CMD_READ_SECTORS;
316 cmd_write = GRUB_ATA_CMD_WRITE_SECTORS;
320 if (batch > (ata->maxbuffer >> ata->log_sector_size))
321 batch = (ata->maxbuffer >> ata->log_sector_size);
323 while (nsectors < size)
325 struct grub_disk_ata_pass_through_parms parms;
326 grub_err_t err;
328 if (size - nsectors < batch)
329 batch = size - nsectors;
331 grub_dprintf("ata", "rw=%d, sector=%llu, batch=%llu\n", rw, (unsigned long long) sector, (unsigned long long) batch);
332 grub_memset (&parms, 0, sizeof (parms));
333 grub_ata_setaddress (ata, &parms, sector, batch, addressing);
334 parms.taskfile.cmd = (! rw ? cmd : cmd_write);
335 parms.buffer = buf;
336 parms.size = batch << ata->log_sector_size;
337 parms.write = rw;
338 if (ata->dma)
339 parms.dma = 1;
341 err = ata->dev->readwrite (ata, &parms, 0);
342 if (err)
343 return err;
344 if (parms.size != batch << ata->log_sector_size)
345 return grub_error (GRUB_ERR_READ_ERROR, "incomplete read");
346 buf += batch << ata->log_sector_size;
347 sector += batch;
348 nsectors += batch;
351 return GRUB_ERR_NONE;
356 static inline void
357 grub_ata_real_close (struct grub_ata *ata)
359 if (ata->dev->close)
360 ata->dev->close (ata);
363 static struct grub_ata *
364 grub_ata_real_open (int id, int bus)
366 struct grub_ata *ata;
367 grub_ata_dev_t p;
369 ata = grub_malloc (sizeof (*ata));
370 if (!ata)
371 return NULL;
372 for (p = grub_ata_dev_list; p; p = p->next)
374 grub_err_t err;
375 if (p->open (id, bus, ata))
377 grub_errno = GRUB_ERR_NONE;
378 continue;
380 ata->dev = p;
381 /* Use the IDENTIFY DEVICE command to query the device. */
382 err = grub_ata_identify (ata);
383 if (err)
385 grub_free (ata);
386 return NULL;
388 return ata;
390 grub_free (ata);
391 grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATA device");
392 return NULL;
395 static int
396 grub_ata_iterate (int (*hook_in) (const char *name),
397 grub_disk_pull_t pull)
399 auto int hook (int id, int bus);
400 int hook (int id, int bus)
402 struct grub_ata *ata;
403 int ret;
404 char devname[40];
406 ata = grub_ata_real_open (id, bus);
408 if (!ata)
410 grub_errno = GRUB_ERR_NONE;
411 return 0;
413 if (ata->atapi)
415 grub_ata_real_close (ata);
416 return 0;
418 grub_snprintf (devname, sizeof (devname),
419 "%s%d", grub_scsi_names[id], bus);
420 ret = hook_in (devname);
421 grub_ata_real_close (ata);
422 return ret;
425 grub_ata_dev_t p;
427 for (p = grub_ata_dev_list; p; p = p->next)
428 if (p->iterate && p->iterate (hook, pull))
429 return 1;
430 return 0;
433 static grub_err_t
434 grub_ata_open (const char *name, grub_disk_t disk)
436 unsigned id, bus;
437 struct grub_ata *ata;
439 for (id = 0; id < GRUB_SCSI_NUM_SUBSYSTEMS; id++)
440 if (grub_strncmp (grub_scsi_names[id], name,
441 grub_strlen (grub_scsi_names[id])) == 0
442 && grub_isdigit (name[grub_strlen (grub_scsi_names[id])]))
443 break;
444 if (id == GRUB_SCSI_NUM_SUBSYSTEMS)
445 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk");
446 bus = grub_strtoul (name + grub_strlen (grub_scsi_names[id]), 0, 0);
447 ata = grub_ata_real_open (id, bus);
448 if (!ata)
449 return grub_errno;
451 if (ata->atapi)
452 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk");
454 disk->total_sectors = ata->size;
455 disk->log_sector_size = ata->log_sector_size;
457 disk->id = grub_make_scsi_id (id, bus, 0);
459 disk->data = ata;
461 return 0;
464 static void
465 grub_ata_close (grub_disk_t disk)
467 struct grub_ata *ata = disk->data;
468 grub_ata_real_close (ata);
471 static grub_err_t
472 grub_ata_read (grub_disk_t disk, grub_disk_addr_t sector,
473 grub_size_t size, char *buf)
475 return grub_ata_readwrite (disk, sector, size, buf, 0);
478 static grub_err_t
479 grub_ata_write (grub_disk_t disk,
480 grub_disk_addr_t sector,
481 grub_size_t size,
482 const char *buf)
484 return grub_ata_readwrite (disk, sector, size, (char *) buf, 1);
487 static struct grub_disk_dev grub_atadisk_dev =
489 .name = "ATA",
490 .id = GRUB_DISK_DEVICE_ATA_ID,
491 .iterate = grub_ata_iterate,
492 .open = grub_ata_open,
493 .close = grub_ata_close,
494 .read = grub_ata_read,
495 .write = grub_ata_write,
496 .next = 0
501 /* ATAPI code. */
503 static grub_err_t
504 grub_atapi_read (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
505 grub_size_t size, char *buf)
507 struct grub_ata *dev = scsi->data;
508 struct grub_disk_ata_pass_through_parms parms;
509 grub_err_t err;
511 grub_dprintf("ata", "grub_atapi_read (size=%llu)\n", (unsigned long long) size);
512 grub_memset (&parms, 0, sizeof (parms));
514 parms.taskfile.disk = 0;
515 parms.taskfile.features = 0;
516 parms.taskfile.atapi_ireason = 0;
517 parms.taskfile.atapi_cnthigh = size >> 8;
518 parms.taskfile.atapi_cntlow = size & 0xff;
519 parms.taskfile.cmd = GRUB_ATA_CMD_PACKET;
520 parms.cmd = cmd;
521 parms.cmdsize = cmdsize;
523 parms.size = size;
524 parms.buffer = buf;
526 err = dev->dev->readwrite (dev, &parms, 0);
527 if (err)
528 return err;
530 if (parms.size != size)
531 return grub_error (GRUB_ERR_READ_ERROR, "incomplete ATAPI read");
532 return GRUB_ERR_NONE;
535 static grub_err_t
536 grub_atapi_write (struct grub_scsi *scsi __attribute__((unused)),
537 grub_size_t cmdsize __attribute__((unused)),
538 char *cmd __attribute__((unused)),
539 grub_size_t size __attribute__((unused)),
540 const char *buf __attribute__((unused)))
542 // XXX: scsi.mod does not use write yet.
543 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "ATAPI write not implemented");
546 static grub_err_t
547 grub_atapi_open (int id, int bus, struct grub_scsi *scsi)
549 struct grub_ata *ata;
551 ata = grub_ata_real_open (id, bus);
552 if (!ata)
553 return grub_errno;
555 if (! ata->atapi)
556 return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device");
558 scsi->data = ata;
559 scsi->luns = 1;
561 return GRUB_ERR_NONE;
564 static int
565 grub_atapi_iterate (int NESTED_FUNC_ATTR (*hook_in) (int id, int bus, int luns),
566 grub_disk_pull_t pull)
568 auto int hook (int id, int bus);
569 int hook (int id, int bus)
571 struct grub_ata *ata;
572 int ret;
574 ata = grub_ata_real_open (id, bus);
576 if (!ata)
578 grub_errno = GRUB_ERR_NONE;
579 return 0;
581 if (!ata->atapi)
583 grub_ata_real_close (ata);
584 return 0;
586 ret = hook_in (id, bus, 1);
587 grub_ata_real_close (ata);
588 return ret;
591 grub_ata_dev_t p;
593 for (p = grub_ata_dev_list; p; p = p->next)
594 if (p->iterate && p->iterate (hook, pull))
595 return 1;
596 return 0;
599 static void
600 grub_atapi_close (grub_scsi_t disk)
602 struct grub_ata *ata = disk->data;
603 grub_ata_real_close (ata);
607 void
608 grub_ata_dev_register (grub_ata_dev_t dev)
610 dev->next = grub_ata_dev_list;
611 grub_ata_dev_list = dev;
614 void
615 grub_ata_dev_unregister (grub_ata_dev_t dev)
617 grub_ata_dev_t *p, q;
619 for (p = &grub_ata_dev_list, q = *p; q; p = &(q->next), q = q->next)
620 if (q == dev)
622 *p = q->next;
623 break;
627 static struct grub_scsi_dev grub_atapi_dev =
629 .iterate = grub_atapi_iterate,
630 .open = grub_atapi_open,
631 .close = grub_atapi_close,
632 .read = grub_atapi_read,
633 .write = grub_atapi_write,
634 .next = 0
639 GRUB_MOD_INIT(ata)
641 grub_disk_dev_register (&grub_atadisk_dev);
643 /* ATAPI devices are handled by scsi.mod. */
644 grub_scsi_dev_register (&grub_atapi_dev);
647 GRUB_MOD_FINI(ata)
649 grub_scsi_dev_unregister (&grub_atapi_dev);
650 grub_disk_dev_unregister (&grub_atadisk_dev);