4 Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
6 This program 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 2 of the License, or
9 (at your option) any later version.
11 This program 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 this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "scsi_ioctls.h"
32 #include "efibootmgr.h"
34 #define BLKSSZGET _IO(0x12,104) /* get block device sector size */
37 disk_info_from_fd(int fd,
39 unsigned int *controllernum,
40 unsigned int *disknum,
47 memset(&buf, 0, sizeof(struct stat));
53 if (!(S_ISBLK(buf.st_mode) || S_ISREG(buf.st_mode))) {
54 printf("Cannot stat non-block or non-regular file\n");
57 major = buf.st_dev >> 8;
58 minor = buf.st_dev && 0xFF;
60 /* IDE disks can have up to 64 partitions, or 6 bits worth,
61 * and have one bit for the disk number.
62 * This leaves an extra bit at the top.
65 *disknum = (minor >> 6) & 1;
66 *controllernum = (major - 3 + 0) + *disknum;
67 *interface_type = ata;
71 else if (major == 22) {
72 *disknum = (minor >> 6) & 1;
73 *controllernum = (major - 22 + 2) + *disknum;
74 *interface_type = ata;
78 else if (major >= 33 && major <= 34) {
79 *disknum = (minor >> 6) & 1;
80 *controllernum = (major - 33 + 4) + *disknum;
81 *interface_type = ata;
85 else if (major >= 56 && major <= 57) {
86 *disknum = (minor >> 6) & 1;
87 *controllernum = (major - 56 + 8) + *disknum;
88 *interface_type = ata;
92 else if (major >= 88 && major <= 91) {
93 *disknum = (minor >> 6) & 1;
94 *controllernum = (major - 88 + 12) + *disknum;
95 *interface_type = ata;
100 /* I2O disks can have up to 16 partitions, or 4 bits worth. */
101 if (major >= 80 && major <= 87) {
102 *interface_type = i2o;
103 *disknum = 16*(major-80) + (minor >> 4);
104 *part = (minor & 0xF);
108 /* SCSI disks can have up to 16 partitions, or 4 bits worth
109 * and have one bit for the disk number.
112 *interface_type = scsi;
113 *disknum = (minor >> 4);
114 *part = (minor & 0xF);
117 else if ( major >= 65 && major <= 71) {
118 *interface_type = scsi;
119 *disknum = 16*(major-64) + (minor >> 4);
120 *part = (minor & 0xF);
124 printf("Unknown interface type.\n");
129 disk_get_scsi_pci(int fd,
131 unsigned char *device,
132 unsigned char *function)
137 unsigned int b=0,d=0,f=0;
138 memset(&buf, 0, sizeof(buf));
139 rc = fstat(fd, &buf);
144 if (S_ISREG(buf.st_mode)) {
145 /* can't call ioctl() on this file and have it succeed.
146 * instead, need to open the block device
149 fprintf(stderr, "You must call this program with "
150 "a file name such as /dev/sda.\n");
154 rc = get_scsi_pci(usefd, slot_name);
156 perror("get_scsi_pci");
159 rc = sscanf(slot_name, "%x:%x.%x", &b,&d,&f);
161 printf("sscanf failed\n");
166 *function = f & 0xFF;
171 * The PCI interface treats multi-function devices as independent
172 * devices. The slot/function address of each device is encoded
173 * in a single byte as follows:
178 * pci bus 00 device 39 vid 8086 did 7111 channel 1
181 #define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
182 #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
183 #define PCI_FUNC(devfn) ((devfn) & 0x07)
186 disk_get_ide_pci(int fd,
188 unsigned char *device,
189 unsigned char *function)
191 int num_scanned, procfd;
192 unsigned int b=0,d=0,disknum=0, controllernum=0;
193 unsigned char part=0;
194 char procname[80], infoline[80];
199 rc = disk_info_from_fd(fd, &interface_type, &controllernum,
204 sprintf(procname, "/proc/ide/ide%d/config", controllernum);
206 procfd = open(procname, O_RDONLY);
208 perror("opening /proc/ide/ide*/config");
211 read_count = read(procfd, infoline, sizeof(infoline)-1);
214 num_scanned = sscanf(infoline,
215 "pci bus %x device %x vid %*x did %*x channel %*x",
218 if (num_scanned == 2) {
220 *device = PCI_SLOT(d);
221 *function = PCI_FUNC(d);
229 /* this is a list of devices */
231 disk_get_md_parts(int fd)
240 unsigned char *device,
241 unsigned char *function)
243 int interface_type=interface_type_unknown;
244 unsigned int controllernum=0, disknum=0;
245 unsigned char part=0;
247 disk_info_from_fd(fd,
252 switch (interface_type) {
254 return disk_get_ide_pci(fd, bus, device, function);
257 return disk_get_scsi_pci(fd, bus, device, function);
270 disk_get_size(int fd, long *size)
272 return ioctl(fd, BLKGETSIZE, size);
276 * is_mbr_valid(): test MBR for validity
277 * @mbr: pointer to a legacy mbr structure
279 * Description: Returns 1 if MBR is valid, 0 otherwise.
280 * Validity depends on one thing:
281 * 1) MSDOS signature is in the last two bytes of the MBR
284 is_mbr_valid(legacy_mbr *mbr)
288 return (mbr->signature == MSDOS_MBR_SIGNATURE);
291 /************************************************************
292 * msdos_disk_get_extended partition_info()
294 * - open file descriptor fd
296 * Modifies: all these
299 * non-zero on failure
301 ************************************************************/
304 msdos_disk_get_extended_partition_info (int fd, legacy_mbr *mbr,
306 uint64_t *start, uint64_t *size)
308 /* Until I can handle these... */
309 fprintf(stderr, "Extended partition info not supported.\n");
313 /************************************************************
314 * msdos_disk_get_partition_info()
317 * - open file descriptor fd (for extended partitions)
318 * - start, size, signature, mbr_type, signature_type
319 * Modifies: all these
322 * non-zero on failure
324 ************************************************************/
327 msdos_disk_get_partition_info (int fd, legacy_mbr *mbr,
329 uint64_t *start, uint64_t *size,
331 uint8_t *mbr_type, uint8_t *signature_type)
339 if (!is_mbr_valid(mbr)) return 1;
342 *signature_type = 0x01;
344 if (!mbr->unique_mbr_signature && !opts.write_signature) {
346 printf("\n\n******************************************************\n");
347 printf("Warning! This MBR disk does not have a unique signature.\n");
348 printf("If this is not the first disk found by EFI, you may not be able\n");
349 printf("to boot from it without a unique signature.\n");
350 printf("Run efibootmgr with the -w flag to write a unique signature\n");
351 printf("to the disk.\n");
352 printf("******************************************************\n\n");
355 else if (opts.write_signature) {
357 /* MBR Signatures must be unique for the
359 to find the right disk to boot from */
361 rc = fstat(fd, &stat);
366 rc = gettimeofday(&tv, NULL);
368 perror("gettimeofday");
371 /* Write the device type to the signature.
372 This should be unique per disk per system */
373 mbr->unique_mbr_signature = tv.tv_usec << 16;
374 mbr->unique_mbr_signature |= stat.st_rdev & 0xFFFF;
376 /* Write it to the disk */
377 lseek(fd, 0, SEEK_SET);
378 write(fd, mbr, sizeof(*mbr));
381 *(uint32_t *)signature = mbr->unique_mbr_signature;
385 /* Extended partition */
386 return msdos_disk_get_extended_partition_info(fd, mbr, num,
392 disk_get_size(fd, &disk_size);
395 else if (num >= 1 && num <= 4) {
396 /* Primary partition */
397 *start = mbr->partition[num-1].starting_lba;
398 *size = mbr->partition[num-1].size_in_lba;
404 /************************************************************
407 * - filedes is an open file descriptor, suitable for reading
410 * sector size, or 512.
411 ************************************************************/
413 get_sector_size(int filedes)
415 int rc, sector_size = 512;
417 rc = ioctl(filedes, BLKSSZGET, §or_size);
423 /************************************************************
426 * - numbers of which to find the lowest common multiple
429 * lowest common multiple of x and y
430 ************************************************************/
432 lcm(unsigned int x, unsigned int y)
434 unsigned int m = x, n = y, o;
436 while ((o = m % n)) {
445 * disk_get_partition_info()
446 * @fd - open file descriptor to disk
447 * @num - partition number (1 is first partition on the disk)
448 * @start - partition starting sector returned
449 * @size - partition size (in sectors) returned
450 * @signature - partition signature returned
451 * @mbr_type - partition type returned
452 * @signature_type - signature type returned
454 * Description: Finds partition table info for given partition on given disk.
455 * Both GPT and MSDOS partition tables are tested for.
456 * Returns 0 on success, non-zero on failure
459 disk_get_partition_info (int fd,
461 uint64_t *start, uint64_t *size,
463 uint8_t *mbr_type, uint8_t *signature_type)
469 int this_bytes_read = 0;
470 int gpt_invalid=0, mbr_invalid=0;
472 int sector_size = get_sector_size(fd);
475 mbr_size = lcm(sizeof(*mbr), sector_size);
476 if ((rc = posix_memalign(&mbr_sector, sector_size, mbr_size)) != 0)
478 memset(mbr_sector, '\0', mbr_size);
480 offset = lseek(fd, 0, SEEK_SET);
481 this_bytes_read = read(fd, mbr_sector, mbr_size);
482 if (this_bytes_read < sizeof(*mbr)) {
486 mbr = (legacy_mbr *)mbr_sector;
487 gpt_invalid = gpt_disk_get_partition_info(fd, num,
493 mbr_invalid = msdos_disk_get_partition_info(fd, mbr, num,
511 main (int argc, char *argv[])
514 unsigned char bus=0,device=0,func=0;
515 if (argc <= 1) return 1;
516 fd = open(argv[1], O_RDONLY|O_DIRECT);
517 rc = disk_get_pci(fd, &bus, &device, &func);
519 printf("PCI %02x:%02x.%02x\n", bus, device, func);