1 /* $OpenBSD: diskprobe.c,v 1.6 2018/12/31 11:44:57 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org> 5 * Copyright (c) 2014 Stefan Sperling <stsp@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/disklabel.h> 22 23 #include <lib/libkern/funcs.h> 24 #include <lib/libsa/stand.h> 25 26 #include "ofdev.h" 27 #include "disk.h" 28 #include "openfirm.h" 29 30 /* List of disk devices we found/probed */ 31 struct disklist_lh disklist; 32 33 struct diskinfo *bootdev_dip; 34 35 void 36 new_diskinfo(int node) 37 { 38 struct diskinfo *dip; 39 struct of_dev ofdev; 40 int ihandle = -1; 41 int len; 42 const char *unit; 43 char buf[32]; 44 int parent; 45 int i; 46 47 dip = alloc(sizeof(*dip)); 48 bzero(dip, sizeof(*dip)); 49 50 len = OF_package_to_path(node, dip->path, sizeof(dip->path)); 51 if (len < 0) { 52 DPRINTF("could not get path for disk node %x\n", node); 53 goto bad; 54 } else if (len >= sizeof(dip->path)) { 55 printf("disk device path too long: %s", dip->path); 56 goto bad; 57 } 58 dip->path[len] = '\0'; 59 60 /* If no device unit was supplied by the firmware, add it. */ 61 unit = NULL; 62 for (i = len - 1; i >= 0; i--) { 63 if (dip->path[i] == '/') 64 break; 65 else if (dip->path[i] == '@') { 66 unit = &dip->path[i]; 67 break; 68 } 69 } 70 if (unit == NULL) { 71 parent = OF_parent(node); 72 if (parent && OF_getprop(parent, "device_type", buf, 73 sizeof(buf)) > 0 && strcmp(buf, "scsi-sas") == 0) 74 len = strlcat(dip->path, "@p0", sizeof(dip->path)); 75 else 76 len = strlcat(dip->path, "@0", sizeof(dip->path)); 77 if (len >= sizeof(dip->path)) { 78 printf("disk device path too long: %s", dip->path); 79 goto bad; 80 } 81 } 82 83 DPRINTF("found disk %s\n", dip->path); 84 85 ihandle = OF_open(dip->path); 86 if (ihandle == -1) 87 goto bad; 88 89 bzero(&ofdev, sizeof(ofdev)); 90 ofdev.handle = ihandle; 91 ofdev.type = OFDEV_DISK; 92 ofdev.bsize = DEV_BSIZE; 93 if (load_disklabel(&ofdev, &dip->disklabel) != 0) 94 goto bad; 95 OF_close(ihandle); 96 TAILQ_INSERT_TAIL(&disklist, dip, list); 97 98 return; 99 bad: 100 if (ihandle != -1) 101 OF_close(ihandle); 102 free(dip, sizeof(*dip)); 103 } 104 105 #ifdef BOOT_DEBUG 106 void dump_node(int node) 107 { 108 char buf[32]; 109 110 printf("node %x ", node); 111 if (OF_getprop(node, "device_type", buf, sizeof(buf)) > 0) 112 printf("type %s ", buf); 113 if (OF_getprop(node, "name", buf, sizeof(buf)) > 0) 114 printf("name %s ", buf); 115 printf("\n"); 116 } 117 #endif 118 119 /* 120 * Hunt through the device tree for disks. There should be no need to 121 * go more than 10 levels deep. 122 */ 123 void 124 diskprobe(void) 125 { 126 int node, child, stack[10], depth; 127 char buf[32]; 128 129 stack[0] = OF_peer(0); 130 if (stack[0] == 0) 131 return; 132 depth = 0; 133 TAILQ_INIT(&disklist); 134 135 for (;;) { 136 node = stack[depth]; 137 138 if (node == 0 || node == -1) { 139 if (--depth < 0) 140 return; 141 142 stack[depth] = OF_peer(stack[depth]); 143 continue; 144 } 145 146 #ifdef BOOT_DEBUG 147 dump_node(node); 148 #endif 149 if ((OF_getprop(node, "device_type", buf, sizeof(buf)) > 0 && 150 strcmp(buf, "block") == 0 && 151 OF_getprop(node, "name", buf, sizeof(buf)) > 0 && 152 strcmp(buf, "disk") == 0)) { 153 new_diskinfo(node); 154 } 155 156 child = OF_child(node); 157 if (child != 0 && child != -1 && depth < 9) 158 stack[++depth] = child; 159 else 160 stack[depth] = OF_peer(stack[depth]); 161 } 162 } 163