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.1 (Berkeley) 06/10/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/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 cdstrategy(bp) 396 register struct buf *bp; 397 { 398 register int unit = cdunit(bp->b_dev); 399 register struct cd_softc *cs = &cd_softc[unit]; 400 register daddr_t bn; 401 register int sz, s; 402 403 #ifdef DEBUG 404 if (cddebug & CDB_FOLLOW) 405 printf("cdstrategy(%x): unit %d\n", bp, unit); 406 #endif 407 if ((cs->sc_flags & CDF_INITED) == 0) { 408 bp->b_error = ENXIO; 409 bp->b_flags |= B_ERROR; 410 goto done; 411 } 412 bn = bp->b_blkno; 413 sz = howmany(bp->b_bcount, DEV_BSIZE); 414 if (bn < 0 || bn + sz > cs->sc_size) { 415 sz = cs->sc_size - bn; 416 if (sz == 0) { 417 bp->b_resid = bp->b_bcount; 418 goto done; 419 } 420 if (sz < 0) { 421 bp->b_error = EINVAL; 422 bp->b_flags |= B_ERROR; 423 goto done; 424 } 425 bp->b_bcount = dbtob(sz); 426 } 427 bp->b_resid = bp->b_bcount; 428 /* 429 * "Start" the unit. 430 */ 431 s = splbio(); 432 cdstart(cs, bp); 433 splx(s); 434 return; 435 done: 436 biodone(bp); 437 } 438 439 cdstart(cs, bp) 440 register struct cd_softc *cs; 441 register struct buf *bp; 442 { 443 register long bcount, rcount; 444 struct buf *cbp; 445 caddr_t addr; 446 daddr_t bn; 447 448 #ifdef DEBUG 449 if (cddebug & CDB_FOLLOW) 450 printf("cdstart(%x, %x)\n", cs, bp); 451 #endif 452 /* 453 * Instumentation (not real meaningful) 454 */ 455 cs->sc_usecnt++; 456 if (cs->sc_dk >= 0) { 457 dk_busy |= 1 << cs->sc_dk; 458 dk_xfer[cs->sc_dk]++; 459 dk_wds[cs->sc_dk] += bp->b_bcount >> 6; 460 } 461 /* 462 * Allocate component buffers and fire off the requests 463 */ 464 bn = bp->b_blkno; 465 addr = bp->b_un.b_addr; 466 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 467 cbp = cdbuffer(cs, bp, bn, addr, bcount); 468 rcount = cbp->b_bcount; 469 (*bdevsw[major(cbp->b_dev)].d_strategy)(cbp); 470 bn += btodb(rcount); 471 addr += rcount; 472 } 473 } 474 475 /* 476 * Build a component buffer header. 477 */ 478 struct buf * 479 cdbuffer(cs, bp, bn, addr, bcount) 480 register struct cd_softc *cs; 481 struct buf *bp; 482 daddr_t bn; 483 caddr_t addr; 484 long bcount; 485 { 486 register struct cdcinfo *ci; 487 register struct buf *cbp; 488 register daddr_t cbn, cboff; 489 490 #ifdef DEBUG 491 if (cddebug & CDB_IO) 492 printf("cdbuffer(%x, %x, %d, %x, %d)\n", 493 cs, bp, bn, addr, bcount); 494 #endif 495 /* 496 * Determine which component bn falls in. 497 */ 498 cbn = bn; 499 cboff = 0; 500 /* 501 * Serially concatenated 502 */ 503 if (cs->sc_ileave == 0) { 504 register daddr_t sblk; 505 506 sblk = 0; 507 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) 508 sblk += ci->ci_size; 509 cbn -= sblk; 510 } 511 /* 512 * Interleaved 513 */ 514 else { 515 register struct cdiinfo *ii; 516 int cdisk, off; 517 518 cboff = cbn % cs->sc_ileave; 519 cbn /= cs->sc_ileave; 520 for (ii = cs->sc_itable; ii->ii_ndisk; ii++) 521 if (ii->ii_startblk > cbn) 522 break; 523 ii--; 524 off = cbn - ii->ii_startblk; 525 if (ii->ii_ndisk == 1) { 526 cdisk = ii->ii_index[0]; 527 cbn = ii->ii_startoff + off; 528 } else { 529 cdisk = ii->ii_index[off % ii->ii_ndisk]; 530 cbn = ii->ii_startoff + off / ii->ii_ndisk; 531 } 532 cbn *= cs->sc_ileave; 533 ci = &cs->sc_cinfo[cdisk]; 534 } 535 /* 536 * Fill in the component buf structure. 537 */ 538 cbp = getcbuf(); 539 cbp->b_flags = bp->b_flags | B_CALL; 540 cbp->b_iodone = cdiodone; 541 cbp->b_proc = bp->b_proc; 542 cbp->b_dev = ci->ci_dev; 543 cbp->b_blkno = cbn + cboff; 544 cbp->b_un.b_addr = addr; 545 cbp->b_vp = 0; 546 if (cs->sc_ileave == 0) 547 cbp->b_bcount = dbtob(ci->ci_size - cbn); 548 else 549 cbp->b_bcount = dbtob(cs->sc_ileave - cboff); 550 if (cbp->b_bcount > bcount) 551 cbp->b_bcount = bcount; 552 /* 553 * XXX context for cdiodone 554 */ 555 cbp->b_saveaddr = (caddr_t)bp; 556 cbp->b_pfcent = ((cs - cd_softc) << 16) | (ci - cs->sc_cinfo); 557 #ifdef DEBUG 558 if (cddebug & CDB_IO) 559 printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n", 560 ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->b_blkno, 561 cbp->b_un.b_addr, cbp->b_bcount); 562 #endif 563 return(cbp); 564 } 565 566 cdintr(cs, bp) 567 register struct cd_softc *cs; 568 register struct buf *bp; 569 { 570 571 #ifdef DEBUG 572 if (cddebug & CDB_FOLLOW) 573 printf("cdintr(%x, %x)\n", cs, bp); 574 #endif 575 /* 576 * Request is done for better or worse, wakeup the top half. 577 */ 578 if (--cs->sc_usecnt == 0 && cs->sc_dk >= 0) 579 dk_busy &= ~(1 << cs->sc_dk); 580 if (bp->b_flags & B_ERROR) 581 bp->b_resid = bp->b_bcount; 582 biodone(bp); 583 } 584 585 /* 586 * Called by biodone at interrupt time. 587 * Mark the component as done and if all components are done, 588 * take a cd interrupt. 589 */ 590 void 591 cdiodone(cbp) 592 register struct buf *cbp; 593 { 594 register struct buf *bp = (struct buf *)cbp->b_saveaddr;/* XXX */ 595 register int unit = (cbp->b_pfcent >> 16) & 0xFFFF; /* XXX */ 596 int count, s; 597 598 s = splbio(); 599 #ifdef DEBUG 600 if (cddebug & CDB_FOLLOW) 601 printf("cdiodone(%x)\n", cbp); 602 if (cddebug & CDB_IO) { 603 printf("cdiodone: bp %x bcount %d resid %d\n", 604 bp, bp->b_bcount, bp->b_resid); 605 printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n", 606 cbp->b_dev, cbp->b_pfcent & 0xFFFF, cbp, 607 cbp->b_blkno, cbp->b_un.b_addr, cbp->b_bcount); 608 } 609 #endif 610 611 if (cbp->b_flags & B_ERROR) { 612 bp->b_flags |= B_ERROR; 613 bp->b_error = biowait(cbp); 614 #ifdef DEBUG 615 printf("cd%d: error %d on component %d\n", 616 unit, bp->b_error, cbp->b_pfcent & 0xFFFF); 617 #endif 618 } 619 count = cbp->b_bcount; 620 putcbuf(cbp); 621 622 /* 623 * If all done, "interrupt". 624 */ 625 bp->b_resid -= count; 626 if (bp->b_resid < 0) 627 panic("cdiodone: count"); 628 if (bp->b_resid == 0) 629 cdintr(&cd_softc[unit], bp); 630 splx(s); 631 } 632 633 cdread(dev, uio) 634 dev_t dev; 635 struct uio *uio; 636 { 637 register int unit = cdunit(dev); 638 639 #ifdef DEBUG 640 if (cddebug & CDB_FOLLOW) 641 printf("cdread(%x, %x)\n", dev, uio); 642 #endif 643 return(physio(cdstrategy, NULL, dev, B_READ, minphys, uio)); 644 } 645 646 cdwrite(dev, uio) 647 dev_t dev; 648 struct uio *uio; 649 { 650 register int unit = cdunit(dev); 651 652 #ifdef DEBUG 653 if (cddebug & CDB_FOLLOW) 654 printf("cdwrite(%x, %x)\n", dev, uio); 655 #endif 656 return(physio(cdstrategy, NULL, dev, B_WRITE, minphys, uio)); 657 } 658 659 cdioctl(dev, cmd, data, flag) 660 dev_t dev; 661 int cmd; 662 caddr_t data; 663 int flag; 664 { 665 return(EINVAL); 666 } 667 668 cdsize(dev) 669 dev_t dev; 670 { 671 int unit = cdunit(dev); 672 register struct cd_softc *cs = &cd_softc[unit]; 673 674 if (unit >= numcd || (cs->sc_flags & CDF_INITED) == 0) 675 return(-1); 676 return(cs->sc_size); 677 } 678 679 cddump(dev) 680 { 681 return(ENXIO); 682 } 683 #endif 684