1 /* ata.c - ATA disk access. */
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/>.
22 #include <grub/disk.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. */
32 grub_ata_strncpy (grub_uint16_t
*dst16
, grub_uint16_t
*src16
, grub_size_t len
)
36 for (i
= 0; i
< len
/ 2; i
++)
37 *(dst16
++) = grub_swap_bytes16 (*(src16
++));
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
);
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
);
63 grub_atapi_identify (struct grub_ata
*dev
)
65 struct grub_disk_ata_pass_through_parms parms
;
69 info
= grub_malloc (GRUB_DISK_SECTOR_SIZE
);
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
;
79 err
= dev
->dev
->readwrite (dev
, &parms
, *dev
->present
);
86 if (parms
.size
!= GRUB_DISK_SECTOR_SIZE
)
89 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
,
90 "device cannot be identified");
95 grub_ata_dumpinfo (dev
, info
);
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
;
111 info64
= grub_malloc (GRUB_DISK_SECTOR_SIZE
);
112 info32
= (grub_uint32_t
*) info64
;
113 info16
= (grub_uint16_t
*) info64
;
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
;
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)
140 /* No device, return error but don't print message. */
141 return GRUB_ERR_UNKNOWN_DEVICE
;
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. */
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
;
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]);
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)
181 for (dev
->log_sector_size
= 0;
182 (1U << dev
->log_sector_size
) < secsize
;
183 dev
->log_sector_size
++);
184 dev
->log_sector_size
++;
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
);
202 grub_ata_setaddress (struct grub_ata
*dev
,
203 struct grub_disk_ata_pass_through_parms
*parms
,
204 grub_disk_addr_t sector
,
206 grub_ata_addressing_t addressing
)
212 unsigned int cylinder
;
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
)
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;
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;
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;
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;
269 return GRUB_ERR_NONE
;
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
;
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)
291 cmd
= GRUB_ATA_CMD_READ_SECTORS_DMA_EXT
;
292 cmd_write
= GRUB_ATA_CMD_WRITE_SECTORS_DMA_EXT
;
296 cmd
= GRUB_ATA_CMD_READ_SECTORS_EXT
;
297 cmd_write
= GRUB_ATA_CMD_WRITE_SECTORS_EXT
;
302 if (addressing
== GRUB_ATA_LBA48
)
303 addressing
= GRUB_ATA_LBA
;
304 if (addressing
!= GRUB_ATA_CHS
)
310 cmd
= GRUB_ATA_CMD_READ_SECTORS_DMA
;
311 cmd_write
= GRUB_ATA_CMD_WRITE_SECTORS_DMA
;
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
;
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
);
336 parms
.size
= batch
<< ata
->log_sector_size
;
341 err
= ata
->dev
->readwrite (ata
, &parms
, 0);
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
;
351 return GRUB_ERR_NONE
;
357 grub_ata_real_close (struct grub_ata
*ata
)
360 ata
->dev
->close (ata
);
363 static struct grub_ata
*
364 grub_ata_real_open (int id
, int bus
)
366 struct grub_ata
*ata
;
369 ata
= grub_malloc (sizeof (*ata
));
372 for (p
= grub_ata_dev_list
; p
; p
= p
->next
)
375 if (p
->open (id
, bus
, ata
))
377 grub_errno
= GRUB_ERR_NONE
;
381 /* Use the IDENTIFY DEVICE command to query the device. */
382 err
= grub_ata_identify (ata
);
391 grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "no such ATA device");
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
;
406 ata
= grub_ata_real_open (id
, bus
);
410 grub_errno
= GRUB_ERR_NONE
;
415 grub_ata_real_close (ata
);
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
);
427 for (p
= grub_ata_dev_list
; p
; p
= p
->next
)
428 if (p
->iterate
&& p
->iterate (hook
, pull
))
434 grub_ata_open (const char *name
, grub_disk_t disk
)
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
])]))
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
);
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);
465 grub_ata_close (grub_disk_t disk
)
467 struct grub_ata
*ata
= disk
->data
;
468 grub_ata_real_close (ata
);
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);
479 grub_ata_write (grub_disk_t disk
,
480 grub_disk_addr_t sector
,
484 return grub_ata_readwrite (disk
, sector
, size
, (char *) buf
, 1);
487 static struct grub_disk_dev grub_atadisk_dev
=
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
,
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
;
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
;
521 parms
.cmdsize
= cmdsize
;
526 err
= dev
->dev
->readwrite (dev
, &parms
, 0);
530 if (parms
.size
!= size
)
531 return grub_error (GRUB_ERR_READ_ERROR
, "incomplete ATAPI read");
532 return GRUB_ERR_NONE
;
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");
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
);
556 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "no such ATAPI device");
561 return GRUB_ERR_NONE
;
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
;
574 ata
= grub_ata_real_open (id
, bus
);
578 grub_errno
= GRUB_ERR_NONE
;
583 grub_ata_real_close (ata
);
586 ret
= hook_in (id
, bus
, 1);
587 grub_ata_real_close (ata
);
593 for (p
= grub_ata_dev_list
; p
; p
= p
->next
)
594 if (p
->iterate
&& p
->iterate (hook
, pull
))
600 grub_atapi_close (grub_scsi_t disk
)
602 struct grub_ata
*ata
= disk
->data
;
603 grub_ata_real_close (ata
);
608 grub_ata_dev_register (grub_ata_dev_t dev
)
610 dev
->next
= grub_ata_dev_list
;
611 grub_ata_dev_list
= dev
;
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
)
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
,
641 grub_disk_dev_register (&grub_atadisk_dev
);
643 /* ATAPI devices are handled by scsi.mod. */
644 grub_scsi_dev_register (&grub_atapi_dev
);
649 grub_scsi_dev_unregister (&grub_atapi_dev
);
650 grub_disk_dev_unregister (&grub_atadisk_dev
);