]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/efi/libefi/efipart.c
MFV r337195: 9454 ::zfs_blkstats should count embedded blocks
[FreeBSD/FreeBSD.git] / stand / efi / libefi / efipart.c
1 /*-
2  * Copyright (c) 2010 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/disk.h>
31 #include <sys/param.h>
32 #include <sys/time.h>
33 #include <sys/queue.h>
34 #include <stddef.h>
35 #include <stdarg.h>
36
37 #include <bootstrap.h>
38
39 #include <efi.h>
40 #include <efilib.h>
41 #include <efiprot.h>
42 #include <efichar.h>
43 #include <disk.h>
44
45 static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL;
46
47 static int efipart_initfd(void);
48 static int efipart_initcd(void);
49 static int efipart_inithd(void);
50
51 static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *);
52 static int efipart_realstrategy(void *, int, daddr_t, size_t, char *, size_t *);
53
54 static int efipart_open(struct open_file *, ...);
55 static int efipart_close(struct open_file *);
56 static int efipart_ioctl(struct open_file *, u_long, void *);
57
58 static int efipart_printfd(int);
59 static int efipart_printcd(int);
60 static int efipart_printhd(int);
61
62 /* EISA PNP ID's for floppy controllers */
63 #define PNP0604 0x604
64 #define PNP0700 0x700
65 #define PNP0701 0x701
66
67 struct devsw efipart_fddev = {
68         .dv_name = "fd",
69         .dv_type = DEVT_FD,
70         .dv_init = efipart_initfd,
71         .dv_strategy = efipart_strategy,
72         .dv_open = efipart_open,
73         .dv_close = efipart_close,
74         .dv_ioctl = efipart_ioctl,
75         .dv_print = efipart_printfd,
76         .dv_cleanup = NULL
77 };
78
79 struct devsw efipart_cddev = {
80         .dv_name = "cd",
81         .dv_type = DEVT_CD,
82         .dv_init = efipart_initcd,
83         .dv_strategy = efipart_strategy,
84         .dv_open = efipart_open,
85         .dv_close = efipart_close,
86         .dv_ioctl = efipart_ioctl,
87         .dv_print = efipart_printcd,
88         .dv_cleanup = NULL
89 };
90
91 struct devsw efipart_hddev = {
92         .dv_name = "disk",
93         .dv_type = DEVT_DISK,
94         .dv_init = efipart_inithd,
95         .dv_strategy = efipart_strategy,
96         .dv_open = efipart_open,
97         .dv_close = efipart_close,
98         .dv_ioctl = efipart_ioctl,
99         .dv_print = efipart_printhd,
100         .dv_cleanup = NULL
101 };
102
103 static pdinfo_list_t fdinfo;
104 static pdinfo_list_t cdinfo;
105 static pdinfo_list_t hdinfo;
106
107 static EFI_HANDLE *efipart_handles = NULL;
108 static UINTN efipart_nhandles = 0;
109
110 pdinfo_list_t *
111 efiblk_get_pdinfo_list(struct devsw *dev)
112 {
113         if (dev->dv_type == DEVT_DISK)
114                 return (&hdinfo);
115         if (dev->dv_type == DEVT_CD)
116                 return (&cdinfo);
117         if (dev->dv_type == DEVT_FD)
118                 return (&fdinfo);
119         return (NULL);
120 }
121
122 /* XXX this gets called way way too often, investigate */
123 pdinfo_t *
124 efiblk_get_pdinfo(struct devdesc *dev)
125 {
126         pdinfo_list_t *pdi;
127         pdinfo_t *pd = NULL;
128
129         pdi = efiblk_get_pdinfo_list(dev->d_dev);
130         if (pdi == NULL)
131                 return (pd);
132
133         STAILQ_FOREACH(pd, pdi, pd_link) {
134                 if (pd->pd_unit == dev->d_unit)
135                         return (pd);
136         }
137         return (pd);
138 }
139
140 pdinfo_t *
141 efiblk_get_pdinfo_by_device_path(EFI_DEVICE_PATH *path)
142 {
143         unsigned i;
144         EFI_DEVICE_PATH *media, *devpath;
145         EFI_HANDLE h;
146
147         media = efi_devpath_to_media_path(path);
148         if (media == NULL)
149                 return (NULL);
150         for (i = 0; i < efipart_nhandles; i++) {
151                 h = efipart_handles[i];
152                 devpath = efi_lookup_devpath(h);
153                 if (devpath == NULL)
154                         continue;
155                 if (!efi_devpath_match_node(media, efi_devpath_to_media_path(devpath)))
156                         continue;
157                 return (efiblk_get_pdinfo_by_handle(h));
158         }
159         return (NULL);
160 }
161
162 static bool
163 same_handle(pdinfo_t *pd, EFI_HANDLE h)
164 {
165
166         return (pd->pd_handle == h || pd->pd_alias == h);
167 }
168
169 pdinfo_t *
170 efiblk_get_pdinfo_by_handle(EFI_HANDLE h)
171 {
172         pdinfo_t *dp, *pp;
173
174         /*
175          * Check hard disks, then cd, then floppy
176          */
177         STAILQ_FOREACH(dp, &hdinfo, pd_link) {
178                 if (same_handle(dp, h))
179                         return (dp);
180                 STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
181                         if (same_handle(pp, h))
182                                 return (pp);
183                 }
184         }
185         STAILQ_FOREACH(dp, &cdinfo, pd_link) {
186                 if (same_handle(dp, h))
187                         return (dp);
188         }
189         STAILQ_FOREACH(dp, &fdinfo, pd_link) {
190                 if (same_handle(dp, h))
191                         return (dp);
192         }
193         return (NULL);
194 }
195
196 static int
197 efiblk_pdinfo_count(pdinfo_list_t *pdi)
198 {
199         pdinfo_t *pd;
200         int i = 0;
201
202         STAILQ_FOREACH(pd, pdi, pd_link) {
203                 i++;
204         }
205         return (i);
206 }
207
208 int
209 efipart_inithandles(void)
210 {
211         UINTN sz;
212         EFI_HANDLE *hin;
213         EFI_STATUS status;
214
215         if (efipart_nhandles != 0) {
216                 free(efipart_handles);
217                 efipart_handles = NULL;
218                 efipart_nhandles = 0;
219         }
220
221         sz = 0;
222         hin = NULL;
223         status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, hin);
224         if (status == EFI_BUFFER_TOO_SMALL) {
225                 hin = malloc(sz);
226                 status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz,
227                     hin);
228                 if (EFI_ERROR(status))
229                         free(hin);
230         }
231         if (EFI_ERROR(status))
232                 return (efi_status_to_errno(status));
233
234         efipart_handles = hin;
235         efipart_nhandles = sz / sizeof(*hin);
236 #ifdef EFIPART_DEBUG
237         printf("%s: Got %d BLOCK IO MEDIA handle(s)\n", __func__,
238             efipart_nhandles);
239 #endif
240         return (0);
241 }
242
243 static ACPI_HID_DEVICE_PATH *
244 efipart_floppy(EFI_DEVICE_PATH *node)
245 {
246         ACPI_HID_DEVICE_PATH *acpi;
247
248         if (DevicePathType(node) == ACPI_DEVICE_PATH &&
249             DevicePathSubType(node) == ACPI_DP) {
250                 acpi = (ACPI_HID_DEVICE_PATH *) node;
251                 if (acpi->HID == EISA_PNP_ID(PNP0604) ||
252                     acpi->HID == EISA_PNP_ID(PNP0700) ||
253                     acpi->HID == EISA_PNP_ID(PNP0701)) {
254                         return (acpi);
255                 }
256         }
257         return (NULL);
258 }
259
260 /*
261  * Determine if the provided device path is hdd.
262  *
263  * There really is no simple fool proof way to classify the devices.
264  * Since we do build three lists of devices - floppy, cd and hdd, we
265  * will try to see  if the device is floppy or cd, and list anything else
266  * as hdd.
267  */
268 static bool
269 efipart_hdd(EFI_DEVICE_PATH *dp)
270 {
271         unsigned i;
272         EFI_DEVICE_PATH *devpath, *node;
273         EFI_BLOCK_IO *blkio;
274         EFI_STATUS status;
275
276         if (dp == NULL)
277                 return (false);
278
279         if ((node = efi_devpath_last_node(dp)) == NULL)
280                 return (false);
281
282         if (efipart_floppy(node) != NULL)
283                 return (false);
284
285         /*
286          * Test every EFI BLOCK IO handle to make sure dp is not device path
287          * for CD/DVD.
288          */
289         for (i = 0; i < efipart_nhandles; i++) {
290                 devpath = efi_lookup_devpath(efipart_handles[i]);
291                 if (devpath == NULL)
292                         return (false);
293
294                 /* Only continue testing when dp is prefix in devpath. */
295                 if (!efi_devpath_is_prefix(dp, devpath))
296                         continue;
297
298                 /*
299                  * The device path has to have last node describing the
300                  *  device, or we can not test the type.
301                  */
302                 if ((node = efi_devpath_last_node(devpath)) == NULL)
303                         return (false);
304
305                 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
306                     DevicePathSubType(node) == MEDIA_CDROM_DP) {
307                         return (false);
308                 }
309
310                 /* Make sure we do have the media. */
311                 status = BS->HandleProtocol(efipart_handles[i],
312                     &blkio_guid, (void **)&blkio);
313                 if (EFI_ERROR(status))
314                         return (false);
315
316                 /* USB or SATA cd without the media. */
317                 if (blkio->Media->RemovableMedia &&
318                     !blkio->Media->MediaPresent) {
319                         return (false);
320                 }
321
322                 /*
323                  * We assume the block size 512 or greater power of 2. 
324                  * iPXE is known to insert stub BLOCK IO device with
325                  * BlockSize 1.
326                  */
327                 if (blkio->Media->BlockSize < 512 ||
328                     !powerof2(blkio->Media->BlockSize)) {
329                         return (false);
330                 }
331         }
332         return (true);
333 }
334
335 /*
336  * Add or update entries with new handle data.
337  */
338 static int
339 efipart_fdinfo_add(EFI_HANDLE handle, uint32_t uid, EFI_DEVICE_PATH *devpath)
340 {
341         pdinfo_t *fd;
342
343         fd = calloc(1, sizeof(pdinfo_t));
344         if (fd == NULL) {
345                 printf("Failed to register floppy %d, out of memory\n", uid);
346                 return (ENOMEM);
347         }
348         STAILQ_INIT(&fd->pd_part);
349
350         fd->pd_unit = uid;
351         fd->pd_handle = handle;
352         fd->pd_devpath = devpath;
353         fd->pd_parent = NULL;
354         fd->pd_devsw = &efipart_fddev;
355         STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
356         return (0);
357 }
358
359 static void
360 efipart_updatefd(void)
361 {
362         EFI_DEVICE_PATH *devpath, *node;
363         ACPI_HID_DEVICE_PATH *acpi;
364         int i;
365
366         for (i = 0; i < efipart_nhandles; i++) {
367                 devpath = efi_lookup_devpath(efipart_handles[i]);
368                 if (devpath == NULL)
369                         continue;
370
371                 if ((node = efi_devpath_last_node(devpath)) == NULL)
372                         continue;
373                 if ((acpi = efipart_floppy(node)) != NULL) {
374                         efipart_fdinfo_add(efipart_handles[i], acpi->UID,
375                             devpath);
376                 }
377         }
378 }
379
380 static int
381 efipart_initfd(void)
382 {
383
384         STAILQ_INIT(&fdinfo);
385
386         efipart_updatefd();
387
388         bcache_add_dev(efiblk_pdinfo_count(&fdinfo));
389         return (0);
390 }
391
392 /*
393  * Add or update entries with new handle data.
394  */
395 static int
396 efipart_cdinfo_add(EFI_HANDLE handle, EFI_HANDLE alias,
397     EFI_DEVICE_PATH *devpath)
398 {
399         int unit;
400         pdinfo_t *cd;
401         pdinfo_t *pd;
402
403         unit = 0;
404         STAILQ_FOREACH(pd, &cdinfo, pd_link) {
405                 if (efi_devpath_match(pd->pd_devpath, devpath) == true) {
406                         pd->pd_handle = handle;
407                         pd->pd_alias = alias;
408                         return (0);
409                 }
410                 unit++;
411         }
412
413         cd = calloc(1, sizeof(pdinfo_t));
414         if (cd == NULL) {
415                 printf("Failed to add cd %d, out of memory\n", unit);
416                 return (ENOMEM);
417         }
418         STAILQ_INIT(&cd->pd_part);
419
420         cd->pd_handle = handle;
421         cd->pd_unit = unit;
422         cd->pd_alias = alias;
423         cd->pd_devpath = devpath;
424         cd->pd_parent = NULL;
425         cd->pd_devsw = &efipart_cddev;
426         STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link);
427         return (0);
428 }
429
430 static void
431 efipart_updatecd(void)
432 {
433         int i;
434         EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
435         EFI_HANDLE handle;
436         EFI_BLOCK_IO *blkio;
437         EFI_STATUS status;
438
439         for (i = 0; i < efipart_nhandles; i++) {
440                 devpath = efi_lookup_devpath(efipart_handles[i]);
441                 if (devpath == NULL)
442                         continue;
443
444                 if ((node = efi_devpath_last_node(devpath)) == NULL)
445                         continue;
446
447                 if (efipart_floppy(node) != NULL)
448                         continue;
449
450                 if (efipart_hdd(devpath))
451                         continue;
452
453                 status = BS->HandleProtocol(efipart_handles[i],
454                     &blkio_guid, (void **)&blkio);
455                 if (EFI_ERROR(status))
456                         continue;
457                 /*
458                  * If we come across a logical partition of subtype CDROM
459                  * it doesn't refer to the CD filesystem itself, but rather
460                  * to any usable El Torito boot image on it. In this case
461                  * we try to find the parent device and add that instead as
462                  * that will be the CD filesystem.
463                  */
464                 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
465                     DevicePathSubType(node) == MEDIA_CDROM_DP) {
466                         devpathcpy = efi_devpath_trim(devpath);
467                         if (devpathcpy == NULL)
468                                 continue;
469                         tmpdevpath = devpathcpy;
470                         status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath,
471                             &handle);
472                         free(devpathcpy);
473                         if (EFI_ERROR(status))
474                                 continue;
475                         devpath = efi_lookup_devpath(handle);
476                         efipart_cdinfo_add(handle, efipart_handles[i],
477                             devpath);
478                         continue;
479                 }
480
481                 if (DevicePathType(node) == MESSAGING_DEVICE_PATH &&
482                     DevicePathSubType(node) == MSG_ATAPI_DP) {
483                         efipart_cdinfo_add(efipart_handles[i], NULL,
484                             devpath);
485                         continue;
486                 }
487
488                 /* USB or SATA cd without the media. */
489                 if (blkio->Media->RemovableMedia &&
490                     !blkio->Media->MediaPresent) {
491                         efipart_cdinfo_add(efipart_handles[i], NULL,
492                             devpath);
493                 }
494         }
495 }
496
497 static int
498 efipart_initcd(void)
499 {
500
501         STAILQ_INIT(&cdinfo);
502
503         efipart_updatecd();
504
505         bcache_add_dev(efiblk_pdinfo_count(&cdinfo));
506         return (0);
507 }
508
509 static int
510 efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle)
511 {
512         EFI_DEVICE_PATH *disk_devpath, *part_devpath;
513         HARDDRIVE_DEVICE_PATH *node;
514         int unit;
515         pdinfo_t *hd, *pd, *last;
516
517         disk_devpath = efi_lookup_devpath(disk_handle);
518         if (disk_devpath == NULL)
519                 return (ENOENT);
520
521         if (part_handle != NULL) {
522                 part_devpath = efi_lookup_devpath(part_handle);
523                 if (part_devpath == NULL)
524                         return (ENOENT);
525                 node = (HARDDRIVE_DEVICE_PATH *)
526                     efi_devpath_last_node(part_devpath);
527                 if (node == NULL)
528                         return (ENOENT);        /* This should not happen. */
529         } else {
530                 part_devpath = NULL;
531                 node = NULL;
532         }
533
534         pd = calloc(1, sizeof(pdinfo_t));
535         if (pd == NULL) {
536                 printf("Failed to add disk, out of memory\n");
537                 return (ENOMEM);
538         }
539         STAILQ_INIT(&pd->pd_part);
540
541         STAILQ_FOREACH(hd, &hdinfo, pd_link) {
542                 if (efi_devpath_match(hd->pd_devpath, disk_devpath) == true) {
543                         if (part_devpath == NULL)
544                                 return (0);
545
546                         /* Add the partition. */
547                         pd->pd_handle = part_handle;
548                         pd->pd_unit = node->PartitionNumber;
549                         pd->pd_devpath = part_devpath;
550                         pd->pd_parent = hd;
551                         pd->pd_devsw = &efipart_hddev;
552                         STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
553                         return (0);
554                 }
555         }
556
557         last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
558         if (last != NULL)
559                 unit = last->pd_unit + 1;
560         else
561                 unit = 0;
562
563         /* Add the disk. */
564         hd = pd;
565         hd->pd_handle = disk_handle;
566         hd->pd_unit = unit;
567         hd->pd_devpath = disk_devpath;
568         hd->pd_parent = NULL;
569         hd->pd_devsw = &efipart_hddev;
570         STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
571
572         if (part_devpath == NULL)
573                 return (0);
574
575         pd = calloc(1, sizeof(pdinfo_t));
576         if (pd == NULL) {
577                 printf("Failed to add partition, out of memory\n");
578                 return (ENOMEM);
579         }
580         STAILQ_INIT(&pd->pd_part);
581
582         /* Add the partition. */
583         pd->pd_handle = part_handle;
584         pd->pd_unit = node->PartitionNumber;
585         pd->pd_devpath = part_devpath;
586         pd->pd_parent = hd;
587         pd->pd_devsw = &efipart_hddev;
588         STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
589
590         return (0);
591 }
592
593 /*
594  * The MEDIA_FILEPATH_DP has device name.
595  * From U-Boot sources it looks like names are in the form
596  * of typeN:M, where type is interface type, N is disk id
597  * and M is partition id.
598  */
599 static int
600 efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle)
601 {
602         EFI_DEVICE_PATH *devpath;
603         FILEPATH_DEVICE_PATH *node;
604         char *pathname, *p;
605         int unit, len;
606         pdinfo_t *pd, *last;
607
608         /* First collect and verify all the data */
609         if ((devpath = efi_lookup_devpath(disk_handle)) == NULL)
610                 return (ENOENT);
611         node = (FILEPATH_DEVICE_PATH *)efi_devpath_last_node(devpath);
612         if (node == NULL)
613                 return (ENOENT);        /* This should not happen. */
614
615         pd = calloc(1, sizeof(pdinfo_t));
616         if (pd == NULL) {
617                 printf("Failed to add disk, out of memory\n");
618                 return (ENOMEM);
619         }
620         STAILQ_INIT(&pd->pd_part);
621         last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
622         if (last != NULL)
623                 unit = last->pd_unit + 1;
624         else
625                 unit = 0;
626
627         /* FILEPATH_DEVICE_PATH has 0 terminated string */
628         len = ucs2len(node->PathName);
629         if ((pathname = malloc(len + 1)) == NULL) {
630                 printf("Failed to add disk, out of memory\n");
631                 free(pd);
632                 return (ENOMEM);
633         }
634         cpy16to8(node->PathName, pathname, len + 1);
635         p = strchr(pathname, ':');
636
637         /*
638          * Assume we are receiving handles in order, first disk handle,
639          * then partitions for this disk. If this assumption proves
640          * false, this code would need update.
641          */
642         if (p == NULL) {        /* no colon, add the disk */
643                 pd->pd_handle = disk_handle;
644                 pd->pd_unit = unit;
645                 pd->pd_devpath = devpath;
646                 pd->pd_parent = NULL;
647                 pd->pd_devsw = &efipart_hddev;
648                 STAILQ_INSERT_TAIL(&hdinfo, pd, pd_link);
649                 free(pathname);
650                 return (0);
651         }
652         p++;    /* skip the colon */
653         errno = 0;
654         unit = (int)strtol(p, NULL, 0);
655         if (errno != 0) {
656                 printf("Bad unit number for partition \"%s\"\n", pathname);
657                 free(pathname);
658                 free(pd);
659                 return (EUNIT);
660         }
661
662         /*
663          * We should have disk registered, if not, we are receiving
664          * handles out of order, and this code should be reworked
665          * to create "blank" disk for partition, and to find the
666          * disk based on PathName compares.
667          */
668         if (last == NULL) {
669                 printf("BUG: No disk for partition \"%s\"\n", pathname);
670                 free(pathname);
671                 free(pd);
672                 return (EINVAL);
673         }
674         /* Add the partition. */
675         pd->pd_handle = disk_handle;
676         pd->pd_unit = unit;
677         pd->pd_devpath = devpath;
678         pd->pd_parent = last;
679         pd->pd_devsw = &efipart_hddev;
680         STAILQ_INSERT_TAIL(&last->pd_part, pd, pd_link);
681         free(pathname);
682         return (0);
683 }
684
685 static void
686 efipart_updatehd(void)
687 {
688         int i;
689         EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
690         EFI_HANDLE handle;
691         EFI_BLOCK_IO *blkio;
692         EFI_STATUS status;
693
694         for (i = 0; i < efipart_nhandles; i++) {
695                 devpath = efi_lookup_devpath(efipart_handles[i]);
696                 if (devpath == NULL)
697                         continue;
698
699                 if ((node = efi_devpath_last_node(devpath)) == NULL)
700                         continue;
701
702                 if (!efipart_hdd(devpath))
703                         continue;
704
705                 status = BS->HandleProtocol(efipart_handles[i],
706                     &blkio_guid, (void **)&blkio);
707                 if (EFI_ERROR(status))
708                         continue;
709
710                 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
711                     DevicePathSubType(node) == MEDIA_FILEPATH_DP) {
712                         efipart_hdinfo_add_filepath(efipart_handles[i]);
713                         continue;
714                 }
715
716                 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
717                     DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) {
718                         devpathcpy = efi_devpath_trim(devpath);
719                         if (devpathcpy == NULL)
720                                 continue;
721                         tmpdevpath = devpathcpy;
722                         status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath,
723                             &handle);
724                         free(devpathcpy);
725                         if (EFI_ERROR(status))
726                                 continue;
727                         /*
728                          * We do not support nested partitions.
729                          */
730                         devpathcpy = efi_lookup_devpath(handle);
731                         if (devpathcpy == NULL)
732                                 continue;
733                         if ((node = efi_devpath_last_node(devpathcpy)) == NULL)
734                                 continue;
735
736                         if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
737                             DevicePathSubType(node) == MEDIA_HARDDRIVE_DP)
738                                 continue;
739
740                         efipart_hdinfo_add(handle, efipart_handles[i]);
741                         continue;
742                 }
743
744                 efipart_hdinfo_add(efipart_handles[i], NULL);
745         }
746 }
747
748 static int
749 efipart_inithd(void)
750 {
751
752         STAILQ_INIT(&hdinfo);
753
754         efipart_updatehd();
755
756         bcache_add_dev(efiblk_pdinfo_count(&hdinfo));
757         return (0);
758 }
759
760 static int
761 efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose)
762 {
763         int ret = 0;
764         EFI_BLOCK_IO *blkio;
765         EFI_STATUS status;
766         EFI_HANDLE h;
767         pdinfo_t *pd;
768         CHAR16 *text;
769         struct disk_devdesc pd_dev;
770         char line[80];
771
772         if (STAILQ_EMPTY(pdlist))
773                 return (0);
774
775         printf("%s devices:", dev->dv_name);
776         if ((ret = pager_output("\n")) != 0)
777                 return (ret);
778
779         STAILQ_FOREACH(pd, pdlist, pd_link) {
780                 h = pd->pd_handle;
781                 if (verbose) {  /* Output the device path. */
782                         text = efi_devpath_name(efi_lookup_devpath(h));
783                         if (text != NULL) {
784                                 printf("  %S", text);
785                                 efi_free_devpath_name(text);
786                                 if ((ret = pager_output("\n")) != 0)
787                                         break;
788                         }
789                 }
790                 snprintf(line, sizeof(line),
791                     "    %s%d", dev->dv_name, pd->pd_unit);
792                 printf("%s:", line);
793                 status = BS->HandleProtocol(h, &blkio_guid, (void **)&blkio);
794                 if (!EFI_ERROR(status)) {
795                         printf("    %llu",
796                             blkio->Media->LastBlock == 0? 0:
797                             (unsigned long long) (blkio->Media->LastBlock + 1));
798                         if (blkio->Media->LastBlock != 0) {
799                                 printf(" X %u", blkio->Media->BlockSize);
800                         }
801                         printf(" blocks");
802                         if (blkio->Media->MediaPresent) {
803                                 if (blkio->Media->RemovableMedia)
804                                         printf(" (removable)");
805                         } else {
806                                 printf(" (no media)");
807                         }
808                         if ((ret = pager_output("\n")) != 0)
809                                 break;
810                         if (!blkio->Media->MediaPresent)
811                                 continue;
812
813                         pd->pd_blkio = blkio;
814                         pd_dev.dd.d_dev = dev;
815                         pd_dev.dd.d_unit = pd->pd_unit;
816                         pd_dev.d_slice = -1;
817                         pd_dev.d_partition = -1;
818                         ret = disk_open(&pd_dev, blkio->Media->BlockSize *
819                             (blkio->Media->LastBlock + 1),
820                             blkio->Media->BlockSize);
821                         if (ret == 0) {
822                                 ret = disk_print(&pd_dev, line, verbose);
823                                 disk_close(&pd_dev);
824                                 if (ret != 0)
825                                         return (ret);
826                         } else {
827                                 /* Do not fail from disk_open() */
828                                 ret = 0;
829                         }
830                 } else {
831                         if ((ret = pager_output("\n")) != 0)
832                                 break;
833                 }
834         }
835         return (ret);
836 }
837
838 static int
839 efipart_printfd(int verbose)
840 {
841         return (efipart_print_common(&efipart_fddev, &fdinfo, verbose));
842 }
843
844 static int
845 efipart_printcd(int verbose)
846 {
847         return (efipart_print_common(&efipart_cddev, &cdinfo, verbose));
848 }
849
850 static int
851 efipart_printhd(int verbose)
852 {
853         return (efipart_print_common(&efipart_hddev, &hdinfo, verbose));
854 }
855
856 static int
857 efipart_open(struct open_file *f, ...)
858 {
859         va_list args;
860         struct disk_devdesc *dev;
861         pdinfo_t *pd;
862         EFI_BLOCK_IO *blkio;
863         EFI_STATUS status;
864
865         va_start(args, f);
866         dev = va_arg(args, struct disk_devdesc*);
867         va_end(args);
868         if (dev == NULL)
869                 return (EINVAL);
870
871         pd = efiblk_get_pdinfo((struct devdesc *)dev);
872         if (pd == NULL)
873                 return (EIO);
874
875         if (pd->pd_blkio == NULL) {
876                 status = BS->HandleProtocol(pd->pd_handle, &blkio_guid,
877                     (void **)&pd->pd_blkio);
878                 if (EFI_ERROR(status))
879                         return (efi_status_to_errno(status));
880         }
881
882         blkio = pd->pd_blkio;
883         if (!blkio->Media->MediaPresent)
884                 return (EAGAIN);
885
886         pd->pd_open++;
887         if (pd->pd_bcache == NULL)
888                 pd->pd_bcache = bcache_allocate();
889
890         if (dev->dd.d_dev->dv_type == DEVT_DISK) {
891                 int rc;
892
893                 rc = disk_open(dev,
894                     blkio->Media->BlockSize * (blkio->Media->LastBlock + 1),
895                     blkio->Media->BlockSize);
896                 if (rc != 0) {
897                         pd->pd_open--;
898                         if (pd->pd_open == 0) {
899                                 pd->pd_blkio = NULL;
900                                 bcache_free(pd->pd_bcache);
901                                 pd->pd_bcache = NULL;
902                         }
903                 }
904                 return (rc);
905         }
906         return (0);
907 }
908
909 static int
910 efipart_close(struct open_file *f)
911 {
912         struct disk_devdesc *dev;
913         pdinfo_t *pd;
914
915         dev = (struct disk_devdesc *)(f->f_devdata);
916         if (dev == NULL)
917                 return (EINVAL);
918
919         pd = efiblk_get_pdinfo((struct devdesc *)dev);
920         if (pd == NULL)
921                 return (EINVAL);
922
923         pd->pd_open--;
924         if (pd->pd_open == 0) {
925                 pd->pd_blkio = NULL;
926                 bcache_free(pd->pd_bcache);
927                 pd->pd_bcache = NULL;
928         }
929         if (dev->dd.d_dev->dv_type == DEVT_DISK)
930                 return (disk_close(dev));
931         return (0);
932 }
933
934 static int
935 efipart_ioctl(struct open_file *f, u_long cmd, void *data)
936 {
937         struct disk_devdesc *dev;
938         pdinfo_t *pd;
939         int rc;
940
941         dev = (struct disk_devdesc *)(f->f_devdata);
942         if (dev == NULL)
943                 return (EINVAL);
944
945         pd = efiblk_get_pdinfo((struct devdesc *)dev);
946         if (pd == NULL)
947                 return (EINVAL);
948
949         if (dev->dd.d_dev->dv_type == DEVT_DISK) {
950                 rc = disk_ioctl(dev, cmd, data);
951                 if (rc != ENOTTY)
952                         return (rc);
953         }
954
955         switch (cmd) {
956         case DIOCGSECTORSIZE:
957                 *(u_int *)data = pd->pd_blkio->Media->BlockSize;
958                 break;
959         case DIOCGMEDIASIZE:
960                 *(uint64_t *)data = pd->pd_blkio->Media->BlockSize *
961                     (pd->pd_blkio->Media->LastBlock + 1);
962                 break;
963         default:
964                 return (ENOTTY);
965         }
966
967         return (0);
968 }
969
970 /*
971  * efipart_readwrite()
972  * Internal equivalent of efipart_strategy(), which operates on the
973  * media-native block size. This function expects all I/O requests
974  * to be within the media size and returns an error if such is not
975  * the case.
976  */
977 static int
978 efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks,
979     char *buf)
980 {
981         EFI_STATUS status;
982
983         if (blkio == NULL)
984                 return (ENXIO);
985         if (blk < 0 || blk > blkio->Media->LastBlock)
986                 return (EIO);
987         if ((blk + nblks - 1) > blkio->Media->LastBlock)
988                 return (EIO);
989
990         switch (rw & F_MASK) {
991         case F_READ:
992                 status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, blk,
993                     nblks * blkio->Media->BlockSize, buf);
994                 break;
995         case F_WRITE:
996                 if (blkio->Media->ReadOnly)
997                         return (EROFS);
998                 status = blkio->WriteBlocks(blkio, blkio->Media->MediaId, blk,
999                     nblks * blkio->Media->BlockSize, buf);
1000                 break;
1001         default:
1002                 return (ENOSYS);
1003         }
1004
1005         if (EFI_ERROR(status)) {
1006                 printf("%s: rw=%d, blk=%ju size=%ju status=%lu\n", __func__, rw,
1007                     blk, nblks, EFI_ERROR_CODE(status));
1008         }
1009         return (efi_status_to_errno(status));
1010 }
1011
1012 static int
1013 efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size,
1014     char *buf, size_t *rsize)
1015 {
1016         struct bcache_devdata bcd;
1017         struct disk_devdesc *dev;
1018         pdinfo_t *pd;
1019
1020         dev = (struct disk_devdesc *)devdata;
1021         if (dev == NULL)
1022                 return (EINVAL);
1023
1024         pd = efiblk_get_pdinfo((struct devdesc *)dev);
1025         if (pd == NULL)
1026                 return (EINVAL);
1027
1028         if (pd->pd_blkio->Media->RemovableMedia &&
1029             !pd->pd_blkio->Media->MediaPresent)
1030                 return (ENXIO);
1031
1032         bcd.dv_strategy = efipart_realstrategy;
1033         bcd.dv_devdata = devdata;
1034         bcd.dv_cache = pd->pd_bcache;
1035
1036         if (dev->dd.d_dev->dv_type == DEVT_DISK) {
1037                 daddr_t offset;
1038
1039                 offset = dev->d_offset * pd->pd_blkio->Media->BlockSize;
1040                 offset /= 512;
1041                 return (bcache_strategy(&bcd, rw, blk + offset,
1042                     size, buf, rsize));
1043         }
1044         return (bcache_strategy(&bcd, rw, blk, size, buf, rsize));
1045 }
1046
1047 static int
1048 efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
1049     char *buf, size_t *rsize)
1050 {
1051         struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
1052         pdinfo_t *pd;
1053         EFI_BLOCK_IO *blkio;
1054         uint64_t off, disk_blocks, d_offset = 0;
1055         char *blkbuf;
1056         size_t blkoff, blksz;
1057         int error;
1058         size_t diskend, readstart;
1059
1060         if (dev == NULL || blk < 0)
1061                 return (EINVAL);
1062
1063         pd = efiblk_get_pdinfo((struct devdesc *)dev);
1064         if (pd == NULL)
1065                 return (EINVAL);
1066
1067         blkio = pd->pd_blkio;
1068         if (blkio == NULL)
1069                 return (ENXIO);
1070
1071         if (size == 0 || (size % 512) != 0)
1072                 return (EIO);
1073
1074         off = blk * 512;
1075         /*
1076          * Get disk blocks, this value is either for whole disk or for
1077          * partition.
1078          */
1079         disk_blocks = 0;
1080         if (dev->dd.d_dev->dv_type == DEVT_DISK) {
1081                 if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
1082                         /* DIOCGMEDIASIZE does return bytes. */
1083                         disk_blocks /= blkio->Media->BlockSize;
1084                 }
1085                 d_offset = dev->d_offset;
1086         }
1087         if (disk_blocks == 0)
1088                 disk_blocks = blkio->Media->LastBlock + 1 - d_offset;
1089
1090         /* make sure we don't read past disk end */
1091         if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) {
1092                 diskend = d_offset + disk_blocks;
1093                 readstart = off / blkio->Media->BlockSize;
1094
1095                 if (diskend <= readstart) {
1096                         if (rsize != NULL)
1097                                 *rsize = 0;
1098
1099                         return (EIO);
1100                 }
1101                 size = diskend - readstart;
1102                 size = size * blkio->Media->BlockSize;
1103         }
1104
1105         if (rsize != NULL)
1106                 *rsize = size;
1107
1108         if ((size % blkio->Media->BlockSize == 0) &&
1109             (off % blkio->Media->BlockSize == 0))
1110                 return (efipart_readwrite(blkio, rw,
1111                     off / blkio->Media->BlockSize,
1112                     size / blkio->Media->BlockSize, buf));
1113
1114         /*
1115          * The block size of the media is not a multiple of I/O.
1116          */
1117         blkbuf = malloc(blkio->Media->BlockSize);
1118         if (blkbuf == NULL)
1119                 return (ENOMEM);
1120
1121         error = 0;
1122         blk = off / blkio->Media->BlockSize;
1123         blkoff = off % blkio->Media->BlockSize;
1124         blksz = blkio->Media->BlockSize - blkoff;
1125         while (size > 0) {
1126                 error = efipart_readwrite(blkio, rw, blk, 1, blkbuf);
1127                 if (error)
1128                         break;
1129                 if (size < blksz)
1130                         blksz = size;
1131                 bcopy(blkbuf + blkoff, buf, blksz);
1132                 buf += blksz;
1133                 size -= blksz;
1134                 blk++;
1135                 blkoff = 0;
1136                 blksz = blkio->Media->BlockSize;
1137         }
1138
1139         free(blkbuf);
1140         return (error);
1141 }