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