ofw_disk.c revision 96423
1/* 2 * Copyright (C) 2000 Benno Rice. 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 Benno Rice ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * $FreeBSD: head/sys/boot/ofw/libofw/ofw_disk.c 96423 2002-05-11 21:30:46Z jake $ 26 */ 27 28/* 29 * Disk I/O routines using Open Firmware 30 */ 31 32#include <sys/param.h> 33#include <sys/disklabel.h> 34 35#include <netinet/in.h> 36 37#include <machine/stdarg.h> 38 39#include <stand.h> 40 41#include "bootstrap.h" 42#include "libofw.h" 43 44#define DISKSECSZ 512 45 46static int ofwd_init(void); 47static int ofwd_strategy(void *devdata, int flag, daddr_t dblk, 48 size_t size, char *buf, size_t *rsize); 49static int ofwd_open(struct open_file *f, ...); 50static int ofwd_close(struct open_file *f); 51static void ofwd_print(int verbose); 52static char * ofwd_getdevpath(int unit); 53int readdisklabel(struct ofw_devdesc *); 54 55struct devsw ofwdisk = { 56 "disk", 57 DEVT_DISK, 58 ofwd_init, 59 ofwd_strategy, 60 ofwd_open, 61 ofwd_close, 62 noioctl, 63 ofwd_print 64}; 65 66static struct ofwdinfo { 67 int ofwd_unit; 68 char ofwd_path[255]; 69} ofwdinfo[MAXDEV]; 70static int nofwdinfo = 0; 71static int probed; 72 73#define OFDP_FOUND 0 74#define OFDP_NOTFOUND 1 75#define OFDP_TERMINATE 2 76 77#define MAXDEV_IDE 4 78#define MAXDEV_DEFAULT 16 /* SCSI etc. */ 79 80void 81ofwd_enter_dev(const char *devpath) 82{ 83 char *p; 84 int n; 85 86 if (ofwd_getunit(devpath) != -1) 87 return; 88 if ((p = strrchr(devpath, ',')) != NULL) 89 n = p - devpath; 90 else 91 n = strlen(devpath); 92 ofwdinfo[nofwdinfo].ofwd_unit = nofwdinfo; 93 strncpy(ofwdinfo[nofwdinfo].ofwd_path, devpath, n); 94 ofwdinfo[nofwdinfo].ofwd_path[n] = '\0'; 95 printf("disk%d is %s\n", nofwdinfo, ofwdinfo[nofwdinfo].ofwd_path); 96 nofwdinfo++; 97} 98 99static int 100ofwd_probe_dev(char *devpath) 101{ 102 ihandle_t instance; 103 int rv; 104 105 /* Is the device already in the list? */ 106 if (ofwd_getunit(devpath) != -1) 107 return OFDP_FOUND; 108 instance = OF_open(devpath); 109 if (instance != -1) { 110 ofwd_enter_dev(devpath); 111 OF_close(instance); 112 } else 113 return OFDP_NOTFOUND; 114 if (nofwdinfo > MAXDEV) { 115 printf("Hit MAXDEV probing disks.\n"); 116 return OFDP_TERMINATE; 117 } 118 return OFDP_FOUND; 119} 120 121static int 122ofwd_probe_devs(void) 123{ 124 int ret; 125 char devpath[255]; 126#ifdef __sparc64__ 127 int i, n; 128 char cdevpath[255]; 129#endif 130 131 probed = 1; 132 ofw_devsearch_init(); 133 while ((ret = ofw_devsearch("block", devpath)) != 0) { 134 devpath[sizeof devpath - 1] = 0; 135 if (ret == -1) 136 return 1; 137#ifdef DEBUG 138 printf("devpath=\"%s\" ret=%d\n", devpath, ret); 139#endif 140 141 if (strstr(devpath, "cdrom") != 0) 142 continue; 143 144#ifdef __sparc64__ 145 /* 146 * sparc64 machines usually only have a single disk node as 147 * child of the controller (in the ATA case, there may exist 148 * an additional cdrom node, which we ignore above, since 149 * booting from it is special, and it can also be used as a 150 * disk node). 151 * Devices are accessed by using disk@unit; when no unit 152 * number is given, 0 is assumed. 153 * There is no way we can enumerate the existing disks except 154 * trying to open them, which unfortunately creates some deleays 155 * and spurioius warnings printed by the prom, which we can't 156 * do much about. The search may not stop on the first 157 * unsuccessful attempt, because that would cause disks that 158 * follow one with an invalid label (like CD-ROMS) would not 159 * be detected this way. 160 * Try to at least be a bit smart and only probe 4 devices in 161 * the IDE case. 162 */ 163 if (strstr(devpath, "/ide@") != NULL) 164 n = MAXDEV_IDE; 165 else 166 n = MAXDEV_DEFAULT; 167 for (i = 0; i < n; i++) { 168 sprintf(cdevpath, "%s@%d", devpath, i); 169 if (ofwd_probe_dev(cdevpath) == OFDP_TERMINATE) 170 return 1; 171 } 172#else 173 if (ofwd_probe_dev(devpath) == OFDP_TERMINATE) 174 return 1; 175#endif 176 } 177 178 return 0; 179} 180 181static int 182ofwd_init(void) 183{ 184#ifdef __sparc64__ 185 /* Short-circuit the device probing, since it takes too long. */ 186 return 0; 187#else 188 return ofwd_init_devs(); 189#endif 190} 191 192static int 193ofwd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, 194 size_t *rsize) 195{ 196 struct ofw_devdesc *dp = (struct ofw_devdesc *)devdata; 197 unsigned long pos; 198 int n; 199 int i, j; 200 201 pos = (dp->d_kind.ofwdisk.partoff + dblk) * dp->d_kind.ofwdisk.bsize; 202 203 do { 204 if (OF_seek(dp->d_kind.ofwdisk.handle, pos) < 0) { 205 return EIO; 206 } 207 n = OF_read(dp->d_kind.ofwdisk.handle, buf, size); 208 if (n < 0 && n != -2) { 209 return EIO; 210 } 211 } while (n == -2); 212 213 *rsize = size; 214 return 0; 215} 216 217static int 218ofwd_open(struct open_file *f, ...) 219{ 220 va_list vl; 221 struct ofw_devdesc *dp; 222 char *devpath; 223 phandle_t diskh; 224 char buf[256]; 225 int i, j; 226 227 va_start(vl, f); 228 dp = va_arg(vl, struct ofw_devdesc *); 229 va_end(vl); 230 231 /* 232 * The unit number is really an index into our device array. 233 * If it is not in the list, we may need to probe now. 234 */ 235 if (!probed && dp->d_kind.ofwdisk.unit >= nofwdinfo) 236 ofwd_probe_devs(); 237 if (dp->d_kind.ofwdisk.unit >= nofwdinfo) 238 return 1; 239 devpath = ofwdinfo[dp->d_kind.ofwdisk.unit].ofwd_path; 240 sprintf(buf, "%s,%d:%c", devpath, dp->d_kind.ofwdisk.slice, 241 'a' + dp->d_kind.ofwdisk.partition); 242 if ((diskh = OF_open(buf)) == -1) { 243 printf("ofwd_open: Could not open %s\n", buf); 244 return 1; 245 } 246 dp->d_kind.ofwdisk.bsize = DISKSECSZ; 247 dp->d_kind.ofwdisk.handle = diskh; 248 readdisklabel(dp); 249 250 return 0; 251} 252 253int 254readdisklabel(struct ofw_devdesc *dp) 255{ 256 char buf[DISKSECSZ]; 257 struct disklabel *lp; 258 size_t size; 259 int i; 260 261 dp->d_kind.ofwdisk.partoff = 0; 262 dp->d_dev->dv_strategy(dp, 0, LABELSECTOR, sizeof(buf), buf, &size); 263 i = dp->d_kind.ofwdisk.partition; 264 if (i >= MAXPARTITIONS) 265 return 1; 266 267 lp = (struct disklabel *)(buf + LABELOFFSET); 268 dp->d_kind.ofwdisk.partoff = lp->d_partitions[i].p_offset; 269 return 0; 270} 271 272static int 273ofwd_close(struct open_file *f) 274{ 275 struct ofw_devdesc *dev = f->f_devdata; 276 OF_close(dev->d_kind.ofwdisk.handle); 277 278 return 0; 279} 280 281static void 282ofwd_print(int verbose) 283{ 284 int i; 285 char line[80]; 286 287 if (!probed) 288 ofwd_probe_devs(); 289 for (i = 0; i < nofwdinfo; i++) { 290 sprintf(line, " disk%d: %s", i, ofwdinfo[i].ofwd_path); 291 pager_output(line); 292 pager_output("\n"); 293 } 294 return; 295} 296 297int 298ofwd_getunit(const char *path) 299{ 300 char *p; 301 int i, n; 302 303 if ((p = strrchr(path, ',')) != NULL) 304 n = p - path; 305 else 306 n = strlen(path); 307 for (i = 0; i < nofwdinfo; i++) { 308 if (strncmp(path, ofwdinfo[i].ofwd_path, n) == 0) 309 return i; 310 } 311 312 return -1; 313} 314