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
29 #include <sys/disk.h>
30 #include <sys/param.h>
31 #include <sys/time.h>
32 #include <sys/queue.h>
33 #include <stddef.h>
34 #include <stdarg.h>
35
36 #include <bootstrap.h>
37
38 #include <efi.h>
39 #include <efilib.h>
40 #include <efichar.h>
41 #include <efidevp.h>
42 #include <Protocol/BlockIo.h>
43 #include <Protocol/BlockIo2.h>
44 #include <disk.h>
45
46 EFI_GUID gEfiBlockIoProtocolGuid = EFI_BLOCK_IO_PROTOCOL_GUID;
47 EFI_GUID gEfiBlockIo2ProtocolGuid = EFI_BLOCK_IO2_PROTOCOL_GUID;
48
49 typedef bool (*pd_test_cb_t)(pdinfo_t *, pdinfo_t *);
50 static int efipart_initfd(void);
51 static int efipart_initcd(void);
52 static int efipart_inithd(void);
53 static void efipart_cdinfo_add(pdinfo_t *);
54
55 static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *);
56 static int efipart_realstrategy(void *, int, daddr_t, size_t, char *, size_t *);
57
58 static int efipart_open(struct open_file *, ...);
59 static int efipart_close(struct open_file *);
60 static int efipart_ioctl(struct open_file *, unsigned long, void *);
61
62 static int efipart_printfd(int);
63 static int efipart_printcd(int);
64 static int efipart_printhd(int);
65
66 /* EISA PNP ID's for floppy controllers */
67 #define PNP0604 0x604
68 #define PNP0700 0x700
69 #define PNP0701 0x701
70
71 /* Bounce buffer max size */
72 #define BIO_BUFFER_SIZE 0x4000
73
74 struct devsw efipart_fddev = {
75 .dv_name = "fd",
76 .dv_type = DEVT_FD,
77 .dv_init = efipart_initfd,
78 .dv_strategy = efipart_strategy,
79 .dv_open = efipart_open,
80 .dv_close = efipart_close,
81 .dv_ioctl = efipart_ioctl,
82 .dv_print = efipart_printfd,
83 .dv_cleanup = NULL
84 };
85
86 struct devsw efipart_cddev = {
87 .dv_name = "cd",
88 .dv_type = DEVT_CD,
89 .dv_init = efipart_initcd,
90 .dv_strategy = efipart_strategy,
91 .dv_open = efipart_open,
92 .dv_close = efipart_close,
93 .dv_ioctl = efipart_ioctl,
94 .dv_print = efipart_printcd,
95 .dv_cleanup = NULL
96 };
97
98 struct devsw efipart_hddev = {
99 .dv_name = "disk",
100 .dv_type = DEVT_DISK,
101 .dv_init = efipart_inithd,
102 .dv_strategy = efipart_strategy,
103 .dv_open = efipart_open,
104 .dv_close = efipart_close,
105 .dv_ioctl = efipart_ioctl,
106 .dv_print = efipart_printhd,
107 .dv_cleanup = NULL
108 };
109
110 static pdinfo_list_t fdinfo = STAILQ_HEAD_INITIALIZER(fdinfo);
111 static pdinfo_list_t cdinfo = STAILQ_HEAD_INITIALIZER(cdinfo);
112 static pdinfo_list_t hdinfo = STAILQ_HEAD_INITIALIZER(hdinfo);
113
114 /*
115 * efipart_inithandles() is used to build up the pdinfo list from
116 * block device handles. Then each devsw init callback is used to
117 * pick items from pdinfo and move to proper device list.
118 * In ideal world, we should end up with empty pdinfo once all
119 * devsw initializers are called.
120 */
121 static pdinfo_list_t pdinfo = STAILQ_HEAD_INITIALIZER(pdinfo);
122
123 pdinfo_list_t *
efiblk_get_pdinfo_list(struct devsw * dev)124 efiblk_get_pdinfo_list(struct devsw *dev)
125 {
126 if (dev->dv_type == DEVT_DISK)
127 return (&hdinfo);
128 if (dev->dv_type == DEVT_CD)
129 return (&cdinfo);
130 if (dev->dv_type == DEVT_FD)
131 return (&fdinfo);
132 return (NULL);
133 }
134
135 /* XXX this gets called way way too often, investigate */
136 pdinfo_t *
efiblk_get_pdinfo(struct devdesc * dev)137 efiblk_get_pdinfo(struct devdesc *dev)
138 {
139 pdinfo_list_t *pdi;
140 pdinfo_t *pd = NULL;
141
142 pdi = efiblk_get_pdinfo_list(dev->d_dev);
143 if (pdi == NULL)
144 return (pd);
145
146 STAILQ_FOREACH(pd, pdi, pd_link) {
147 if (pd->pd_unit == dev->d_unit)
148 return (pd);
149 }
150 return (pd);
151 }
152
153 static bool
same_handle(pdinfo_t * pd,EFI_HANDLE h)154 same_handle(pdinfo_t *pd, EFI_HANDLE h)
155 {
156
157 return (pd->pd_handle == h || pd->pd_alias == h);
158 }
159
160 pdinfo_t *
efiblk_get_pdinfo_by_handle(EFI_HANDLE h)161 efiblk_get_pdinfo_by_handle(EFI_HANDLE h)
162 {
163 pdinfo_t *dp, *pp;
164
165 /*
166 * Check hard disks, then cd, then floppy
167 */
168 STAILQ_FOREACH(dp, &hdinfo, pd_link) {
169 if (same_handle(dp, h))
170 return (dp);
171 STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
172 if (same_handle(pp, h))
173 return (pp);
174 }
175 }
176 STAILQ_FOREACH(dp, &cdinfo, pd_link) {
177 if (same_handle(dp, h))
178 return (dp);
179 STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
180 if (same_handle(pp, h))
181 return (pp);
182 }
183 }
184 STAILQ_FOREACH(dp, &fdinfo, pd_link) {
185 if (same_handle(dp, h))
186 return (dp);
187 }
188 return (NULL);
189 }
190
191 static int
efiblk_pdinfo_count(pdinfo_list_t * pdi)192 efiblk_pdinfo_count(pdinfo_list_t *pdi)
193 {
194 pdinfo_t *pd;
195 int i = 0;
196
197 STAILQ_FOREACH(pd, pdi, pd_link) {
198 i++;
199 }
200 return (i);
201 }
202
203 static pdinfo_t *
efipart_find_parent(pdinfo_list_t * pdi,EFI_DEVICE_PATH * devpath)204 efipart_find_parent(pdinfo_list_t *pdi, EFI_DEVICE_PATH *devpath)
205 {
206 pdinfo_t *pd;
207 EFI_DEVICE_PATH *parent;
208
209 /* We want to find direct parent */
210 parent = efi_devpath_trim(devpath);
211 /* We should not get out of memory here but be careful. */
212 if (parent == NULL)
213 return (NULL);
214
215 STAILQ_FOREACH(pd, pdi, pd_link) {
216 /* We must have exact match. */
217 if (efi_devpath_match(pd->pd_devpath, parent))
218 break;
219 }
220 free(parent);
221 return (pd);
222 }
223
224 /*
225 * Return true when we should ignore this device.
226 */
227 static bool
efipart_ignore_device(EFI_HANDLE h,EFI_BLOCK_IO * blkio,EFI_DEVICE_PATH * devpath)228 efipart_ignore_device(EFI_HANDLE h, EFI_BLOCK_IO *blkio,
229 EFI_DEVICE_PATH *devpath)
230 {
231 EFI_DEVICE_PATH *node, *parent;
232
233 /*
234 * We assume the block size 512 or greater power of 2.
235 * Also skip devices with block size > 64k (16 is max
236 * ashift supported by zfs).
237 * iPXE is known to insert stub BLOCK IO device with
238 * BlockSize 1.
239 */
240 if (blkio->Media->BlockSize < 512 ||
241 blkio->Media->BlockSize > (1 << 16) ||
242 !powerof2(blkio->Media->BlockSize)) {
243 efi_close_devpath(h);
244 return (true);
245 }
246
247 /* Allowed values are 0, 1 and power of 2. */
248 if (blkio->Media->IoAlign > 1 &&
249 !powerof2(blkio->Media->IoAlign)) {
250 efi_close_devpath(h);
251 return (true);
252 }
253
254 /*
255 * With device tree setup:
256 * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)
257 * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x1)
258 * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x2)
259 * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x3)
260 * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x3)/CDROM..
261 * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x3)/CDROM..
262 * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x4)
263 * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x5)
264 * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x6)
265 * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x7)
266 *
267 * In above exmple only Unit(0x3) has media, all other nodes are
268 * missing media and should not be used.
269 *
270 * No media does not always mean there is no device, but in above
271 * case, we can not really assume there is any device.
272 * Therefore, if this node is USB, or this node is Unit (LUN) and
273 * direct parent is USB and we have no media, we will ignore this
274 * device.
275 *
276 * Variation of the same situation, but with SCSI devices:
277 * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x1)
278 * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x2)
279 * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x3)
280 * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x3)/CD..
281 * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x3)/CD..
282 * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x4)
283 *
284 * Here above the SCSI luns 1,2 and 4 have no media.
285 */
286
287 /* Do not ignore device with media. */
288 if (blkio->Media->MediaPresent)
289 return (false);
290
291 node = efi_devpath_last_node(devpath);
292 if (node == NULL)
293 return (false);
294
295 /* USB without media present */
296 if (DevicePathType(node) == MESSAGING_DEVICE_PATH &&
297 DevicePathSubType(node) == MSG_USB_DP) {
298 efi_close_devpath(h);
299 return (true);
300 }
301
302 parent = efi_devpath_trim(devpath);
303 if (parent != NULL) {
304 bool parent_is_usb = false;
305
306 node = efi_devpath_last_node(parent);
307 if (node == NULL) {
308 free(parent);
309 return (false);
310 }
311 if (DevicePathType(node) == MESSAGING_DEVICE_PATH &&
312 DevicePathSubType(node) == MSG_USB_DP)
313 parent_is_usb = true;
314 free(parent);
315
316 node = efi_devpath_last_node(devpath);
317 if (node == NULL)
318 return (false);
319 if (parent_is_usb &&
320 DevicePathType(node) == MESSAGING_DEVICE_PATH) {
321 /*
322 * no media, parent is USB and devicepath is
323 * LUN or SCSI.
324 */
325 if (DevicePathSubType(node) ==
326 MSG_DEVICE_LOGICAL_UNIT_DP ||
327 DevicePathSubType(node) == MSG_SCSI_DP) {
328 efi_close_devpath(h);
329 return (true);
330 }
331 }
332 }
333 return (false);
334 }
335
336 int
efipart_inithandles(void)337 efipart_inithandles(void)
338 {
339 uint_t i, nin;
340 EFI_HANDLE *hin;
341 EFI_DEVICE_PATH *devpath;
342 EFI_BLOCK_IO *blkio;
343 EFI_STATUS status;
344 pdinfo_t *pd;
345
346 if (!STAILQ_EMPTY(&pdinfo))
347 return (0);
348
349 status = efi_get_protocol_handles(&gEfiBlockIoProtocolGuid, &nin, &hin);
350 if (EFI_ERROR(status))
351 return (efi_status_to_errno(status));
352
353 #ifdef EFIPART_DEBUG
354 printf("%s: Got %d BLOCK IO MEDIA handle(s)\n", __func__, nin);
355 #endif
356
357 for (i = 0; i < nin; i++) {
358 /*
359 * Get devpath and open protocol.
360 * We should not get errors here
361 */
362 if ((devpath = efi_lookup_devpath(hin[i])) == NULL)
363 continue;
364
365 status = OpenProtocolByHandle(hin[i], &gEfiBlockIoProtocolGuid,
366 (void **)&blkio);
367 if (EFI_ERROR(status)) {
368 printf("error %lu\n", DECODE_ERROR(status));
369 continue;
370 }
371
372 if (efipart_ignore_device(hin[i], blkio, devpath))
373 continue;
374
375 /* This is bad. */
376 if ((pd = calloc(1, sizeof (*pd))) == NULL) {
377 printf("efipart_inithandles: Out of memory.\n");
378 free(hin);
379 return (ENOMEM);
380 }
381 STAILQ_INIT(&pd->pd_part);
382
383 pd->pd_handle = hin[i];
384 pd->pd_devpath = devpath;
385 pd->pd_blkio = blkio;
386 STAILQ_INSERT_TAIL(&pdinfo, pd, pd_link);
387 }
388
389 /*
390 * Walk pdinfo and set parents based on device path.
391 */
392 STAILQ_FOREACH(pd, &pdinfo, pd_link) {
393 pd->pd_parent = efipart_find_parent(&pdinfo, pd->pd_devpath);
394 }
395 free(hin);
396 return (0);
397 }
398
399 /*
400 * Get node identified by pd_test() from plist.
401 */
402 static pdinfo_t *
efipart_get_pd(pdinfo_list_t * plist,pd_test_cb_t pd_test,pdinfo_t * data)403 efipart_get_pd(pdinfo_list_t *plist, pd_test_cb_t pd_test, pdinfo_t *data)
404 {
405 pdinfo_t *pd;
406
407 STAILQ_FOREACH(pd, plist, pd_link) {
408 if (pd_test(pd, data))
409 break;
410 }
411
412 return (pd);
413 }
414
415 static ACPI_HID_DEVICE_PATH *
efipart_floppy(EFI_DEVICE_PATH * node)416 efipart_floppy(EFI_DEVICE_PATH *node)
417 {
418 ACPI_HID_DEVICE_PATH *acpi;
419
420 if (DevicePathType(node) == ACPI_DEVICE_PATH &&
421 DevicePathSubType(node) == ACPI_DP) {
422 acpi = (ACPI_HID_DEVICE_PATH *) node;
423 if (acpi->HID == EISA_PNP_ID(PNP0604) ||
424 acpi->HID == EISA_PNP_ID(PNP0700) ||
425 acpi->HID == EISA_PNP_ID(PNP0701)) {
426 return (acpi);
427 }
428 }
429 return (NULL);
430 }
431
432 static bool
efipart_testfd(pdinfo_t * fd,pdinfo_t * data __unused)433 efipart_testfd(pdinfo_t *fd, pdinfo_t *data __unused)
434 {
435 EFI_DEVICE_PATH *node;
436
437 node = efi_devpath_last_node(fd->pd_devpath);
438 if (node == NULL)
439 return (false);
440
441 if (efipart_floppy(node) != NULL)
442 return (true);
443
444 return (false);
445 }
446
447 static int
efipart_initfd(void)448 efipart_initfd(void)
449 {
450 EFI_DEVICE_PATH *node;
451 ACPI_HID_DEVICE_PATH *acpi;
452 pdinfo_t *parent, *fd;
453
454 while ((fd = efipart_get_pd(&pdinfo, efipart_testfd, NULL)) != NULL) {
455 if ((node = efi_devpath_last_node(fd->pd_devpath)) == NULL)
456 continue;
457
458 if ((acpi = efipart_floppy(node)) == NULL)
459 continue;
460
461 STAILQ_REMOVE(&pdinfo, fd, pdinfo, pd_link);
462 parent = fd->pd_parent;
463 if (parent != NULL) {
464 STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
465 parent->pd_alias = fd->pd_handle;
466 parent->pd_unit = acpi->UID;
467 free(fd);
468 fd = parent;
469 } else {
470 fd->pd_unit = acpi->UID;
471 }
472 fd->pd_devsw = &efipart_fddev;
473 STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
474 }
475
476 bcache_add_dev(efiblk_pdinfo_count(&fdinfo));
477 return (0);
478 }
479
480 /*
481 * Add or update entries with new handle data.
482 */
483 static void
efipart_cdinfo_add(pdinfo_t * cd)484 efipart_cdinfo_add(pdinfo_t *cd)
485 {
486 pdinfo_t *parent, *pd, *last;
487
488 if (cd == NULL)
489 return;
490
491 parent = cd->pd_parent;
492 /* Make sure we have parent added */
493 efipart_cdinfo_add(parent);
494
495 STAILQ_FOREACH(pd, &pdinfo, pd_link) {
496 if (efi_devpath_match(pd->pd_devpath, cd->pd_devpath)) {
497 STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link);
498 break;
499 }
500 }
501 if (pd == NULL) {
502 /* This device is already added. */
503 return;
504 }
505
506 if (parent != NULL) {
507 last = STAILQ_LAST(&parent->pd_part, pdinfo, pd_link);
508 if (last != NULL)
509 cd->pd_unit = last->pd_unit + 1;
510 else
511 cd->pd_unit = 0;
512 cd->pd_devsw = &efipart_cddev;
513 STAILQ_INSERT_TAIL(&parent->pd_part, cd, pd_link);
514 return;
515 }
516
517 last = STAILQ_LAST(&cdinfo, pdinfo, pd_link);
518 if (last != NULL)
519 cd->pd_unit = last->pd_unit + 1;
520 else
521 cd->pd_unit = 0;
522
523 cd->pd_devsw = &efipart_cddev;
524 STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link);
525 }
526
527 static bool
efipart_testcd(pdinfo_t * cd,pdinfo_t * data __unused)528 efipart_testcd(pdinfo_t *cd, pdinfo_t *data __unused)
529 {
530 EFI_DEVICE_PATH *node;
531
532 node = efi_devpath_last_node(cd->pd_devpath);
533 if (node == NULL)
534 return (false);
535
536 if (efipart_floppy(node) != NULL)
537 return (false);
538
539 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
540 DevicePathSubType(node) == MEDIA_CDROM_DP) {
541 return (true);
542 }
543
544 /* cd drive without the media. */
545 if (cd->pd_blkio->Media->RemovableMedia &&
546 !cd->pd_blkio->Media->MediaPresent) {
547 return (true);
548 }
549
550 return (false);
551 }
552
553 /*
554 * Test if pd is parent for device.
555 */
556 static bool
efipart_testchild(pdinfo_t * dev,pdinfo_t * pd)557 efipart_testchild(pdinfo_t *dev, pdinfo_t *pd)
558 {
559 /* device with no parent. */
560 if (dev->pd_parent == NULL)
561 return (false);
562
563 if (efi_devpath_match(dev->pd_parent->pd_devpath, pd->pd_devpath)) {
564 return (true);
565 }
566 return (false);
567 }
568
569 static int
efipart_initcd(void)570 efipart_initcd(void)
571 {
572 pdinfo_t *cd;
573
574 while ((cd = efipart_get_pd(&pdinfo, efipart_testcd, NULL)) != NULL)
575 efipart_cdinfo_add(cd);
576
577 /* Find all children of CD devices we did add above. */
578 STAILQ_FOREACH(cd, &cdinfo, pd_link) {
579 pdinfo_t *child;
580
581 for (child = efipart_get_pd(&pdinfo, efipart_testchild, cd);
582 child != NULL;
583 child = efipart_get_pd(&pdinfo, efipart_testchild, cd))
584 efipart_cdinfo_add(child);
585 }
586 bcache_add_dev(efiblk_pdinfo_count(&cdinfo));
587 return (0);
588 }
589
590 static void
efipart_hdinfo_add_node(pdinfo_t * hd,EFI_DEVICE_PATH * node)591 efipart_hdinfo_add_node(pdinfo_t *hd, EFI_DEVICE_PATH *node)
592 {
593 pdinfo_t *parent, *ptr;
594
595 if (node == NULL)
596 return;
597
598 parent = hd->pd_parent;
599 /*
600 * If the node is not MEDIA_HARDDRIVE_DP, it is sub-partition.
601 * This can happen with Vendor nodes, and since we do not know
602 * the more about those nodes, we just count them.
603 */
604 if (DevicePathSubType(node) != MEDIA_HARDDRIVE_DP) {
605 ptr = STAILQ_LAST(&parent->pd_part, pdinfo, pd_link);
606 if (ptr != NULL)
607 hd->pd_unit = ptr->pd_unit + 1;
608 else
609 hd->pd_unit = 0;
610 } else {
611 hd->pd_unit = ((HARDDRIVE_DEVICE_PATH *)node)->PartitionNumber;
612 }
613
614 hd->pd_devsw = &efipart_hddev;
615 STAILQ_INSERT_TAIL(&parent->pd_part, hd, pd_link);
616 }
617
618 /*
619 * The MEDIA_FILEPATH_DP has device name.
620 * From U-Boot sources it looks like names are in the form
621 * of typeN:M, where type is interface type, N is disk id
622 * and M is partition id.
623 */
624 static void
efipart_hdinfo_add_filepath(pdinfo_t * hd,FILEPATH_DEVICE_PATH * node)625 efipart_hdinfo_add_filepath(pdinfo_t *hd, FILEPATH_DEVICE_PATH *node)
626 {
627 char *pathname, *p;
628 int len;
629 pdinfo_t *last;
630
631 last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
632 if (last != NULL)
633 hd->pd_unit = last->pd_unit + 1;
634 else
635 hd->pd_unit = 0;
636
637 /* FILEPATH_DEVICE_PATH has 0 terminated string */
638 len = ucs2len(node->PathName);
639 if ((pathname = malloc(len + 1)) == NULL) {
640 printf("Failed to add disk, out of memory\n");
641 free(hd);
642 return;
643 }
644 cpy16to8(node->PathName, pathname, len + 1);
645 p = strchr(pathname, ':');
646
647 /*
648 * Assume we are receiving handles in order, first disk handle,
649 * then partitions for this disk. If this assumption proves
650 * false, this code would need update.
651 */
652 if (p == NULL) { /* no colon, add the disk */
653 hd->pd_devsw = &efipart_hddev;
654 STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
655 free(pathname);
656 return;
657 }
658 p++; /* skip the colon */
659 errno = 0;
660 hd->pd_unit = (int)strtol(p, NULL, 0);
661 if (errno != 0) {
662 printf("Bad unit number for partition \"%s\"\n", pathname);
663 free(pathname);
664 free(hd);
665 return;
666 }
667
668 /*
669 * We should have disk registered, if not, we are receiving
670 * handles out of order, and this code should be reworked
671 * to create "blank" disk for partition, and to find the
672 * disk based on PathName compares.
673 */
674 if (last == NULL) {
675 printf("BUG: No disk for partition \"%s\"\n", pathname);
676 free(pathname);
677 free(hd);
678 return;
679 }
680 /* Add the partition. */
681 hd->pd_parent = last;
682 hd->pd_devsw = &efipart_hddev;
683 STAILQ_INSERT_TAIL(&last->pd_part, hd, pd_link);
684 free(pathname);
685 }
686
687 static void
efipart_hdinfo_add(pdinfo_t * hd)688 efipart_hdinfo_add(pdinfo_t *hd)
689 {
690 pdinfo_t *parent, *pd, *last;
691 EFI_DEVICE_PATH *node;
692
693 if (hd == NULL)
694 return;
695
696 parent = hd->pd_parent;
697 /* Make sure we have parent added */
698 efipart_hdinfo_add(parent);
699
700 STAILQ_FOREACH(pd, &pdinfo, pd_link) {
701 if (efi_devpath_match(pd->pd_devpath, hd->pd_devpath)) {
702 STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
703 break;
704 }
705 }
706 if (pd == NULL) {
707 /* This device is already added. */
708 return;
709 }
710
711 if ((node = efi_devpath_last_node(hd->pd_devpath)) == NULL)
712 return;
713
714 if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
715 DevicePathSubType(node) == MEDIA_FILEPATH_DP) {
716 efipart_hdinfo_add_filepath(hd,
717 (FILEPATH_DEVICE_PATH *)node);
718 return;
719 }
720
721 if (parent != NULL) {
722 efipart_hdinfo_add_node(hd, node);
723 return;
724 }
725
726 last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
727 if (last != NULL)
728 hd->pd_unit = last->pd_unit + 1;
729 else
730 hd->pd_unit = 0;
731
732 /* Add the disk. */
733 hd->pd_devsw = &efipart_hddev;
734 STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
735 }
736
737 static bool
efipart_testhd(pdinfo_t * hd,pdinfo_t * data __unused)738 efipart_testhd(pdinfo_t *hd, pdinfo_t *data __unused)
739 {
740 if (efipart_testfd(hd, NULL))
741 return (false);
742
743 if (efipart_testcd(hd, NULL))
744 return (false);
745
746 /* Anything else must be HD. */
747 return (true);
748 }
749
750 static int
efipart_inithd(void)751 efipart_inithd(void)
752 {
753 pdinfo_t *hd;
754
755 while ((hd = efipart_get_pd(&pdinfo, efipart_testhd, NULL)) != NULL)
756 efipart_hdinfo_add(hd);
757
758 bcache_add_dev(efiblk_pdinfo_count(&hdinfo));
759 return (0);
760 }
761
762 static int
efipart_print_common(struct devsw * dev,pdinfo_list_t * pdlist,int verbose)763 efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose)
764 {
765 int ret = 0;
766 EFI_BLOCK_IO *blkio;
767 EFI_STATUS status;
768 EFI_HANDLE h;
769 pdinfo_t *pd;
770 CHAR16 *text;
771 struct disk_devdesc pd_dev;
772 char line[80];
773
774 if (STAILQ_EMPTY(pdlist))
775 return (0);
776
777 printf("%s devices:", dev->dv_name);
778 if ((ret = pager_output("\n")) != 0)
779 return (ret);
780
781 STAILQ_FOREACH(pd, pdlist, pd_link) {
782 h = pd->pd_handle;
783 if (verbose) { /* Output the device path. */
784 text = efi_devpath_name(efi_lookup_devpath(h));
785 if (text != NULL) {
786 printf(" %S", text);
787 efi_free_devpath_name(text);
788 if ((ret = pager_output("\n")) != 0)
789 break;
790 }
791 }
792 snprintf(line, sizeof (line),
793 " %s%d", dev->dv_name, pd->pd_unit);
794 printf("%s:", line);
795 status = OpenProtocolByHandle(h, &gEfiBlockIoProtocolGuid,
796 (void **)&blkio);
797 if (!EFI_ERROR(status)) {
798 printf(" %llu",
799 blkio->Media->LastBlock == 0? 0:
800 (unsigned long long) (blkio->Media->LastBlock + 1));
801 if (blkio->Media->LastBlock != 0) {
802 printf(" X %u", blkio->Media->BlockSize);
803 }
804 printf(" blocks");
805 if (blkio->Media->MediaPresent) {
806 if (blkio->Media->RemovableMedia)
807 printf(" (removable)");
808 } else {
809 printf(" (no media)");
810 }
811 if ((ret = pager_output("\n")) != 0)
812 break;
813 if (!blkio->Media->MediaPresent)
814 continue;
815
816 pd->pd_blkio = blkio;
817 pd_dev.dd.d_dev = dev;
818 pd_dev.dd.d_unit = pd->pd_unit;
819 pd_dev.d_slice = D_SLICENONE;
820 pd_dev.d_partition = D_PARTNONE;
821 ret = disk_open(&pd_dev, blkio->Media->BlockSize *
822 (blkio->Media->LastBlock + 1),
823 blkio->Media->BlockSize);
824 if (ret == 0) {
825 ret = disk_print(&pd_dev, line, verbose);
826 disk_close(&pd_dev);
827 if (ret != 0)
828 return (ret);
829 } else {
830 /* Do not fail from disk_open() */
831 ret = 0;
832 }
833 } else {
834 if ((ret = pager_output("\n")) != 0)
835 break;
836 }
837 }
838 return (ret);
839 }
840
841 static int
efipart_printfd(int verbose)842 efipart_printfd(int verbose)
843 {
844 return (efipart_print_common(&efipart_fddev, &fdinfo, verbose));
845 }
846
847 static int
efipart_printcd(int verbose)848 efipart_printcd(int verbose)
849 {
850 return (efipart_print_common(&efipart_cddev, &cdinfo, verbose));
851 }
852
853 static int
efipart_printhd(int verbose)854 efipart_printhd(int verbose)
855 {
856 return (efipart_print_common(&efipart_hddev, &hdinfo, verbose));
857 }
858
859 static int
efipart_open(struct open_file * f,...)860 efipart_open(struct open_file *f, ...)
861 {
862 va_list args;
863 struct disk_devdesc *dev;
864 pdinfo_t *pd;
865 EFI_BLOCK_IO *blkio;
866 EFI_STATUS status;
867
868 va_start(args, f);
869 dev = va_arg(args, struct disk_devdesc *);
870 va_end(args);
871 if (dev == NULL)
872 return (EINVAL);
873
874 pd = efiblk_get_pdinfo((struct devdesc *)dev);
875 if (pd == NULL)
876 return (EIO);
877
878 if (pd->pd_blkio == NULL) {
879 status = OpenProtocolByHandle(pd->pd_handle,
880 &gEfiBlockIoProtocolGuid,
881 (void **)&pd->pd_blkio);
882 if (EFI_ERROR(status))
883 return (efi_status_to_errno(status));
884 }
885
886 blkio = pd->pd_blkio;
887 if (!blkio->Media->MediaPresent)
888 return (EAGAIN);
889
890 pd->pd_open++;
891 if (pd->pd_bcache == NULL)
892 pd->pd_bcache = bcache_allocate();
893
894 if (dev->dd.d_dev->dv_type == DEVT_DISK) {
895 int rc;
896
897 rc = disk_open(dev,
898 blkio->Media->BlockSize * (blkio->Media->LastBlock + 1),
899 blkio->Media->BlockSize);
900 if (rc != 0) {
901 pd->pd_open--;
902 if (pd->pd_open == 0) {
903 pd->pd_blkio = NULL;
904 bcache_free(pd->pd_bcache);
905 pd->pd_bcache = NULL;
906 }
907 }
908 return (rc);
909 }
910 return (0);
911 }
912
913 static int
efipart_close(struct open_file * f)914 efipart_close(struct open_file *f)
915 {
916 struct disk_devdesc *dev;
917 pdinfo_t *pd;
918
919 dev = (struct disk_devdesc *)(f->f_devdata);
920 if (dev == NULL)
921 return (EINVAL);
922
923 pd = efiblk_get_pdinfo((struct devdesc *)dev);
924 if (pd == NULL)
925 return (EINVAL);
926
927 pd->pd_open--;
928 if (pd->pd_open == 0) {
929 pd->pd_blkio = NULL;
930 if (dev->dd.d_dev->dv_type != DEVT_DISK) {
931 bcache_free(pd->pd_bcache);
932 pd->pd_bcache = NULL;
933 }
934 }
935 if (dev->dd.d_dev->dv_type == DEVT_DISK)
936 return (disk_close(dev));
937 return (0);
938 }
939
940 static int
efipart_ioctl(struct open_file * f,unsigned long cmd,void * data)941 efipart_ioctl(struct open_file *f, unsigned long cmd, void *data)
942 {
943 struct disk_devdesc *dev;
944 pdinfo_t *pd;
945 int rc;
946
947 dev = (struct disk_devdesc *)(f->f_devdata);
948 if (dev == NULL)
949 return (EINVAL);
950
951 pd = efiblk_get_pdinfo((struct devdesc *)dev);
952 if (pd == NULL)
953 return (EINVAL);
954
955 if (dev->dd.d_dev->dv_type == DEVT_DISK) {
956 rc = disk_ioctl(dev, cmd, data);
957 if (rc != ENOTTY)
958 return (rc);
959 }
960
961 switch (cmd) {
962 case DIOCGSECTORSIZE:
963 *(uint_t *)data = pd->pd_blkio->Media->BlockSize;
964 break;
965 case DIOCGMEDIASIZE:
966 *(uint64_t *)data = pd->pd_blkio->Media->BlockSize *
967 (pd->pd_blkio->Media->LastBlock + 1);
968 break;
969 default:
970 return (ENOTTY);
971 }
972
973 return (0);
974 }
975
976 /*
977 * efipart_readwrite()
978 * Internal equivalent of efipart_strategy(), which operates on the
979 * media-native block size. This function expects all I/O requests
980 * to be within the media size and returns an error if such is not
981 * the case.
982 */
983 static int
efipart_readwrite(pdinfo_t * pd,int rw,daddr_t blk,daddr_t nblks,char * buf)984 efipart_readwrite(pdinfo_t *pd, int rw, daddr_t blk, daddr_t nblks,
985 char *buf)
986 {
987 EFI_STATUS status;
988 EFI_BLOCK_IO *blkio = pd->pd_blkio;
989
990 if (blkio == NULL)
991 return (ENXIO);
992 if (blk < 0 || blk > blkio->Media->LastBlock)
993 return (EIO);
994 if ((blk + nblks - 1) > blkio->Media->LastBlock)
995 return (EIO);
996
997 switch (rw & F_MASK) {
998 case F_READ:
999 status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, blk,
1000 nblks * blkio->Media->BlockSize, buf);
1001 break;
1002 case F_WRITE:
1003 if (blkio->Media->ReadOnly)
1004 return (EROFS);
1005 status = blkio->WriteBlocks(blkio, blkio->Media->MediaId, blk,
1006 nblks * blkio->Media->BlockSize, buf);
1007 break;
1008 default:
1009 return (ENOSYS);
1010 }
1011
1012 if (EFI_ERROR(status)) {
1013 CHAR16 *pathname;
1014
1015 pathname = efi_devpath_name(pd->pd_devpath);
1016 if (pathname != NULL) {
1017 printf("%S: ", pathname);
1018 efi_free_devpath_name(pathname);
1019 }
1020 printf("%s error: blk=%ju size=%ju status=%lu\n",
1021 (rw & F_MASK) == F_READ ? "read" : "write",
1022 blk, nblks, DECODE_ERROR(status));
1023 }
1024 return (efi_status_to_errno(status));
1025 }
1026
1027 static int
efipart_strategy(void * devdata,int rw,daddr_t blk,size_t size,char * buf,size_t * rsize)1028 efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size,
1029 char *buf, size_t *rsize)
1030 {
1031 struct bcache_devdata bcd;
1032 struct disk_devdesc *dev;
1033 pdinfo_t *pd;
1034
1035 dev = (struct disk_devdesc *)devdata;
1036 if (dev == NULL)
1037 return (EINVAL);
1038
1039 pd = efiblk_get_pdinfo((struct devdesc *)dev);
1040 if (pd == NULL)
1041 return (EINVAL);
1042
1043 if (pd->pd_blkio->Media->RemovableMedia &&
1044 !pd->pd_blkio->Media->MediaPresent)
1045 return (ENXIO);
1046
1047 bcd.dv_strategy = efipart_realstrategy;
1048 bcd.dv_devdata = devdata;
1049 bcd.dv_cache = pd->pd_bcache;
1050
1051 if (dev->dd.d_dev->dv_type == DEVT_DISK) {
1052 daddr_t offset;
1053
1054 offset = dev->d_offset * pd->pd_blkio->Media->BlockSize;
1055 offset /= 512;
1056 return (bcache_strategy(&bcd, rw, blk + offset,
1057 size, buf, rsize));
1058 }
1059 return (bcache_strategy(&bcd, rw, blk, size, buf, rsize));
1060 }
1061
1062 static int
efipart_realstrategy(void * devdata,int rw,daddr_t blk,size_t size,char * buf,size_t * rsize)1063 efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
1064 char *buf, size_t *rsize)
1065 {
1066 struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
1067 pdinfo_t *pd;
1068 EFI_BLOCK_IO *blkio;
1069 uint64_t off, disk_blocks, d_offset = 0;
1070 char *blkbuf;
1071 size_t blkoff, blksz, bio_size;
1072 unsigned ioalign;
1073 bool need_buf;
1074 int rc;
1075 uint64_t diskend, readstart;
1076
1077 if (dev == NULL || blk < 0)
1078 return (EINVAL);
1079
1080 pd = efiblk_get_pdinfo((struct devdesc *)dev);
1081 if (pd == NULL)
1082 return (EINVAL);
1083
1084 blkio = pd->pd_blkio;
1085 if (blkio == NULL)
1086 return (ENXIO);
1087
1088 if (size == 0 || (size % 512) != 0)
1089 return (EIO);
1090
1091 off = blk * 512;
1092 /*
1093 * Get disk blocks, this value is either for whole disk or for
1094 * partition.
1095 */
1096 disk_blocks = 0;
1097 if (dev->dd.d_dev->dv_type == DEVT_DISK) {
1098 if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
1099 /* DIOCGMEDIASIZE does return bytes. */
1100 disk_blocks /= blkio->Media->BlockSize;
1101 }
1102 d_offset = dev->d_offset;
1103 }
1104 if (disk_blocks == 0)
1105 disk_blocks = blkio->Media->LastBlock + 1 - d_offset;
1106
1107 /* make sure we don't read past disk end */
1108 if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) {
1109 diskend = d_offset + disk_blocks;
1110 readstart = off / blkio->Media->BlockSize;
1111
1112 if (diskend <= readstart) {
1113 if (rsize != NULL)
1114 *rsize = 0;
1115
1116 return (EIO);
1117 }
1118 size = diskend - readstart;
1119 size = size * blkio->Media->BlockSize;
1120 }
1121
1122 need_buf = true;
1123 /* Do we need bounce buffer? */
1124 if ((size % blkio->Media->BlockSize == 0) &&
1125 (off % blkio->Media->BlockSize == 0))
1126 need_buf = false;
1127
1128 /* Do we have IO alignment requirement? */
1129 ioalign = blkio->Media->IoAlign;
1130 if (ioalign == 0)
1131 ioalign++;
1132
1133 if (ioalign > 1 && (uintptr_t)buf != roundup2((uintptr_t)buf, ioalign))
1134 need_buf = true;
1135
1136 if (need_buf) {
1137 for (bio_size = BIO_BUFFER_SIZE; bio_size > 0;
1138 bio_size -= blkio->Media->BlockSize) {
1139 blkbuf = memalign(ioalign, bio_size);
1140 if (blkbuf != NULL)
1141 break;
1142 }
1143 } else {
1144 blkbuf = buf;
1145 bio_size = size;
1146 }
1147
1148 if (blkbuf == NULL)
1149 return (ENOMEM);
1150
1151 if (rsize != NULL)
1152 *rsize = size;
1153
1154 rc = 0;
1155 blk = off / blkio->Media->BlockSize;
1156 blkoff = off % blkio->Media->BlockSize;
1157
1158 while (size > 0) {
1159 size_t x = min(size, bio_size);
1160
1161 if (x < blkio->Media->BlockSize)
1162 x = 1;
1163 else
1164 x /= blkio->Media->BlockSize;
1165
1166 switch (rw & F_MASK) {
1167 case F_READ:
1168 blksz = blkio->Media->BlockSize * x - blkoff;
1169 if (size < blksz)
1170 blksz = size;
1171
1172 rc = efipart_readwrite(pd, rw, blk, x, blkbuf);
1173 if (rc != 0)
1174 goto error;
1175
1176 if (need_buf)
1177 bcopy(blkbuf + blkoff, buf, blksz);
1178 break;
1179 case F_WRITE:
1180 rc = 0;
1181 if (blkoff != 0) {
1182 /*
1183 * We got offset to sector, read 1 sector to
1184 * blkbuf.
1185 */
1186 x = 1;
1187 blksz = blkio->Media->BlockSize - blkoff;
1188 blksz = min(blksz, size);
1189 rc = efipart_readwrite(pd, F_READ, blk, x,
1190 blkbuf);
1191 } else if (size < blkio->Media->BlockSize) {
1192 /*
1193 * The remaining block is not full
1194 * sector. Read 1 sector to blkbuf.
1195 */
1196 x = 1;
1197 blksz = size;
1198 rc = efipart_readwrite(pd, F_READ, blk, x,
1199 blkbuf);
1200 } else {
1201 /* We can write full sector(s). */
1202 blksz = blkio->Media->BlockSize * x;
1203 }
1204
1205 if (rc != 0)
1206 goto error;
1207 /*
1208 * Put your Data In, Put your Data out,
1209 * Put your Data In, and shake it all about
1210 */
1211 if (need_buf)
1212 bcopy(buf, blkbuf + blkoff, blksz);
1213 rc = efipart_readwrite(pd, F_WRITE, blk, x, blkbuf);
1214 if (rc != 0)
1215 goto error;
1216 break;
1217 default:
1218 /* DO NOTHING */
1219 rc = EROFS;
1220 goto error;
1221 }
1222
1223 blkoff = 0;
1224 buf += blksz;
1225 size -= blksz;
1226 blk += x;
1227 }
1228
1229 error:
1230 if (rsize != NULL)
1231 *rsize -= size;
1232
1233 if (need_buf)
1234 free(blkbuf);
1235 return (rc);
1236 }
1237