1 /* $NetBSD: mscp_disk.c,v 1.76 2012/10/27 17:18:26 chs Exp $ */ 2 /* 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Chris Torek. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)uda.c 7.32 (Berkeley) 2/13/91 34 */ 35 36 /* 37 * Copyright (c) 1996 Ludd, University of Lule}, Sweden. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * Chris Torek. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 * 70 * @(#)uda.c 7.32 (Berkeley) 2/13/91 71 */ 72 73 /* 74 * RA disk device driver 75 * RX MSCP floppy disk device driver 76 * RRD MSCP CD device driver 77 */ 78 79 /* 80 * TODO 81 * write bad block forwarding code 82 */ 83 84 #include <sys/cdefs.h> 85 __KERNEL_RCSID(0, "$NetBSD: mscp_disk.c,v 1.76 2012/10/27 17:18:26 chs Exp $"); 86 87 #include <sys/param.h> 88 #include <sys/buf.h> 89 #include <sys/bufq.h> 90 #include <sys/device.h> 91 #include <sys/disk.h> 92 #include <sys/disklabel.h> 93 #include <sys/ioctl.h> 94 #include <sys/stat.h> 95 #include <sys/fcntl.h> 96 #include <sys/reboot.h> 97 #include <sys/proc.h> 98 #include <sys/systm.h> 99 #include <sys/conf.h> 100 101 #include <ufs/ufs/dinode.h> 102 #include <ufs/ffs/fs.h> 103 104 #include <sys/bus.h> 105 #include <sys/cpu.h> 106 107 #include <dev/mscp/mscp.h> 108 #include <dev/mscp/mscpreg.h> 109 #include <dev/mscp/mscpvar.h> 110 111 #include "locators.h" 112 #include "ioconf.h" 113 #include "ra.h" 114 115 /* 116 * Drive status, per drive 117 */ 118 struct ra_softc { 119 device_t ra_dev; /* Autoconf struct */ 120 struct disk ra_disk; 121 int ra_state; /* open/closed state */ 122 u_long ra_mediaid; /* media id */ 123 int ra_hwunit; /* Hardware unit number */ 124 int ra_havelabel; /* true if we have a label */ 125 int ra_wlabel; /* label sector is currently writable */ 126 }; 127 128 #define rx_softc ra_softc 129 #define racd_softc ra_softc 130 131 void raattach(device_t, device_t, void *); 132 int rx_putonline(struct rx_softc *); 133 void rrmakelabel(struct disklabel *, long); 134 int ra_putonline(dev_t, struct ra_softc *); 135 static inline struct ra_softc *mscp_device_lookup(dev_t); 136 137 #if NRA 138 139 int ramatch(device_t, cfdata_t, void *); 140 141 CFATTACH_DECL_NEW(ra, sizeof(struct ra_softc), 142 ramatch, raattach, NULL, NULL); 143 144 #endif /* NRA */ 145 146 #if NRA || NRACD || NRX 147 148 dev_type_open(raopen); 149 dev_type_close(raclose); 150 dev_type_read(raread); 151 dev_type_write(rawrite); 152 dev_type_ioctl(raioctl); 153 dev_type_strategy(rastrategy); 154 dev_type_dump(radump); 155 dev_type_size(rasize); 156 157 #if NRA 158 159 const struct bdevsw ra_bdevsw = { 160 raopen, raclose, rastrategy, raioctl, radump, rasize, D_DISK 161 }; 162 163 const struct cdevsw ra_cdevsw = { 164 raopen, raclose, raread, rawrite, raioctl, 165 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 166 }; 167 168 static struct dkdriver radkdriver = { 169 rastrategy, minphys 170 }; 171 172 /* 173 * More driver definitions, for generic MSCP code. 174 */ 175 176 int 177 ramatch(device_t parent, cfdata_t cf, void *aux) 178 { 179 struct drive_attach_args *da = aux; 180 struct mscp *mp = da->da_mp; 181 182 if ((da->da_typ & MSCPBUS_DISK) == 0) 183 return 0; 184 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT && 185 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit) 186 return 0; 187 /* 188 * Check if this disk is a floppy (RX) or cd (RRD) 189 * Seems to be a safe way to test it per Chris Torek. 190 */ 191 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@') 192 return 0; 193 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'R' - '@') 194 return 0; 195 return 1; 196 } 197 198 #endif /* NRA */ 199 200 /* 201 * Open a drive. 202 */ 203 /*ARGSUSED*/ 204 int 205 raopen(dev_t dev, int flag, int fmt, struct lwp *l) 206 { 207 struct ra_softc *ra = mscp_device_lookup(dev); 208 int error, part, mask; 209 /* 210 * Make sure this is a reasonable open request. 211 */ 212 if (!ra) 213 return ENXIO; 214 215 part = DISKPART(dev); 216 217 mutex_enter(&ra->ra_disk.dk_openlock); 218 219 /* 220 * If there are wedges, and this is not RAW_PART, then we 221 * need to fail. 222 */ 223 if (ra->ra_disk.dk_nwedges != 0 && part != RAW_PART) { 224 error = EBUSY; 225 goto bad1; 226 } 227 228 /* 229 * If this is the first open; we must first try to put 230 * the disk online (and read the label). 231 */ 232 if (ra->ra_state == DK_CLOSED) { 233 if (ra_putonline(dev, ra) == MSCP_FAILED) { 234 error = ENXIO; 235 goto bad1; 236 } 237 } 238 239 /* If the disk has no label; allow writing everywhere */ 240 if (ra->ra_havelabel == 0) 241 ra->ra_wlabel = 1; 242 243 if (part >= ra->ra_disk.dk_label->d_npartitions) { 244 error = ENXIO; 245 goto bad1; 246 } 247 248 /* 249 * Wait for the state to settle 250 */ 251 #if notyet 252 while (ra->ra_state != DK_OPEN) 253 if ((error = tsleep((void *)ra, (PZERO + 1) | PCATCH, 254 devopn, 0))) { 255 splx(s); 256 return (error); 257 } 258 #endif 259 260 mask = 1 << part; 261 262 switch (fmt) { 263 case S_IFCHR: 264 ra->ra_disk.dk_copenmask |= mask; 265 break; 266 case S_IFBLK: 267 ra->ra_disk.dk_bopenmask |= mask; 268 break; 269 } 270 ra->ra_disk.dk_openmask |= mask; 271 error = 0; 272 bad1: 273 mutex_exit(&ra->ra_disk.dk_openlock); 274 return (error); 275 } 276 277 /* ARGSUSED */ 278 int 279 raclose(dev_t dev, int flags, int fmt, struct lwp *l) 280 { 281 struct ra_softc *ra = mscp_device_lookup(dev); 282 int mask = (1 << DISKPART(dev)); 283 284 mutex_enter(&ra->ra_disk.dk_openlock); 285 286 switch (fmt) { 287 case S_IFCHR: 288 ra->ra_disk.dk_copenmask &= ~mask; 289 break; 290 case S_IFBLK: 291 ra->ra_disk.dk_bopenmask &= ~mask; 292 break; 293 } 294 ra->ra_disk.dk_openmask = 295 ra->ra_disk.dk_copenmask | ra->ra_disk.dk_bopenmask; 296 297 /* 298 * Should wait for I/O to complete on this partition even if 299 * others are open, but wait for work on blkflush(). 300 */ 301 #if notyet 302 if (ra->ra_openpart == 0) { 303 s = spluba(); 304 while (bufq_peek(udautab[unit]) != NULL) 305 (void) tsleep(&udautab[unit], PZERO - 1, 306 "raclose", 0); 307 splx(s); 308 ra->ra_state = DK_CLOSED; 309 ra->ra_wlabel = 0; 310 } 311 #endif 312 mutex_exit(&ra->ra_disk.dk_openlock); 313 return (0); 314 } 315 316 /* 317 * Queue a transfer request, and if possible, hand it to the controller. 318 */ 319 void 320 rastrategy(struct buf *bp) 321 { 322 struct ra_softc *ra = mscp_device_lookup(bp->b_dev); 323 int unit; 324 int b; 325 326 /* 327 * Make sure this is a reasonable drive to use. 328 */ 329 unit = DISKUNIT(bp->b_dev); 330 if (ra == NULL) { 331 bp->b_error = ENXIO; 332 goto done; 333 } 334 /* 335 * If drive is open `raw' or reading label, let it at it. 336 */ 337 if (ra->ra_state == DK_RDLABEL) { 338 /* Make some statistics... /bqt */ 339 b = splbio(); 340 disk_busy(&ra->ra_disk); 341 splx(b); 342 mscp_strategy(bp, device_parent(ra->ra_dev)); 343 return; 344 } 345 346 /* If disk is not online, try to put it online */ 347 if (ra->ra_state == DK_CLOSED) 348 if (ra_putonline(bp->b_dev, ra) == MSCP_FAILED) { 349 bp->b_error = EIO; 350 goto done; 351 } 352 353 /* 354 * Determine the size of the transfer, and make sure it is 355 * within the boundaries of the partition. 356 */ 357 if (bounds_check_with_label(&ra->ra_disk, bp, ra->ra_wlabel) <= 0) 358 goto done; 359 360 /* Make some statistics... /bqt */ 361 b = splbio(); 362 disk_busy(&ra->ra_disk); 363 splx(b); 364 mscp_strategy(bp, device_parent(ra->ra_dev)); 365 return; 366 367 done: 368 biodone(bp); 369 } 370 371 int 372 raread(dev_t dev, struct uio *uio, int flags) 373 { 374 375 return (physio(rastrategy, NULL, dev, B_READ, minphys, uio)); 376 } 377 378 int 379 rawrite(dev_t dev, struct uio *uio, int flags) 380 { 381 382 return (physio(rastrategy, NULL, dev, B_WRITE, minphys, uio)); 383 } 384 385 /* 386 * I/O controls. 387 */ 388 int 389 raioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 390 { 391 struct disklabel *lp, *tp; 392 struct ra_softc *ra = mscp_device_lookup(dev); 393 int error = 0; 394 #ifdef __HAVE_OLD_DISKLABEL 395 struct disklabel newlabel; 396 #endif 397 398 lp = ra->ra_disk.dk_label; 399 400 switch (cmd) { 401 402 case DIOCGDINFO: 403 memcpy(data, lp, sizeof (struct disklabel)); 404 break; 405 #ifdef __HAVE_OLD_DISKLABEL 406 case ODIOCGDINFO: 407 memcpy(&newlabel, lp, sizeof newlabel); 408 if (newlabel.d_npartitions > OLDMAXPARTITIONS) 409 return ENOTTY; 410 memcpy(data, &newlabel, sizeof (struct olddisklabel)); 411 break; 412 #endif 413 414 case DIOCGPART: 415 ((struct partinfo *)data)->disklab = lp; 416 ((struct partinfo *)data)->part = 417 &lp->d_partitions[DISKPART(dev)]; 418 break; 419 420 case DIOCWDINFO: 421 case DIOCSDINFO: 422 #ifdef __HAVE_OLD_DISKLABEL 423 case ODIOCWDINFO: 424 case ODIOCSDINFO: 425 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { 426 memset(&newlabel, 0, sizeof newlabel); 427 memcpy(&newlabel, data, sizeof (struct olddisklabel)); 428 tp = &newlabel; 429 } else 430 #endif 431 tp = (struct disklabel *)data; 432 433 if ((flag & FWRITE) == 0) 434 error = EBADF; 435 else { 436 mutex_enter(&ra->ra_disk.dk_openlock); 437 error = setdisklabel(lp, tp, 0, 0); 438 if ((error == 0) && (cmd == DIOCWDINFO 439 #ifdef __HAVE_OLD_DISKLABEL 440 || cmd == ODIOCWDINFO 441 #endif 442 )) { 443 ra->ra_wlabel = 1; 444 error = writedisklabel(dev, rastrategy, lp,0); 445 ra->ra_wlabel = 0; 446 } 447 mutex_exit(&ra->ra_disk.dk_openlock); 448 } 449 break; 450 451 case DIOCWLABEL: 452 if ((flag & FWRITE) == 0) 453 error = EBADF; 454 else 455 ra->ra_wlabel = 1; 456 break; 457 458 case DIOCGDEFLABEL: 459 #ifdef __HAVE_OLD_DISKLABEL 460 case ODIOCGDEFLABEL: 461 if (cmd == ODIOCGDEFLABEL) 462 tp = &newlabel; 463 else 464 #endif 465 tp = (struct disklabel *)data; 466 memset(tp, 0, sizeof(struct disklabel)); 467 tp->d_secsize = lp->d_secsize; 468 tp->d_nsectors = lp->d_nsectors; 469 tp->d_ntracks = lp->d_ntracks; 470 tp->d_ncylinders = lp->d_ncylinders; 471 tp->d_secpercyl = lp->d_secpercyl; 472 tp->d_secperunit = lp->d_secperunit; 473 tp->d_type = DTYPE_MSCP; 474 tp->d_rpm = 3600; 475 rrmakelabel(tp, ra->ra_mediaid); 476 #ifdef __HAVE_OLD_DISKLABEL 477 if (cmd == ODIOCGDEFLABEL) { 478 if (tp->d_npartitions > OLDMAXPARTITIONS) 479 return ENOTTY; 480 memcpy(data, tp, sizeof (struct olddisklabel)); 481 } 482 #endif 483 break; 484 485 case DIOCAWEDGE: 486 { 487 struct dkwedge_info *dkw = (void *) data; 488 489 if ((flag & FWRITE) == 0) 490 return (EBADF); 491 492 /* If the ioctl happens here, the parent is us. */ 493 strlcpy(dkw->dkw_parent, device_xname(ra->ra_dev), 494 sizeof(dkw->dkw_parent)); 495 return (dkwedge_add(dkw)); 496 } 497 498 case DIOCDWEDGE: 499 { 500 struct dkwedge_info *dkw = (void *) data; 501 502 if ((flag & FWRITE) == 0) 503 return (EBADF); 504 505 /* If the ioctl happens here, the parent is us. */ 506 strlcpy(dkw->dkw_parent, device_xname(ra->ra_dev), 507 sizeof(dkw->dkw_parent)); 508 return (dkwedge_del(dkw)); 509 } 510 511 case DIOCLWEDGES: 512 { 513 struct dkwedge_list *dkwl = (void *) data; 514 515 return (dkwedge_list(&ra->ra_disk, dkwl, l)); 516 } 517 518 default: 519 error = ENOTTY; 520 break; 521 } 522 return (error); 523 } 524 525 int 526 radump(dev_t dev, daddr_t blkno, void *va, size_t size) 527 { 528 return ENXIO; 529 } 530 531 /* 532 * Return the size of a partition, if known, or -1 if not. 533 */ 534 int 535 rasize(dev_t dev) 536 { 537 struct ra_softc *ra = mscp_device_lookup(dev); 538 539 if (!ra) 540 return -1; 541 542 if (ra->ra_state == DK_CLOSED) 543 if (ra_putonline(dev, ra) == MSCP_FAILED) 544 return -1; 545 546 return ra->ra_disk.dk_label->d_partitions[DISKPART(dev)].p_size * 547 (ra->ra_disk.dk_label->d_secsize / DEV_BSIZE); 548 } 549 550 #endif /* NRA || NRACD || NRX */ 551 552 #if NRX 553 554 int rxmatch(device_t, cfdata_t, void *); 555 556 CFATTACH_DECL_NEW(rx, sizeof(struct rx_softc), 557 rxmatch, raattach, NULL, NULL); 558 559 dev_type_open(rxopen); 560 dev_type_read(rxread); 561 dev_type_write(rxwrite); 562 dev_type_ioctl(rxioctl); 563 dev_type_strategy(rxstrategy); 564 dev_type_dump(radump); 565 dev_type_size(rxsize); 566 567 const struct bdevsw rx_bdevsw = { 568 rxopen, nullclose, rxstrategy, rxioctl, radump, rxsize, D_DISK 569 }; 570 571 const struct cdevsw rx_cdevsw = { 572 rxopen, nullclose, rxread, rxwrite, rxioctl, 573 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 574 }; 575 576 static struct dkdriver rxdkdriver = { 577 rxstrategy, minphys 578 }; 579 580 /* 581 * More driver definitions, for generic MSCP code. 582 */ 583 584 int 585 rxmatch(device_t parent, cfdata_t cf, void *aux) 586 { 587 struct drive_attach_args *da = aux; 588 struct mscp *mp = da->da_mp; 589 590 if ((da->da_typ & MSCPBUS_DISK) == 0) 591 return 0; 592 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT && 593 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit) 594 return 0; 595 /* 596 * Check if this disk is a floppy (RX) 597 * Seems to be a safe way to test it per Chris Torek. 598 */ 599 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@') 600 return 1; 601 return 0; 602 } 603 604 #endif /* NRX */ 605 606 #if NRACD 607 608 /* Use almost all ra* routines for racd */ 609 610 int racdmatch(device_t, cfdata_t, void *); 611 612 CFATTACH_DECL_NEW(racd, sizeof(struct racd_softc), 613 racdmatch, raattach, NULL, NULL); 614 615 dev_type_open(raopen); 616 dev_type_read(raread); 617 dev_type_write(rawrite); 618 dev_type_ioctl(raioctl); 619 dev_type_strategy(rastrategy); 620 dev_type_dump(radump); 621 dev_type_size(rasize); 622 623 const struct bdevsw racd_bdevsw = { 624 raopen, nullclose, rastrategy, raioctl, radump, rasize, D_DISK 625 }; 626 627 const struct cdevsw racd_cdevsw = { 628 raopen, nullclose, raread, rawrite, raioctl, 629 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 630 }; 631 632 static struct dkdriver racddkdriver = { 633 rastrategy, minphys 634 }; 635 636 /* 637 * More driver definitions, for generic MSCP code. 638 */ 639 640 int 641 racdmatch(device_t parent, cfdata_t cf, void *aux) 642 { 643 struct drive_attach_args *da = aux; 644 struct mscp *mp = da->da_mp; 645 646 if ((da->da_typ & MSCPBUS_DISK) == 0) 647 return 0; 648 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT && 649 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit) 650 return 0; 651 /* 652 * Check if this disk is a CD (RRD) 653 */ 654 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'R' - '@') 655 return 1; 656 return 0; 657 } 658 659 #endif /* NRACD */ 660 661 /* 662 * The attach routine only checks and prints drive type. 663 * Bringing the disk online is done when the disk is accessed 664 * the first time. 665 */ 666 void 667 raattach(device_t parent, device_t self, void *aux) 668 { 669 struct rx_softc *rx = device_private(self); 670 struct drive_attach_args *da = aux; 671 struct mscp *mp = da->da_mp; 672 struct mscp_softc *mi = device_private(parent); 673 struct disklabel *dl; 674 675 rx->ra_dev = self; 676 rx->ra_mediaid = mp->mscp_guse.guse_mediaid; 677 rx->ra_state = DK_CLOSED; 678 rx->ra_hwunit = mp->mscp_unit; 679 mi->mi_dp[mp->mscp_unit] = self; 680 681 #if NRX 682 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@') 683 disk_init((struct disk *)&rx->ra_disk, device_xname(rx->ra_dev), 684 &rxdkdriver); 685 #endif 686 #if NRACD 687 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'R' - '@') 688 disk_init((struct disk *)&rx->ra_disk, device_xname(rx->ra_dev), 689 &racddkdriver); 690 #endif 691 #if NRA 692 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'X' - '@' && 693 MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'R' - '@') 694 disk_init((struct disk *)&rx->ra_disk, device_xname(rx->ra_dev), 695 &radkdriver); 696 #endif 697 disk_attach(&rx->ra_disk); 698 699 /* Fill in what we know. The actual size is gotten later */ 700 dl = rx->ra_disk.dk_label; 701 702 dl->d_secsize = DEV_BSIZE; 703 dl->d_nsectors = mp->mscp_guse.guse_nspt; 704 dl->d_ntracks = mp->mscp_guse.guse_ngpc * mp->mscp_guse.guse_group; 705 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks; 706 disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid); 707 #ifdef DEBUG 708 printf("%s: nspt %d group %d ngpc %d rct %d nrpt %d nrct %d\n", 709 device_xname(self), mp->mscp_guse.guse_nspt, mp->mscp_guse.guse_group, 710 mp->mscp_guse.guse_ngpc, mp->mscp_guse.guse_rctsize, 711 mp->mscp_guse.guse_nrpt, mp->mscp_guse.guse_nrct); 712 #endif 713 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'X' - '@') { 714 /* 715 * XXX We should try to discover wedges here, but 716 * XXX that would mean being able to do I/O. Should 717 * XXX use config_defer() here. 718 */ 719 } 720 } 721 722 /* 723 * (Try to) put the drive online. This is done the first time the 724 * drive is opened, or if it har fallen offline. 725 */ 726 int 727 rx_putonline(struct rx_softc *rx) 728 { 729 struct mscp *mp; 730 struct mscp_softc *mi = device_private(device_parent(rx->ra_dev)); 731 volatile int i; 732 733 rx->ra_state = DK_CLOSED; 734 mp = mscp_getcp(mi, MSCP_WAIT); 735 mp->mscp_opcode = M_OP_ONLINE; 736 mp->mscp_unit = rx->ra_hwunit; 737 mp->mscp_cmdref = 1; 738 *mp->mscp_addr |= MSCP_OWN | MSCP_INT; 739 740 /* Poll away */ 741 i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0); 742 if (tsleep(&rx->ra_state, PRIBIO, "rxonline", 100*100)) 743 rx->ra_state = DK_CLOSED; 744 745 if (rx->ra_state == DK_CLOSED) 746 return MSCP_FAILED; 747 748 return MSCP_DONE; 749 } 750 751 #if NRX 752 753 /* 754 * Open a drive. 755 */ 756 /*ARGSUSED*/ 757 int 758 rxopen(dev_t dev, int flag, int fmt, struct lwp *l) 759 { 760 struct rx_softc *rx; 761 int unit; 762 763 /* 764 * Make sure this is a reasonable open request. 765 */ 766 unit = DISKUNIT(dev); 767 rx = device_lookup_private(&rx_cd, unit); 768 if (!rx) 769 return ENXIO; 770 771 /* 772 * If this is the first open; we must first try to put 773 * the disk online (and read the label). 774 */ 775 if (rx->ra_state == DK_CLOSED) 776 if (rx_putonline(rx) == MSCP_FAILED) 777 return ENXIO; 778 779 return 0; 780 } 781 782 /* 783 * Queue a transfer request, and if possible, hand it to the controller. 784 * 785 * This routine is broken into two so that the internal version 786 * udastrat1() can be called by the (nonexistent, as yet) bad block 787 * revectoring routine. 788 */ 789 void 790 rxstrategy(struct buf *bp) 791 { 792 int unit; 793 struct rx_softc *rx; 794 int b; 795 796 /* 797 * Make sure this is a reasonable drive to use. 798 */ 799 unit = DISKUNIT(bp->b_dev); 800 if ((rx = device_lookup_private(&rx_cd, unit)) == NULL) { 801 bp->b_error = ENXIO; 802 goto done; 803 } 804 805 /* If disk is not online, try to put it online */ 806 if (rx->ra_state == DK_CLOSED) 807 if (rx_putonline(rx) == MSCP_FAILED) { 808 bp->b_error = EIO; 809 goto done; 810 } 811 812 /* 813 * Determine the size of the transfer, and make sure it is 814 * within the boundaries of the partition. 815 */ 816 if (bp->b_blkno >= rx->ra_disk.dk_label->d_secperunit) { 817 bp->b_resid = bp->b_bcount; 818 goto done; 819 } 820 821 /* Make some statistics... /bqt */ 822 b = splbio(); 823 disk_busy(&rx->ra_disk); 824 splx(b); 825 mscp_strategy(bp, device_parent(rx->ra_dev)); 826 return; 827 828 done: 829 biodone(bp); 830 } 831 832 int 833 rxread(dev_t dev, struct uio *uio, int flag) 834 { 835 836 return (physio(rxstrategy, NULL, dev, B_READ, minphys, uio)); 837 } 838 839 int 840 rxwrite(dev_t dev, struct uio *uio, int flag) 841 { 842 843 return (physio(rxstrategy, NULL, dev, B_WRITE, minphys, uio)); 844 } 845 846 /* 847 * I/O controls. 848 */ 849 int 850 rxioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 851 { 852 int unit = DISKUNIT(dev); 853 struct disklabel *lp; 854 struct rx_softc *rx = device_lookup_private(&rx_cd, unit); 855 int error = 0; 856 857 lp = rx->ra_disk.dk_label; 858 859 switch (cmd) { 860 861 case DIOCGDINFO: 862 memcpy(data, lp, sizeof (struct disklabel)); 863 break; 864 865 case DIOCGPART: 866 ((struct partinfo *)data)->disklab = lp; 867 ((struct partinfo *)data)->part = 868 &lp->d_partitions[DISKPART(dev)]; 869 break; 870 871 872 case DIOCWDINFO: 873 case DIOCSDINFO: 874 case DIOCWLABEL: 875 break; 876 877 default: 878 error = ENOTTY; 879 break; 880 } 881 return (error); 882 } 883 884 int 885 rxsize(dev_t dev) 886 { 887 888 return -1; 889 } 890 891 #endif /* NRX */ 892 893 void rrdgram(device_t, struct mscp *, struct mscp_softc *); 894 void rriodone(device_t, struct buf *); 895 int rronline(device_t, struct mscp *); 896 int rrgotstatus(device_t, struct mscp *); 897 void rrreplace(device_t, struct mscp *); 898 int rrioerror(device_t, struct mscp *, struct buf *); 899 void rrfillin(struct buf *, struct mscp *); 900 void rrbb(device_t, struct mscp *, struct buf *); 901 902 903 struct mscp_device ra_device = { 904 rrdgram, 905 rriodone, 906 rronline, 907 rrgotstatus, 908 rrreplace, 909 rrioerror, 910 rrbb, 911 rrfillin, 912 }; 913 914 /* 915 * Handle an error datagram. 916 * This can come from an unconfigured drive as well. 917 */ 918 void 919 rrdgram(device_t usc, struct mscp *mp, struct mscp_softc *mi) 920 { 921 if (mscp_decodeerror(usc == NULL?"unconf disk" : device_xname(usc), mp, mi)) 922 return; 923 /* 924 * SDI status information bytes 10 and 11 are the microprocessor 925 * error code and front panel code respectively. These vary per 926 * drive type and are printed purely for field service information. 927 */ 928 if (mp->mscp_format == M_FM_SDI) 929 printf("\tsdi uproc error code 0x%x, front panel code 0x%x\n", 930 mp->mscp_erd.erd_sdistat[10], 931 mp->mscp_erd.erd_sdistat[11]); 932 } 933 934 935 void 936 rriodone(device_t usc, struct buf *bp) 937 { 938 struct ra_softc *ra = device_private(usc); 939 940 disk_unbusy(&ra->ra_disk, bp->b_bcount, (bp->b_flags & B_READ)); 941 942 biodone(bp); 943 } 944 945 /* 946 * A drive came on line. Check its type and size. Return DONE if 947 * we think the drive is truly on line. In any case, awaken anyone 948 * sleeping on the drive on-line-ness. 949 */ 950 int 951 rronline(device_t usc, struct mscp *mp) 952 { 953 struct ra_softc *ra = device_private(usc); 954 struct disklabel *dl; 955 956 wakeup((void *)&ra->ra_state); 957 if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) { 958 aprint_error_dev(usc, "attempt to bring on line failed: "); 959 mscp_printevent(mp); 960 return (MSCP_FAILED); 961 } 962 963 ra->ra_state = DK_OPEN; 964 965 dl = ra->ra_disk.dk_label; 966 dl->d_secperunit = (daddr_t)mp->mscp_onle.onle_unitsize; 967 968 if (dl->d_secpercyl) { 969 dl->d_ncylinders = dl->d_secperunit/dl->d_secpercyl; 970 dl->d_type = DTYPE_MSCP; 971 dl->d_rpm = 3600; 972 } else { 973 dl->d_type = DTYPE_FLOPPY; 974 dl->d_rpm = 300; 975 } 976 rrmakelabel(dl, ra->ra_mediaid); 977 978 return (MSCP_DONE); 979 } 980 981 void 982 rrmakelabel(struct disklabel *dl, long type) 983 { 984 int n, p = 0; 985 986 dl->d_bbsize = BBSIZE; 987 dl->d_sbsize = SBLOCKSIZE; 988 989 /* Create the disk name for disklabel. Phew... */ 990 dl->d_typename[p++] = MSCP_MID_CHAR(2, type); 991 dl->d_typename[p++] = MSCP_MID_CHAR(1, type); 992 if (MSCP_MID_ECH(0, type)) 993 dl->d_typename[p++] = MSCP_MID_CHAR(0, type); 994 n = MSCP_MID_NUM(type); 995 if (n > 99) { 996 dl->d_typename[p++] = '1'; 997 n -= 100; 998 } 999 if (n > 9) { 1000 dl->d_typename[p++] = (n / 10) + '0'; 1001 n %= 10; 1002 } 1003 dl->d_typename[p++] = n + '0'; 1004 dl->d_typename[p] = 0; 1005 dl->d_npartitions = MAXPARTITIONS; 1006 dl->d_partitions[0].p_size = dl->d_partitions[2].p_size = 1007 dl->d_secperunit; 1008 dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0; 1009 dl->d_interleave = dl->d_headswitch = 1; 1010 dl->d_magic = dl->d_magic2 = DISKMAGIC; 1011 dl->d_checksum = dkcksum(dl); 1012 } 1013 1014 /* 1015 * We got some (configured) unit's status. Return DONE if it succeeded. 1016 */ 1017 int 1018 rrgotstatus(device_t usc, struct mscp *mp) 1019 { 1020 if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) { 1021 aprint_error_dev(usc, "attempt to get status failed: "); 1022 mscp_printevent(mp); 1023 return (MSCP_FAILED); 1024 } 1025 /* record for (future) bad block forwarding and whatever else */ 1026 #ifdef notyet 1027 uda_rasave(ui->ui_unit, mp, 1); 1028 #endif 1029 return (MSCP_DONE); 1030 } 1031 1032 /* 1033 * A replace operation finished. 1034 */ 1035 /*ARGSUSED*/ 1036 void 1037 rrreplace(device_t usc, struct mscp *mp) 1038 { 1039 1040 panic("udareplace"); 1041 } 1042 1043 /* 1044 * A transfer failed. We get a chance to fix or restart it. 1045 * Need to write the bad block forwaring code first.... 1046 */ 1047 /*ARGSUSED*/ 1048 int 1049 rrioerror(device_t usc, struct mscp *mp, struct buf *bp) 1050 { 1051 struct ra_softc *ra = device_private(usc); 1052 int code = mp->mscp_event; 1053 1054 switch (code & M_ST_MASK) { 1055 /* The unit has fallen offline. Try to figure out why. */ 1056 case M_ST_OFFLINE: 1057 bp->b_error = EIO; 1058 ra->ra_state = DK_CLOSED; 1059 if (code & M_OFFLINE_UNMOUNTED) 1060 aprint_error_dev(usc, "not mounted/spun down\n"); 1061 if (code & M_OFFLINE_DUPLICATE) 1062 aprint_error_dev(usc, "duplicate unit number!!!\n"); 1063 return MSCP_DONE; 1064 1065 case M_ST_AVAILABLE: 1066 ra->ra_state = DK_CLOSED; /* Force another online */ 1067 return MSCP_DONE; 1068 1069 default: 1070 printf("%s:", device_xname(usc)); 1071 break; 1072 } 1073 return (MSCP_FAILED); 1074 } 1075 1076 /* 1077 * Fill in disk addresses in a mscp packet waiting for transfer. 1078 */ 1079 void 1080 rrfillin(struct buf *bp, struct mscp *mp) 1081 { 1082 struct ra_softc *ra; 1083 struct disklabel *lp; 1084 int part = DISKPART(bp->b_dev); 1085 1086 ra = mscp_device_lookup(bp->b_dev); 1087 lp = ra->ra_disk.dk_label; 1088 1089 mp->mscp_seq.seq_lbn = lp->d_partitions[part].p_offset + bp->b_blkno; 1090 mp->mscp_unit = ra->ra_hwunit; 1091 mp->mscp_seq.seq_bytecount = bp->b_bcount; 1092 } 1093 1094 /* 1095 * A bad block related operation finished. 1096 */ 1097 /*ARGSUSED*/ 1098 void 1099 rrbb(device_t usc, struct mscp *mp, struct buf *bp) 1100 { 1101 1102 panic("udabb"); 1103 } 1104 1105 /* 1106 * (Try to) put the drive online. This is done the first time the 1107 * drive is opened, or if it has fallen offline. 1108 */ 1109 int 1110 ra_putonline(dev_t dev, struct ra_softc *ra) 1111 { 1112 struct disklabel *dl; 1113 const char *msg; 1114 1115 if (rx_putonline(ra) != MSCP_DONE) 1116 return MSCP_FAILED; 1117 1118 dl = ra->ra_disk.dk_label; 1119 1120 ra->ra_state = DK_RDLABEL; 1121 printf("%s", device_xname(ra->ra_dev)); 1122 if ((msg = readdisklabel( 1123 MAKEDISKDEV(major(dev), device_unit(ra->ra_dev), RAW_PART), 1124 rastrategy, dl, NULL)) == NULL) { 1125 ra->ra_havelabel = 1; 1126 ra->ra_state = DK_OPEN; 1127 } 1128 #if NRACD 1129 else if (cdevsw_lookup(dev) == &racd_cdevsw) { 1130 dl->d_partitions[0].p_offset = 0; 1131 dl->d_partitions[0].p_size = dl->d_secperunit; 1132 dl->d_partitions[0].p_fstype = FS_ISO9660; 1133 } 1134 #endif /* NRACD */ 1135 else { 1136 printf(": %s", msg); 1137 } 1138 1139 printf(": size %d sectors\n", dl->d_secperunit); 1140 1141 return MSCP_DONE; 1142 } 1143 1144 1145 static inline struct ra_softc * 1146 mscp_device_lookup(dev_t dev) 1147 { 1148 struct ra_softc *ra; 1149 int unit; 1150 1151 unit = DISKUNIT(dev); 1152 #if NRA 1153 if (cdevsw_lookup(dev) == &ra_cdevsw) 1154 ra = device_lookup_private(&ra_cd, unit); 1155 else 1156 #endif 1157 #if NRACD 1158 if (cdevsw_lookup(dev) == &racd_cdevsw) 1159 ra = device_lookup_private(&racd_cd, unit); 1160 else 1161 #endif 1162 #if NRX 1163 if (cdevsw_lookup(dev) == &rx_cdevsw) 1164 ra = device_lookup_private(&rx_cd, unit); 1165 else 1166 #endif 1167 panic("mscp_device_lookup: unexpected major %"PRIu32" unit %u", 1168 major(dev), unit); 1169 return ra; 1170 } 1171