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