1 /* $NetBSD: diskio.c,v 1.1 2002/02/24 20:51:08 leo Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Waldi Ravens. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Waldi Ravens. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <ctype.h> 37 #include <stdio.h> 38 #include <xhdi.h> 39 #include "libtos.h" 40 #include "diskio.h" 41 #include "ahdilbl.h" 42 #include <osbind.h> 43 44 struct pun_info { 45 u_int16_t puns; 46 u_int8_t pun[16]; 47 u_int32_t part_start[16]; 48 u_int32_t P_cookie; 49 u_int32_t *P_cookptr; 50 u_int16_t P_version; 51 u_int16_t P_max_sector; 52 u_int32_t reserved[16]; 53 }; 54 55 static char * strbd PROTO((char *, ...)); 56 static int setmami PROTO((disk_t *, char *)); 57 static int setnames PROTO((disk_t *)); 58 static int setsizes PROTO((disk_t *)); 59 static int ahdi_compatible PROTO((void)); 60 61 disk_t * 62 disk_open(name) 63 char *name; 64 { 65 disk_t *dd; 66 67 dd = xmalloc(sizeof *dd); 68 memset(dd, 0, sizeof *dd); 69 70 if (setmami(dd, name) || setnames(dd) || setsizes(dd)) { 71 disk_close(dd); 72 return(NULL); 73 } 74 return(dd); 75 } 76 77 void 78 disk_close(dd) 79 disk_t *dd; 80 { 81 if (dd) { 82 free(dd->product); 83 free(dd->sname); 84 free(dd->fname); 85 if (dd->xtra_info != NULL) 86 free(dd->xtra_info); 87 free(dd); 88 } 89 } 90 91 void * 92 disk_read(dd, start, count) 93 disk_t *dd; 94 u_int start, 95 count; 96 { 97 char *buffer; 98 int bdev; 99 long e; 100 101 buffer = xmalloc(count * dd->bsize); 102 103 e = XHReadWrite(dd->major, dd->minor, 0, start, count, buffer); 104 if (!e) 105 return(buffer); 106 if (e == -32 || (e == -1 && XHGetVersion() == -1)) { 107 if (!ahdi_compatible()) 108 fatal(-1, "AHDI 3.0 compatible harddisk driver required"); 109 bdev = BIOSDEV(dd->major, dd->minor); 110 if (bdev && !bios_read(buffer, start, count, bdev)) 111 return(buffer); 112 } 113 114 free(buffer); 115 return(NULL); 116 } 117 118 int 119 disk_write(dd, start, count, buffer) 120 disk_t *dd; 121 u_int start, 122 count; 123 void *buffer; 124 { 125 int bdev; 126 long e; 127 128 e = XHReadWrite(dd->major, dd->minor, 1, start, count, buffer); 129 if (e == -32 || (e == -1 && XHGetVersion() == -1)) { 130 if (!ahdi_compatible()) 131 fatal(-1, "AHDI 3.0 compatible harddisk driver required"); 132 bdev = BIOSDEV(dd->major, dd->minor); 133 if (bdev) 134 e = bios_write(buffer, start, count, bdev); 135 } 136 137 return((int)e); 138 } 139 140 static int 141 ahdi_compatible() 142 { 143 static int ahdi_compat; 144 145 if (!ahdi_compat) { 146 long oldsp = Super(0L); 147 struct pun_info *punp = *((struct pun_info **)0x0516); 148 (void)Super(oldsp); 149 if (punp && punp->P_cookie == 0x41484449 150 && punp->P_cookptr == &punp->P_cookie 151 && punp->P_version >= 0x0300) 152 ahdi_compat = 1; 153 } 154 return(ahdi_compat); 155 } 156 157 static int 158 setmami(dd, name) 159 disk_t *dd; 160 char *name; 161 { 162 char *p = name; 163 u_int target, lun; 164 bus_t bus; 165 166 if (*p == 'i') { 167 bus = IDE; 168 if (*++p < '0' || *p > '1') { 169 if (*p) 170 error(-1, "%s: invalid IDE target `%c'", name, *p); 171 else 172 error(-1, "%s: missing IDE target", name); 173 return(-1); 174 } 175 target = *p++ - '0'; 176 lun = 0; 177 } else { 178 char *b; 179 180 if (*p == 'a') { 181 bus = ACSI; 182 b = "ACSI"; 183 } else if (*p == 's') { 184 bus = SCSI; 185 b = "SCSI"; 186 } else { 187 error(-1, "%s: invalid DISK argument", name); 188 return(-1); 189 } 190 if (*++p < '0' || *p > '7') { 191 if (*p) 192 error(-1, "%s: invalid %s target `%c'", name, 193 b, *p); 194 else 195 error(-1, "%s: missing %s target", name, b); 196 return(-1); 197 } 198 target = *p++ - '0'; 199 200 if (*p < '0' || *p > '7') { 201 if (*p) { 202 error(-1, "%s: invalid %s lun `%c'", name, 203 b, *p); 204 return(-1); 205 } 206 lun = 0; 207 } else 208 lun = *p++ - '0'; 209 } 210 if (*p) { 211 error(-1, "%s: invalid DISK argument", name); 212 return(-1); 213 } 214 dd->major = MAJOR(bus, target, lun); 215 dd->minor = MINOR(bus, target, lun); 216 return(0); 217 } 218 219 static int 220 setnames(dd) 221 disk_t *dd; 222 { 223 char sn[16], us[16], ls[16], *bs; 224 int b, u, l; 225 226 b = BUS(dd->major, dd->minor); 227 u = TARGET(dd->major, dd->minor); 228 l = LUN(dd->major, dd->minor); 229 230 switch (b) { 231 case IDE: bs = "IDE"; 232 break; 233 case ACSI: bs = "ACSI"; 234 break; 235 case SCSI: bs = "SCSI"; 236 break; 237 default: error(-1, "invalid bus no. %d", b); 238 return(-1); 239 } 240 241 if (u < 0 || u > 7 || (b == IDE && u > 1)) { 242 error(-1, "invalid %s target `%d'", bs, u); 243 return(-1); 244 } 245 sprintf(us, " target %d", u); 246 247 if (l < 0 || l > 7 || (b == IDE && l > 0)) { 248 error(-1, "invalid %s lun `%d'", bs, l); 249 return(-1); 250 } 251 if (b == IDE) { 252 sprintf(sn, "i%d", u); 253 ls[0] = '\0'; 254 } else { 255 sprintf(sn, "%c%d%d", tolower(*bs), u, l); 256 sprintf(ls, " lun %d", l); 257 } 258 259 dd->fname = strbd(bs, us, ls, NULL); 260 dd->sname = strbd(sn, NULL); 261 return(0); 262 } 263 264 static int 265 setsizes(dd) 266 disk_t *dd; 267 { 268 if (XHGetVersion() != -1) { 269 char *p, prod[1024]; 270 271 if (XHInqTarget2(dd->major, dd->minor, &dd->bsize, NULL, prod, 272 sizeof(prod))) { 273 if (XHInqTarget(dd->major, dd->minor, &dd->bsize, NULL, prod)) { 274 error(-1, "%s: device not configured", dd->sname); 275 return(-1); 276 } 277 } 278 p = strrchr(prod, '\0'); 279 while (isspace(*--p)) 280 *p = '\0'; 281 dd->product = strbd(prod, NULL); 282 if (!XHGetCapacity(dd->major, dd->minor, &dd->msize, &dd->bsize)) 283 return(0); 284 } else { 285 dd->product = strbd("unknown", NULL); 286 dd->bsize = AHDI_BSIZE; /* XXX */ 287 } 288 289 /* Trial&error search for last sector on medium */ 290 { 291 u_int u, l, m; 292 void *p, (*oldvec)(); 293 294 /* turn off etv_critic handler */ 295 oldvec = Setexc(257, bios_critic); 296 297 u = (u_int)-2; l = 0; 298 while (u != l) { 299 m = l + ((u - l + 1) / 2); 300 p = disk_read(dd, m, 1); 301 free(p); 302 if (p == NULL) 303 u = m - 1; 304 else 305 l = m; 306 } 307 308 /* turn on etv_critic handler */ 309 (void)Setexc(257, oldvec); 310 311 if (l) { 312 dd->msize = l + 1; 313 return(0); 314 } 315 error(-1, "%s: device not configured", dd->sname); 316 return(-1); 317 } 318 } 319 320 static char * 321 strbd(string1) 322 char *string1; 323 { 324 char *p, *result; 325 size_t length = 1; 326 va_list ap; 327 328 va_start(ap, string1); 329 for (p = string1; p; p = va_arg(ap, char *)) 330 length += strlen(p); 331 va_end(ap); 332 333 *(result = xmalloc(length)) = '\0'; 334 335 va_start(ap, string1); 336 for (p = string1; p; p = va_arg(ap, char *)) 337 strcat(result, p); 338 va_end(ap); 339 340 return(result); 341 } 342