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