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