1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * %sccs.include.redist.c% 11 * 12 * from: Utah $Hdr: cd.c 1.1 90/07/09$ 13 * 14 * @(#)cd.c 7.3 (Berkeley) 12/16/90 15 */ 16 17 /* 18 * "Concatenated" disk driver. 19 */ 20 #include "cd.h" 21 #if NCD > 0 22 23 #include "sys/param.h" 24 #include "sys/systm.h" 25 #include "sys/errno.h" 26 #include "sys/dkstat.h" 27 #include "sys/buf.h" 28 #include "sys/malloc.h" 29 #include "sys/conf.h" 30 31 #include "cdvar.h" 32 33 #ifdef DEBUG 34 int cddebug = 0x00; 35 #define CDB_FOLLOW 0x01 36 #define CDB_INIT 0x02 37 #define CDB_IO 0x04 38 #endif 39 40 struct buf cdbuf[NCD]; 41 struct buf *cdbuffer(); 42 int cdiodone(); 43 44 #define cdunit(x) ((minor(x) >> 3) & 0x7) /* for consistency */ 45 46 #define getcbuf() \ 47 ((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK)) 48 #define putcbuf(bp) \ 49 free((caddr_t)(bp), M_DEVBUF) 50 51 struct cd_softc { 52 int sc_flags; /* flags */ 53 size_t sc_size; /* size of cd */ 54 int sc_ileave; /* interleave */ 55 int sc_ncdisks; /* number of components */ 56 struct cdcinfo sc_cinfo[NCDISKS]; /* component info */ 57 struct cdiinfo *sc_itable; /* interleave table */ 58 int sc_usecnt; /* number of requests active */ 59 struct buf *sc_bp; /* "current" request */ 60 int sc_dk; /* disk index */ 61 } cd_softc[NCD]; 62 63 /* sc_flags */ 64 #define CDF_ALIVE 0x01 65 #define CDF_INITED 0x02 66 67 cdinit(cd) 68 struct cddevice *cd; 69 { 70 register struct cd_softc *cs = &cd_softc[cd->cd_unit]; 71 register struct cdcinfo *ci; 72 register size_t size; 73 register int ix; 74 size_t minsize; 75 dev_t dev; 76 77 #ifdef DEBUG 78 if (cddebug & (CDB_FOLLOW|CDB_INIT)) 79 printf("cdinit: unit %d\n", cd->cd_unit); 80 #endif 81 cs->sc_dk = cd->cd_dk; 82 cs->sc_size = 0; 83 cs->sc_ileave = cd->cd_interleave; 84 cs->sc_ncdisks = 0; 85 /* 86 * Verify that each component piece exists and record 87 * relevant information about it. 88 */ 89 minsize = 0; 90 for (ix = 0; ix < NCDISKS; ix++) { 91 if ((dev = cd->cd_dev[ix]) == NODEV) 92 break; 93 ci = &cs->sc_cinfo[ix]; 94 ci->ci_dev = dev; 95 /* 96 * Calculate size (truncated to interleave boundary 97 * if necessary. 98 */ 99 if (bdevsw[major(dev)].d_psize) { 100 size = (*bdevsw[major(dev)].d_psize)(dev); 101 if (size <= 0) 102 size = 0; 103 } else 104 size = 0; 105 if (cs->sc_ileave > 1) 106 size -= size % cs->sc_ileave; 107 if (size == 0) 108 return(0); 109 if (minsize == 0 || size < minsize) 110 minsize = size; 111 ci->ci_size = size; 112 cs->sc_size += size; 113 cs->sc_ncdisks++; 114 } 115 /* 116 * If uniform interleave is desired set all sizes to that of 117 * the smallest component. 118 */ 119 if (cd->cd_flags & CDF_UNIFORM) { 120 for (ci = cs->sc_cinfo; 121 ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++) 122 ci->ci_size = minsize; 123 cs->sc_size = cs->sc_ncdisks * minsize; 124 } 125 /* 126 * Construct the interleave table 127 */ 128 if (!cdinterleave(cs)) 129 return(0); 130 if (cd->cd_dk >= 0) 131 dk_wpms[cd->cd_dk] = 32 * (60 * DEV_BSIZE / 2); /* XXX */ 132 printf("cd%d: %d components (%d blocks) concatenated", 133 cd->cd_unit, cs->sc_ncdisks, cs->sc_size); 134 if (cs->sc_ileave) 135 printf(", %d block interleave\n", cs->sc_ileave); 136 else 137 printf(" serially\n"); 138 cs->sc_flags = CDF_ALIVE | CDF_INITED; 139 return(1); 140 } 141 142 cdinterleave(cs) 143 register struct cd_softc *cs; 144 { 145 register struct cdcinfo *ci, *smallci; 146 register struct cdiinfo *ii; 147 register daddr_t bn, lbn; 148 register int ix; 149 u_long size; 150 151 #ifdef DEBUG 152 if (cddebug & CDB_INIT) 153 printf("cdinterleave(%x): ileave %d\n", cs, cs->sc_ileave); 154 #endif 155 /* 156 * Allocate an interleave table. 157 * Chances are this is too big, but we don't care. 158 */ 159 size = (cs->sc_ncdisks + 1) * sizeof(struct cdiinfo); 160 cs->sc_itable = (struct cdiinfo *)malloc(size, M_DEVBUF, M_WAITOK); 161 bzero((caddr_t)cs->sc_itable, size); 162 /* 163 * Trivial case: no interleave (actually interleave of disk size). 164 * Each table entry represent a single component in its entirety. 165 */ 166 if (cs->sc_ileave == 0) { 167 bn = 0; 168 ii = cs->sc_itable; 169 for (ix = 0; ix < cs->sc_ncdisks; ix++) { 170 ii->ii_ndisk = 1; 171 ii->ii_startblk = bn; 172 ii->ii_startoff = 0; 173 ii->ii_index[0] = ix; 174 bn += cs->sc_cinfo[ix].ci_size; 175 ii++; 176 } 177 ii->ii_ndisk = 0; 178 #ifdef DEBUG 179 if (cddebug & CDB_INIT) 180 printiinfo(cs->sc_itable); 181 #endif 182 return(1); 183 } 184 /* 185 * The following isn't fast or pretty; it doesn't have to be. 186 */ 187 size = 0; 188 bn = lbn = 0; 189 for (ii = cs->sc_itable; ; ii++) { 190 /* 191 * Locate the smallest of the remaining components 192 */ 193 smallci = NULL; 194 for (ci = cs->sc_cinfo; 195 ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++) 196 if (ci->ci_size > size && 197 (smallci == NULL || 198 ci->ci_size < smallci->ci_size)) 199 smallci = ci; 200 /* 201 * Nobody left, all done 202 */ 203 if (smallci == NULL) { 204 ii->ii_ndisk = 0; 205 break; 206 } 207 /* 208 * Record starting logical block and component offset 209 */ 210 ii->ii_startblk = bn / cs->sc_ileave; 211 ii->ii_startoff = lbn; 212 /* 213 * Determine how many disks take part in this interleave 214 * and record their indices. 215 */ 216 ix = 0; 217 for (ci = cs->sc_cinfo; 218 ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++) 219 if (ci->ci_size >= smallci->ci_size) 220 ii->ii_index[ix++] = ci - cs->sc_cinfo; 221 ii->ii_ndisk = ix; 222 bn += ix * (smallci->ci_size - size); 223 lbn = smallci->ci_size / cs->sc_ileave; 224 size = smallci->ci_size; 225 } 226 #ifdef DEBUG 227 if (cddebug & CDB_INIT) 228 printiinfo(cs->sc_itable); 229 #endif 230 return(1); 231 } 232 233 #ifdef DEBUG 234 printiinfo(ii) 235 struct cdiinfo *ii; 236 { 237 register int ix, i; 238 239 for (ix = 0; ii->ii_ndisk; ix++, ii++) { 240 printf(" itab[%d]: #dk %d sblk %d soff %d", 241 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); 242 for (i = 0; i < ii->ii_ndisk; i++) 243 printf(" %d", ii->ii_index[i]); 244 printf("\n"); 245 } 246 } 247 #endif 248 249 cdopen(dev, flags) 250 dev_t dev; 251 { 252 int unit = cdunit(dev); 253 register struct cd_softc *cs = &cd_softc[unit]; 254 255 #ifdef DEBUG 256 if (cddebug & CDB_FOLLOW) 257 printf("cdopen(%x, %x)\n", dev, flags); 258 #endif 259 if (unit >= NCD || (cs->sc_flags & CDF_ALIVE) == 0) 260 return(ENXIO); 261 return(0); 262 } 263 264 cdstrategy(bp) 265 register struct buf *bp; 266 { 267 register int unit = cdunit(bp->b_dev); 268 register struct cd_softc *cs = &cd_softc[unit]; 269 register daddr_t bn; 270 register int sz, s; 271 272 #ifdef DEBUG 273 if (cddebug & CDB_FOLLOW) 274 printf("cdstrategy(%x): unit %d\n", bp, unit); 275 #endif 276 if ((cs->sc_flags & CDF_INITED) == 0) { 277 bp->b_error = ENXIO; 278 bp->b_flags |= B_ERROR; 279 goto done; 280 } 281 bn = bp->b_blkno; 282 sz = howmany(bp->b_bcount, DEV_BSIZE); 283 if (bn < 0 || bn + sz > cs->sc_size) { 284 sz = cs->sc_size - bn; 285 if (sz == 0) { 286 bp->b_resid = bp->b_bcount; 287 goto done; 288 } 289 if (sz < 0) { 290 bp->b_error = EINVAL; 291 bp->b_flags |= B_ERROR; 292 goto done; 293 } 294 bp->b_bcount = dbtob(sz); 295 } 296 bp->b_resid = bp->b_bcount; 297 /* 298 * "Start" the unit. 299 * XXX: the use of sc_bp is just to retain the "traditional" 300 * interface to the start routine. 301 */ 302 s = splbio(); 303 cs->sc_bp = bp; 304 cdstart(unit); 305 splx(s); 306 return; 307 done: 308 biodone(bp); 309 } 310 311 cdstart(unit) 312 int unit; 313 { 314 register struct cd_softc *cs = &cd_softc[unit]; 315 register struct buf *bp = cs->sc_bp; 316 register long bcount, rcount; 317 struct buf *cbp; 318 caddr_t addr; 319 daddr_t bn; 320 321 #ifdef DEBUG 322 if (cddebug & CDB_FOLLOW) 323 printf("cdstart(%d)\n", unit); 324 #endif 325 /* 326 * Instumentation (not real meaningful) 327 */ 328 cs->sc_usecnt++; 329 if (cs->sc_dk >= 0) { 330 dk_busy |= 1 << cs->sc_dk; 331 dk_xfer[cs->sc_dk]++; 332 dk_wds[cs->sc_dk] += bp->b_bcount >> 6; 333 } 334 /* 335 * Allocate component buffers and fire off the requests 336 */ 337 bn = bp->b_blkno; 338 addr = bp->b_un.b_addr; 339 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 340 cbp = cdbuffer(cs, bp, bn, addr, bcount); 341 rcount = cbp->b_bcount; 342 (*bdevsw[major(cbp->b_dev)].d_strategy)(cbp); 343 bn += btodb(rcount); 344 addr += rcount; 345 } 346 } 347 348 /* 349 * Build a component buffer header. 350 */ 351 struct buf * 352 cdbuffer(cs, bp, bn, addr, bcount) 353 register struct cd_softc *cs; 354 struct buf *bp; 355 daddr_t bn; 356 caddr_t addr; 357 long bcount; 358 { 359 register struct cdcinfo *ci; 360 register struct buf *cbp; 361 register daddr_t cbn, cboff; 362 363 #ifdef DEBUG 364 if (cddebug & CDB_IO) 365 printf("cdbuffer(%x, %x, %d, %x, %d)\n", 366 cs, bp, bn, addr, bcount); 367 #endif 368 /* 369 * Determine which component bn falls in. 370 */ 371 cbn = bn; 372 cboff = 0; 373 /* 374 * Serially concatenated 375 */ 376 if (cs->sc_ileave == 0) { 377 register daddr_t sblk; 378 379 sblk = 0; 380 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) 381 sblk += ci->ci_size; 382 cbn -= sblk; 383 } 384 /* 385 * Interleaved 386 */ 387 else { 388 register struct cdiinfo *ii; 389 int cdisk, off; 390 391 cboff = cbn % cs->sc_ileave; 392 cbn /= cs->sc_ileave; 393 for (ii = cs->sc_itable; ii->ii_ndisk; ii++) 394 if (ii->ii_startblk > cbn) 395 break; 396 ii--; 397 off = cbn - ii->ii_startblk; 398 if (ii->ii_ndisk == 1) { 399 cdisk = ii->ii_index[0]; 400 cbn = ii->ii_startoff + off; 401 } else { 402 cdisk = ii->ii_index[off % ii->ii_ndisk]; 403 cbn = ii->ii_startoff + off / ii->ii_ndisk; 404 } 405 cbn *= cs->sc_ileave; 406 ci = &cs->sc_cinfo[cdisk]; 407 } 408 /* 409 * Fill in the component buf structure. 410 */ 411 cbp = getcbuf(); 412 cbp->b_flags = bp->b_flags | B_CALL; 413 cbp->b_iodone = cdiodone; 414 cbp->b_proc = bp->b_proc; 415 cbp->b_dev = ci->ci_dev; 416 cbp->b_blkno = cbn + cboff; 417 cbp->b_un.b_addr = addr; 418 cbp->b_vp = 0; 419 if (cs->sc_ileave == 0) 420 cbp->b_bcount = dbtob(ci->ci_size - cbn); 421 else 422 cbp->b_bcount = dbtob(cs->sc_ileave - cboff); 423 if (cbp->b_bcount > bcount) 424 cbp->b_bcount = bcount; 425 /* 426 * XXX: context for cdiodone 427 */ 428 cbp->b_saveaddr = (caddr_t)bp; 429 cbp->b_pfcent = ((cs - cd_softc) << 16) | (ci - cs->sc_cinfo); 430 #ifdef DEBUG 431 if (cddebug & CDB_IO) 432 printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n", 433 ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->b_blkno, 434 cbp->b_un.b_addr, cbp->b_bcount); 435 #endif 436 return(cbp); 437 } 438 439 cdintr(unit) 440 int unit; 441 { 442 register struct cd_softc *cs = &cd_softc[unit]; 443 register struct buf *bp = cs->sc_bp; 444 445 #ifdef DEBUG 446 if (cddebug & CDB_FOLLOW) 447 printf("cdintr(%d): bp %x\n", unit, bp); 448 #endif 449 /* 450 * Request is done for better or worse, wakeup the top half. 451 */ 452 if (--cs->sc_usecnt == 0 && cs->sc_dk >= 0) 453 dk_busy &= ~(1 << cs->sc_dk); 454 if (bp->b_flags & B_ERROR) 455 bp->b_resid = bp->b_bcount; 456 biodone(bp); 457 } 458 459 /* 460 * Called by biodone at interrupt time. 461 * Mark the component as done and if all components are done, 462 * take a cd interrupt. 463 */ 464 cdiodone(cbp) 465 register struct buf *cbp; 466 { 467 register struct buf *bp = (struct buf *)cbp->b_saveaddr;/* XXX */ 468 register int unit = (cbp->b_pfcent >> 16) & 0xFFFF; /* XXX */ 469 int count, s; 470 471 s = splbio(); 472 #ifdef DEBUG 473 if (cddebug & CDB_FOLLOW) 474 printf("cdiodone(%x)\n", cbp); 475 if (cddebug & CDB_IO) { 476 printf("cdiodone: bp %x bcount %d resid %d\n", 477 bp, bp->b_bcount, bp->b_resid); 478 printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n", 479 cbp->b_dev, cbp->b_pfcent & 0xFFFF, cbp, 480 cbp->b_blkno, cbp->b_un.b_addr, cbp->b_bcount); 481 } 482 #endif 483 484 if (cbp->b_flags & B_ERROR) { 485 bp->b_flags |= B_ERROR; 486 bp->b_error = biowait(cbp); 487 #ifdef DEBUG 488 printf("cd%d: error %d on component %d\n", 489 unit, bp->b_error, cbp->b_pfcent & 0xFFFF); 490 #endif 491 } 492 count = cbp->b_bcount; 493 putcbuf(cbp); 494 495 /* 496 * If all done, "interrupt". 497 * Again, sc_bp is only used to preserve the traditional interface. 498 */ 499 bp->b_resid -= count; 500 if (bp->b_resid < 0) 501 panic("cdiodone: count"); 502 if (bp->b_resid == 0) { 503 cd_softc[unit].sc_bp = bp; 504 cdintr(unit); 505 } 506 splx(s); 507 } 508 509 cdread(dev, uio) 510 dev_t dev; 511 struct uio *uio; 512 { 513 register int unit = cdunit(dev); 514 515 #ifdef DEBUG 516 if (cddebug & CDB_FOLLOW) 517 printf("cdread(%x, %x)\n", dev, uio); 518 #endif 519 return(physio(cdstrategy, &cdbuf[unit], dev, B_READ, minphys, uio)); 520 } 521 522 cdwrite(dev, uio) 523 dev_t dev; 524 struct uio *uio; 525 { 526 register int unit = cdunit(dev); 527 528 #ifdef DEBUG 529 if (cddebug & CDB_FOLLOW) 530 printf("cdwrite(%x, %x)\n", dev, uio); 531 #endif 532 return(physio(cdstrategy, &cdbuf[unit], dev, B_WRITE, minphys, uio)); 533 } 534 535 cdioctl(dev, cmd, data, flag) 536 dev_t dev; 537 int cmd; 538 caddr_t data; 539 int flag; 540 { 541 return(EINVAL); 542 } 543 544 cdsize(dev) 545 dev_t dev; 546 { 547 int unit = cdunit(dev); 548 register struct cd_softc *cs = &cd_softc[unit]; 549 550 if (unit >= NCD || (cs->sc_flags & CDF_INITED) == 0) 551 return(-1); 552 return(cs->sc_size); 553 } 554 555 cddump(dev) 556 { 557 return(ENXIO); 558 } 559 #endif 560