|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1990 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * This code is derived from software contributed to Berkeley by ! 6: * Van Jacobson of Lawrence Berkeley Laboratory. ! 7: * ! 8: * Redistribution and use in source and binary forms, with or without ! 9: * modification, are permitted provided that the following conditions ! 10: * are met: ! 11: * 1. Redistributions of source code must retain the above copyright ! 12: * notice, this list of conditions and the following disclaimer. ! 13: * 2. Redistributions in binary form must reproduce the above copyright ! 14: * notice, this list of conditions and the following disclaimer in the ! 15: * documentation and/or other materials provided with the distribution. ! 16: * 3. All advertising materials mentioning features or use of this software ! 17: * must display the following acknowledgement: ! 18: * This product includes software developed by the University of ! 19: * California, Berkeley and its contributors. ! 20: * 4. Neither the name of the University nor the names of its contributors ! 21: * may be used to endorse or promote products derived from this software ! 22: * without specific prior written permission. ! 23: * ! 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 34: * SUCH DAMAGE. ! 35: * ! 36: * @(#)sd.c 7.8 (Berkeley) 6/9/91 ! 37: */ ! 38: ! 39: /* ! 40: * SCSI CCS (Command Command Set) disk driver. ! 41: */ ! 42: #include "sd.h" ! 43: #if NSD > 0 ! 44: ! 45: #ifndef lint ! 46: static char rcsid[] = "/b/source/CVS/src/sys/arch/amiga/dev/sd.c,v 1.1.1.1 1993/07/05 19:19:47 mw Exp"; ! 47: #endif ! 48: ! 49: #include "sys/param.h" ! 50: #include "sys/systm.h" ! 51: #include "sys/buf.h" ! 52: #include "sys/dkstat.h" ! 53: #include "sys/disklabel.h" ! 54: #include "sys/malloc.h" ! 55: #include "sys/proc.h" ! 56: #include "sys/reboot.h" ! 57: #include "sys/file.h" ! 58: ! 59: #include "device.h" ! 60: #include "scsireg.h" ! 61: #include "vm/vm_param.h" ! 62: #include "vm/lock.h" ! 63: #include "vm/vm_statistics.h" ! 64: #include "vm/pmap.h" ! 65: #include "vm/vm_prot.h" ! 66: ! 67: #include "rdb.h" ! 68: ! 69: struct sd_softc; ! 70: ! 71: extern int sdinit (register struct amiga_device *ad); ! 72: extern void sdreset (register struct sd_softc *sc, register struct amiga_device *ad); ! 73: extern int sdopen (dev_t dev, int flags, int mode, struct proc *p); ! 74: extern void sdstrategy (register struct buf *bp); ! 75: extern void sdustart (register int unit); ! 76: extern void sdstart (register int unit); ! 77: extern void sdgo (register int unit); ! 78: extern void sdintr (register int unit, int stat); ! 79: extern int sdioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p); ! 80: extern int sdsize (dev_t dev); ! 81: extern int sddump (dev_t dev); ! 82: static int sdident (struct sd_softc *sc, struct amiga_device *ad); ! 83: static void sdlblkstrat (register struct buf *bp, register int bsize); ! 84: static int sderror (int unit, register struct sd_softc *sc, register struct amiga_device *am, int stat); ! 85: static void sdfinish (int unit, register struct sd_softc *sc, register struct buf *bp); ! 86: ! 87: extern void disksort(); ! 88: extern int physio(); ! 89: extern void TBIS(); ! 90: ! 91: int sdinit(); ! 92: void sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr(); ! 93: ! 94: struct driver sddriver = { ! 95: sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr, 0, ! 96: }; ! 97: ! 98: #if 0 ! 99: struct size { ! 100: u_long strtblk; ! 101: u_long endblk; ! 102: int nblocks; ! 103: }; ! 104: ! 105: struct sdinfo { ! 106: u_int cylinders; /* number of driver cylinders RDB value */ ! 107: u_int sectors; /* sectors per track RDB value */ ! 108: u_int heads; /* number of drive heads RDB value */ ! 109: u_int cylblocks; /* available number of blocks per cyl RDB value */ ! 110: struct size part[8]; ! 111: }; ! 112: ! 113: /* ! 114: * since the SCSI standard tends to hide the disk structure, we define ! 115: * partitions in terms of DEV_BSIZE blocks. The default partition table ! 116: * (for an unlabeled disk) reserves 512K for a boot area, has an 8 meg ! 117: * root and 32 meg of swap. The rest of the space on the drive goes in ! 118: * the G partition. As usual, the C partition covers the entire disk ! 119: * (including the boot area). ! 120: */ ! 121: struct sdinfo sddefaultpart = { ! 122: 1024, 17408, 16384 , /* A */ ! 123: 17408, 82944, 65536 , /* B */ ! 124: 0, 0, 0 , /* C */ ! 125: 17408, 115712, 98304 , /* D */ ! 126: 115712, 218112, 102400 , /* E */ ! 127: 218112, 0, 0 , /* F */ ! 128: 82944, 0, 0 , /* G */ ! 129: 115712, 0, 0 , /* H */ ! 130: }; ! 131: #endif ! 132: ! 133: struct sd_softc { ! 134: struct amiga_device *sc_ad; ! 135: struct devqueue sc_dq; ! 136: int sc_format_pid; /* process using "format" mode */ ! 137: short sc_flags; ! 138: short sc_type; /* drive type */ ! 139: short sc_punit; /* physical unit (scsi lun) */ ! 140: u_short sc_bshift; /* convert device blocks to DEV_BSIZE blks */ ! 141: u_int sc_blks; /* number of blocks on device */ ! 142: int sc_blksize; /* device block size in bytes */ ! 143: u_int sc_wpms; /* average xfer rate in 16 bit wds/sec. */ ! 144: char sc_idstr[32]; /* XXX */ ! 145: struct disklabel sc_label; /* drive partition table & label info */ ! 146: int sc_have_label; ! 147: int sc_write_label; ! 148: } sd_softc[NSD]; ! 149: ! 150: /* sc_flags values */ ! 151: #define SDF_ALIVE 0x1 ! 152: ! 153: #ifdef DEBUG ! 154: int sddebug = 0; ! 155: #define SDB_ERROR 0x01 ! 156: #define SDB_PARTIAL 0x02 ! 157: /*#define QUASEL*/ ! 158: #endif ! 159: ! 160: #ifdef QUASEL ! 161: #define QPRINTF(a) printf a ! 162: #else ! 163: #define QPRINTF(a) ! 164: #endif ! 165: ! 166: struct sdstats { ! 167: long sdresets; ! 168: long sdtransfers; ! 169: long sdpartials; ! 170: } sdstats[NSD]; ! 171: ! 172: struct buf sdtab[NSD]; ! 173: struct scsi_fmt_cdb sdcmd[NSD]; ! 174: struct scsi_fmt_sense sdsense[NSD]; ! 175: ! 176: static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT }; ! 177: static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT }; ! 178: ! 179: #define sdunit(x) (minor(x) >> 3) ! 180: #define sdpart(x) (minor(x) & 0x7) ! 181: #define sdpunit(x) ((x) & 7) ! 182: #define b_cylin b_resid ! 183: ! 184: #define SDRETRY 2 ! 185: ! 186: /* ! 187: * Table of scsi commands users are allowed to access via "format" ! 188: * mode. 0 means not legal. 1 means "immediate" (doesn't need dma). ! 189: * -1 means needs dma and/or wait for intr. ! 190: */ ! 191: static char legal_cmds[256] = { ! 192: /***** 0 1 2 3 4 5 6 7 8 9 A B C D E F */ ! 193: /*00*/ 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 194: /*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, ! 195: /*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 196: /*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 197: /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 198: /*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 199: /*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 200: /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 201: /*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 202: /*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 203: /*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 204: /*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 205: /*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 206: /*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 207: /*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 208: /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ! 209: }; ! 210: ! 211: static struct scsi_inquiry inqbuf; ! 212: static struct scsi_fmt_cdb inq = { ! 213: 6, ! 214: CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 ! 215: }; ! 216: ! 217: static u_char capbuf[8]; ! 218: struct scsi_fmt_cdb cap = { ! 219: 10, ! 220: CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 ! 221: }; ! 222: ! 223: static int ! 224: sdident(sc, ad) ! 225: struct sd_softc *sc; ! 226: struct amiga_device *ad; ! 227: { ! 228: int unit; ! 229: register int ctlr, slave; ! 230: register int i; ! 231: register int tries = 10; ! 232: int ismo = 0; ! 233: ! 234: ctlr = ad->amiga_ctlr; ! 235: slave = ad->amiga_slave; ! 236: unit = sc->sc_punit; ! 237: scsi_delay(-1); ! 238: ! 239: /* ! 240: * See if unit exists and is a disk then read block size & nblocks. ! 241: */ ! 242: while ((i = scsi_test_unit_rdy(slave)) != 0) { ! 243: retry_TUR: ! 244: if (i == -1 || --tries < 0) { ! 245: if (ismo) ! 246: break; ! 247: /* doesn't exist or not a CCS device */ ! 248: goto failed; ! 249: } ! 250: if (i == STS_CHECKCOND) { ! 251: u_char sensebuf[128]; ! 252: struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf; ! 253: ! 254: i = scsi_request_sense(slave, sensebuf, sizeof(sensebuf)); ! 255: if (sp->class == 7) ! 256: switch (sp->key) { ! 257: /* not ready -- might be MO with no media */ ! 258: case 2: ! 259: if (sp->len == 12 && ! 260: sensebuf[12] == 10) /* XXX */ ! 261: ismo = 1; ! 262: break; ! 263: /* drive doing an RTZ -- give it a while */ ! 264: case 6: ! 265: DELAY(1000000); ! 266: break; ! 267: default: ! 268: break; ! 269: } ! 270: } ! 271: DELAY(1000); ! 272: } ! 273: /* ! 274: * Find out about device ! 275: */ ! 276: if (i = scsi_immed_command(slave, &inq, (u_char *)&inqbuf, sizeof(inqbuf), B_READ)) ! 277: { ! 278: if (i == STS_CHECKCOND) ! 279: goto retry_TUR; ! 280: goto failed; ! 281: } ! 282: switch (inqbuf.type) { ! 283: case 0: /* disk */ ! 284: case 4: /* WORM */ ! 285: case 5: /* CD-ROM */ ! 286: case 7: /* Magneto-optical */ ! 287: break; ! 288: default: /* not a disk */ ! 289: if (sddebug) ! 290: printf ("Unit %d unknown scsi-type: %d\n", slave, inqbuf.type); ! 291: goto failed; ! 292: } ! 293: /* ! 294: * Get a usable id string ! 295: */ ! 296: if (inqbuf.version < 1) { ! 297: bcopy("UNKNOWN", &sc->sc_idstr[0], 8); ! 298: bcopy("DRIVE TYPE", &sc->sc_idstr[8], 11); ! 299: } else { ! 300: bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)sc->sc_idstr, 28); ! 301: for (i = 27; i > 23; --i) ! 302: if (sc->sc_idstr[i] != ' ') ! 303: break; ! 304: sc->sc_idstr[i+1] = 0; ! 305: for (i = 23; i > 7; --i) ! 306: if (sc->sc_idstr[i] != ' ') ! 307: break; ! 308: sc->sc_idstr[i+1] = 0; ! 309: for (i = 7; i >= 0; --i) ! 310: if (sc->sc_idstr[i] != ' ') ! 311: break; ! 312: sc->sc_idstr[i+1] = 0; ! 313: } ! 314: i = scsi_immed_command(slave, &cap, (u_char *)&capbuf, sizeof(capbuf), B_READ); ! 315: if (i) { ! 316: if (i != STS_CHECKCOND || ! 317: bcmp(&sc->sc_idstr[0], "HP", 3) || ! 318: bcmp(&sc->sc_idstr[8], "S6300.650A", 11)) ! 319: goto failed; ! 320: /* XXX unformatted or non-existant MO media; fake it */ ! 321: sc->sc_blks = 318664; ! 322: sc->sc_blksize = 1024; ! 323: } else { ! 324: sc->sc_blks = *(u_int *)&capbuf[0]; ! 325: sc->sc_blksize = *(int *)&capbuf[4]; ! 326: } ! 327: /* return value of read capacity is last valid block number */ ! 328: sc->sc_blks++; ! 329: ! 330: if (inqbuf.version < 1) ! 331: printf("sd%d: type 0x%x, qual 0x%x, ver %d", ad->amiga_unit, ! 332: inqbuf.type, inqbuf.qual, inqbuf.version); ! 333: else ! 334: printf("sd%d: %s %s rev %s", ad->amiga_unit, sc->sc_idstr, &sc->sc_idstr[8], ! 335: &sc->sc_idstr[24]); ! 336: printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize); ! 337: if (sc->sc_blksize != DEV_BSIZE) { ! 338: if (sc->sc_blksize < DEV_BSIZE) { ! 339: printf("sd%d: need %d byte blocks - drive ignored\n", ! 340: unit, DEV_BSIZE); ! 341: goto failed; ! 342: } ! 343: for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) ! 344: ++sc->sc_bshift; ! 345: sc->sc_blks <<= sc->sc_bshift; ! 346: } ! 347: sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */ ! 348: scsi_delay(0); ! 349: return(inqbuf.type); ! 350: failed: ! 351: scsi_delay(0); ! 352: return(-1); ! 353: } ! 354: ! 355: int ! 356: sdinit(ad) ! 357: register struct amiga_device *ad; ! 358: { ! 359: register struct sd_softc *sc = &sd_softc[ad->amiga_unit]; ! 360: static u_int block [DEV_BSIZE / 4]; ! 361: struct RigidDiskBlock *rdb = (struct RigidDiskBlock *) block; ! 362: struct PartitionBlock *pb = (struct PartitionBlock *) block; ! 363: int bnum, npbnum, num_bsd_part = 0; ! 364: struct disklabel *dl; ! 365: ! 366: sc->sc_ad = ad; ! 367: sc->sc_punit = sdpunit(ad->amiga_flags); ! 368: sc->sc_type = sdident(sc, ad); ! 369: if (sc->sc_type < 0) ! 370: return(0); ! 371: sc->sc_dq.dq_ctlr = ad->amiga_ctlr; ! 372: sc->sc_dq.dq_unit = ad->amiga_unit; ! 373: sc->sc_dq.dq_slave = ad->amiga_slave; ! 374: sc->sc_dq.dq_driver = &sddriver; ! 375: ! 376: /* read RDB and partition blocks to find out about which partitions ! 377: are ok to be scribbled upon by BSD. This is quite Amiga specific. */ ! 378: ! 379: for (bnum = 0; bnum < RDB_LOCATION_LIMIT; bnum++) ! 380: { ! 381: if (scsi_tt_read (ad->amiga_slave, block, DEV_BSIZE, bnum, sc->sc_bshift)) ! 382: /* read error on block */ ! 383: return 0; ! 384: ! 385: if (rdb->rdb_ID == IDNAME_RIGIDDISK) ! 386: break; ! 387: } ! 388: if (bnum == RDB_LOCATION_LIMIT) ! 389: /* no RDB on this disk */ ! 390: return 0; ! 391: ! 392: /* fill in as much as we can of the disklabel */ ! 393: dl = &sc->sc_label; ! 394: bzero (dl, sizeof (*dl)); ! 395: dl->d_magic = DISKMAGIC; ! 396: dl->d_type = DTYPE_SCSI; ! 397: ! 398: strncpy (dl->d_typename, sc->sc_idstr, sizeof (dl->d_typename) - 1); ! 399: strcpy (dl->d_packname, "some pack"); ! 400: ! 401: /* now for more serious information.. */ ! 402: dl->d_secsize = rdb->rdb_BlockBytes; ! 403: dl->d_nsectors = rdb->rdb_Sectors; ! 404: dl->d_ntracks = rdb->rdb_Heads; ! 405: dl->d_ncylinders = rdb->rdb_Cylinders; ! 406: dl->d_secpercyl = rdb->rdb_CylBlocks; ! 407: dl->d_secperunit = (rdb->rdb_CylBlocks ! 408: * (rdb->rdb_HiCylinder - rdb->rdb_LoCylinder)); ! 409: ! 410: /* makes sense? */ ! 411: dl->d_acylinders = rdb->rdb_Cylinders - (rdb->rdb_HiCylinder - rdb->rdb_LoCylinder); ! 412: ! 413: dl->d_magic2 = DISKMAGIC; ! 414: ! 415: /* ok, go thru the partition blocks, and check for BSD ID's */ ! 416: ! 417: for (npbnum = rdb->rdb_PartitionList; npbnum; ) ! 418: { ! 419: u_int start_block, end_block, nblocks; ! 420: u_int reserved; ! 421: int part; ! 422: ! 423: if (scsi_tt_read (ad->amiga_slave, block, DEV_BSIZE, npbnum, sc->sc_bshift)) ! 424: break; ! 425: ! 426: if (pb->pb_ID != IDNAME_PARTITION) ! 427: break; ! 428: ! 429: /* remember those values, they're destroyed when reading the first ! 430: partition block */ ! 431: npbnum = pb->pb_Next; ! 432: start_block = pb->pb_Environment[DE_LOWCYL] * dl->d_secpercyl; ! 433: reserved = pb->pb_Environment[DE_RESERVEDBLKS]; ! 434: end_block = pb->pb_Environment[DE_UPPERCYL] * dl->d_secpercyl; ! 435: ! 436: part = -1; ! 437: switch (pb->pb_Environment[DE_DOSTYPE]) ! 438: { ! 439: case DOSTYPE_BSD_ROOT: ! 440: if (! dl->d_partitions[0].p_size) ! 441: { ! 442: extern u_long bootdev; ! 443: ! 444: part = 0; ! 445: ! 446: /* Since we don't boot BSD with a standalone-kernel, but ! 447: with a simple boot-loader from AmigaDOS, we fake a ! 448: bootdev by assigning the just computed values of the ! 449: root partition. */ ! 450: ! 451: /* 4: sd major ! 452: 0: adaptor number ! 453: 0: controller number ! 454: ad->amiga_unit: scsi-unit ! 455: part: partition (A) */ ! 456: ! 457: bootdev = MAKEBOOTDEV (4, 0, 0, ad->amiga_unit, part); ! 458: } ! 459: break; ! 460: ! 461: case DOSTYPE_BSD_SWAP: ! 462: if (! dl->d_partitions[1].p_size) ! 463: part = 1; ! 464: break; ! 465: ! 466: case DOSTYPE_BSD_D: ! 467: if (! dl->d_partitions[3].p_size) ! 468: part = 3; ! 469: break; ! 470: ! 471: case DOSTYPE_BSD_E: ! 472: if (! dl->d_partitions[4].p_size) ! 473: part = 4; ! 474: break; ! 475: ! 476: case DOSTYPE_BSD_F: ! 477: if (! dl->d_partitions[5].p_size) ! 478: part = 5; ! 479: break; ! 480: ! 481: case DOSTYPE_BSD_G: ! 482: if (! dl->d_partitions[6].p_size) ! 483: part = 6; ! 484: break; ! 485: ! 486: case DOSTYPE_BSD_H: ! 487: if (! dl->d_partitions[7].p_size) ! 488: part = 7; ! 489: break; ! 490: } ! 491: ! 492: if (part >= 0) ! 493: { ! 494: num_bsd_part++; ! 495: ! 496: dl->d_partitions[part].p_offset = start_block + reserved; ! 497: dl->d_partitions[part].p_size = end_block - start_block - reserved; ! 498: ! 499: /* for now, have this static.. XXX */ ! 500: dl->d_partitions[part].p_fsize = 1024; ! 501: dl->d_partitions[part].p_fstype = part == 1 ? FS_SWAP : FS_BSDFFS; ! 502: dl->d_partitions[part].p_frag = 8; ! 503: dl->d_partitions[part].p_cpg = 0; /* XXX */ ! 504: ! 505: if (sddebug) ! 506: printf ("%c @%d - %d = %d\n", part + 'A', ! 507: start_block, end_block, end_block - start_block - reserved); ! 508: } ! 509: } ! 510: ! 511: dl->d_npartitions = num_bsd_part; ! 512: if (sddebug) ! 513: printf ("total %d BSD-partitions.\n", num_bsd_part); ! 514: ! 515: /* C gets everything */ ! 516: dl->d_partitions[2].p_size = sc->sc_blks; ! 517: ! 518: dl->d_checksum = 0; ! 519: dl->d_checksum = dkcksum (dl); ! 520: ! 521: sc->sc_have_label = 1; ! 522: sc->sc_write_label = 0; ! 523: ! 524: sc->sc_flags = SDF_ALIVE; ! 525: return(1); ! 526: } ! 527: ! 528: void ! 529: sdreset(sc, ad) ! 530: register struct sd_softc *sc; ! 531: register struct amiga_device *ad; ! 532: { ! 533: sdstats[ad->amiga_unit].sdresets++; ! 534: } ! 535: ! 536: int ! 537: sdopen(dev, flags, mode, p) ! 538: dev_t dev; ! 539: int flags, mode; ! 540: struct proc *p; ! 541: { ! 542: register int unit = sdunit(dev); ! 543: register struct sd_softc *sc = &sd_softc[unit]; ! 544: ! 545: if (unit >= NSD) ! 546: return(ENXIO); ! 547: if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag)) ! 548: return(ENXIO); ! 549: ! 550: if (sc->sc_ad->amiga_dk >= 0) ! 551: dk_wpms[sc->sc_ad->amiga_dk] = sc->sc_wpms; ! 552: return(0); ! 553: } ! 554: ! 555: /* ! 556: * This routine is called for partial block transfers and non-aligned ! 557: * transfers (the latter only being possible on devices with a block size ! 558: * larger than DEV_BSIZE). The operation is performed in three steps ! 559: * using a locally allocated buffer: ! 560: * 1. transfer any initial partial block ! 561: * 2. transfer full blocks ! 562: * 3. transfer any final partial block ! 563: */ ! 564: static void ! 565: sdlblkstrat(bp, bsize) ! 566: register struct buf *bp; ! 567: register int bsize; ! 568: { ! 569: register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf), ! 570: M_DEVBUF, M_WAITOK); ! 571: caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); ! 572: register int bn, resid; ! 573: register caddr_t addr; ! 574: ! 575: bzero((caddr_t)cbp, sizeof(*cbp)); ! 576: cbp->b_proc = curproc; /* XXX */ ! 577: cbp->b_dev = bp->b_dev; ! 578: bn = bp->b_blkno; ! 579: resid = bp->b_bcount; ! 580: addr = bp->b_un.b_addr; ! 581: #ifdef DEBUG ! 582: if (sddebug & SDB_PARTIAL) ! 583: printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", ! 584: bp, bp->b_flags, bn, resid, addr); ! 585: #endif ! 586: ! 587: while (resid > 0) { ! 588: register int boff = dbtob(bn) & (bsize - 1); ! 589: register int count; ! 590: ! 591: if (boff || resid < bsize) { ! 592: sdstats[sdunit(bp->b_dev)].sdpartials++; ! 593: count = MIN(resid, bsize - boff); ! 594: cbp->b_flags = B_BUSY | B_PHYS | B_READ; ! 595: cbp->b_blkno = bn - btodb(boff); ! 596: cbp->b_un.b_addr = cbuf; ! 597: cbp->b_bcount = bsize; ! 598: #ifdef DEBUG ! 599: if (sddebug & SDB_PARTIAL) ! 600: printf(" readahead: bn %x cnt %x off %x addr %x\n", ! 601: cbp->b_blkno, count, boff, addr); ! 602: #endif ! 603: sdstrategy(cbp); ! 604: biowait(cbp); ! 605: if (cbp->b_flags & B_ERROR) { ! 606: bp->b_flags |= B_ERROR; ! 607: bp->b_error = cbp->b_error; ! 608: break; ! 609: } ! 610: if (bp->b_flags & B_READ) { ! 611: bcopy(&cbuf[boff], addr, count); ! 612: goto done; ! 613: } ! 614: bcopy(addr, &cbuf[boff], count); ! 615: #ifdef DEBUG ! 616: if (sddebug & SDB_PARTIAL) ! 617: printf(" writeback: bn %x cnt %x off %x addr %x\n", ! 618: cbp->b_blkno, count, boff, addr); ! 619: #endif ! 620: } else { ! 621: count = resid & ~(bsize - 1); ! 622: cbp->b_blkno = bn; ! 623: cbp->b_un.b_addr = addr; ! 624: cbp->b_bcount = count; ! 625: #ifdef DEBUG ! 626: if (sddebug & SDB_PARTIAL) ! 627: printf(" fulltrans: bn %x cnt %x addr %x\n", ! 628: cbp->b_blkno, count, addr); ! 629: #endif ! 630: } ! 631: cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); ! 632: sdstrategy(cbp); ! 633: biowait(cbp); ! 634: if (cbp->b_flags & B_ERROR) { ! 635: bp->b_flags |= B_ERROR; ! 636: bp->b_error = cbp->b_error; ! 637: break; ! 638: } ! 639: done: ! 640: bn += btodb(count); ! 641: resid -= count; ! 642: addr += count; ! 643: #ifdef DEBUG ! 644: if (sddebug & SDB_PARTIAL) ! 645: printf(" done: bn %x resid %x addr %x\n", ! 646: bn, resid, addr); ! 647: #endif ! 648: } ! 649: free(cbuf, M_DEVBUF); ! 650: free(cbp, M_DEVBUF); ! 651: } ! 652: ! 653: void ! 654: sdstrategy(bp) ! 655: register struct buf *bp; ! 656: { ! 657: register int unit = sdunit(bp->b_dev); ! 658: register struct sd_softc *sc = &sd_softc[unit]; ! 659: register struct partition *pinfo = &sc->sc_label.d_partitions[sdpart(bp->b_dev)]; ! 660: register struct buf *dp = &sdtab[unit]; ! 661: register daddr_t bn; ! 662: register int sz, s; ! 663: ! 664: QPRINTF (("sdstrat: unit=%d [s=%d,l=%d], [b=%d,l=%d]\n", unit, ! 665: pinfo->p_offset, pinfo->p_size, bp->b_blkno, bp->b_bcount)); ! 666: ! 667: if (sc->sc_format_pid) { ! 668: if (sc->sc_format_pid != curproc->p_pid) { /* XXX */ ! 669: bp->b_error = EPERM; ! 670: bp->b_flags |= B_ERROR; ! 671: goto done; ! 672: } ! 673: bp->b_cylin = 0; ! 674: } else { ! 675: bn = bp->b_blkno; ! 676: sz = howmany(bp->b_bcount, DEV_BSIZE); ! 677: if (bn < 0 || bn + sz > pinfo->p_size) { ! 678: sz = pinfo->p_size - bn; ! 679: if (sz == 0) { ! 680: bp->b_resid = bp->b_bcount; ! 681: goto done; ! 682: } ! 683: if (sz < 0) { ! 684: bp->b_error = EINVAL; ! 685: bp->b_flags |= B_ERROR; ! 686: goto done; ! 687: } ! 688: bp->b_bcount = dbtob(sz); ! 689: } ! 690: /* ! 691: * Non-aligned or partial-block transfers handled specially. ! 692: */ ! 693: s = sc->sc_blksize - 1; ! 694: if ((dbtob(bn) & s) || (bp->b_bcount & s)) { ! 695: sdlblkstrat(bp, sc->sc_blksize); ! 696: goto done; ! 697: } ! 698: bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift; ! 699: } ! 700: s = splbio(); ! 701: disksort(dp, bp); ! 702: if (dp->b_active == 0) { ! 703: dp->b_active = 1; ! 704: sdustart(unit); ! 705: } ! 706: splx(s); ! 707: return; ! 708: done: ! 709: biodone(bp); ! 710: } ! 711: ! 712: void ! 713: sdustart(unit) ! 714: register int unit; ! 715: { ! 716: if (scsireq(&sd_softc[unit].sc_dq)) ! 717: sdstart(unit); ! 718: } ! 719: ! 720: /* ! 721: * Return: ! 722: * 0 if not really an error ! 723: * <0 if we should do a retry ! 724: * >0 if a fatal error ! 725: */ ! 726: static int ! 727: sderror(unit, sc, am, stat) ! 728: int unit, stat; ! 729: register struct sd_softc *sc; ! 730: register struct amiga_device *am; ! 731: { ! 732: int cond = 1; ! 733: ! 734: sdsense[unit].status = stat; ! 735: if (stat & STS_CHECKCOND) { ! 736: struct scsi_xsense *sp; ! 737: ! 738: scsi_request_sense(am->amiga_slave, ! 739: sdsense[unit].sense, ! 740: sizeof(sdsense[unit].sense)); ! 741: sp = (struct scsi_xsense *)sdsense[unit].sense; ! 742: printf("sd%d: scsi sense class %d, code %d", unit, ! 743: sp->class, sp->code); ! 744: if (sp->class == 7) { ! 745: printf(", key %d", sp->key); ! 746: if (sp->valid) ! 747: printf(", blk %d", *(int *)&sp->info1); ! 748: switch (sp->key) { ! 749: /* no sense, try again */ ! 750: case 0: ! 751: cond = -1; ! 752: break; ! 753: /* recovered error, not a problem */ ! 754: case 1: ! 755: cond = 0; ! 756: break; ! 757: } ! 758: } ! 759: printf("\n"); ! 760: } ! 761: return(cond); ! 762: } ! 763: ! 764: static void ! 765: sdfinish(unit, sc, bp) ! 766: int unit; ! 767: register struct sd_softc *sc; ! 768: register struct buf *bp; ! 769: { ! 770: sdtab[unit].b_errcnt = 0; ! 771: sdtab[unit].b_actf = bp->b_actf; ! 772: bp->b_resid = 0; ! 773: biodone(bp); ! 774: scsifree(&sc->sc_dq); ! 775: if (sdtab[unit].b_actf) ! 776: sdustart(unit); ! 777: else ! 778: sdtab[unit].b_active = 0; ! 779: } ! 780: ! 781: void ! 782: sdstart(unit) ! 783: register int unit; ! 784: { ! 785: register struct sd_softc *sc = &sd_softc[unit]; ! 786: register struct amiga_device *am = sc->sc_ad; ! 787: ! 788: /* ! 789: * we have the SCSI bus -- in format mode, we may or may not need dma ! 790: * so check now. ! 791: */ ! 792: if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) { ! 793: register struct buf *bp = sdtab[unit].b_actf; ! 794: register int sts; ! 795: ! 796: sts = scsi_immed_command(am->amiga_slave, ! 797: &sdcmd[unit], ! 798: bp->b_un.b_addr, bp->b_bcount, ! 799: bp->b_flags & B_READ); ! 800: sdsense[unit].status = sts; ! 801: if (sts & 0xfe) { ! 802: (void) sderror(unit, sc, am, sts); ! 803: bp->b_flags |= B_ERROR; ! 804: bp->b_error = EIO; ! 805: } ! 806: sdfinish(unit, sc, bp); ! 807: ! 808: } else if (scsiustart(am->amiga_ctlr)) ! 809: sdgo(unit); ! 810: } ! 811: ! 812: void ! 813: sdgo(unit) ! 814: register int unit; ! 815: { ! 816: register struct sd_softc *sc = &sd_softc[unit]; ! 817: register struct amiga_device *am = sc->sc_ad; ! 818: register struct buf *bp = sdtab[unit].b_actf; ! 819: register int pad; ! 820: register struct scsi_fmt_cdb *cmd; ! 821: ! 822: /* XXX ? */ ! 823: if (! bp) ! 824: return; ! 825: ! 826: if (sc->sc_format_pid) { ! 827: cmd = &sdcmd[unit]; ! 828: pad = 0; ! 829: } else { ! 830: cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd; ! 831: *(int *)(&cmd->cdb[2]) = bp->b_cylin; ! 832: pad = howmany(bp->b_bcount, sc->sc_blksize); ! 833: *(u_short *)(&cmd->cdb[7]) = pad; ! 834: QPRINTF(("sdgo[%d, %d]: %s @%d >%d\n", ! 835: am->amiga_ctlr, am->amiga_slave, ! 836: bp->b_flags & B_READ ? "R" : "W", ! 837: bp->b_cylin, pad)); ! 838: pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0; ! 839: #ifdef DEBUG ! 840: if (pad) ! 841: printf("sd%d: partial block xfer -- %x bytes\n", ! 842: unit, bp->b_bcount); ! 843: #endif ! 844: sdstats[unit].sdtransfers++; ! 845: } ! 846: if (scsigo(am->amiga_ctlr, am->amiga_slave, bp, cmd, pad) == 0) { ! 847: if (am->amiga_dk >= 0) { ! 848: dk_busy |= 1 << am->amiga_dk; ! 849: ++dk_seek[am->amiga_dk]; ! 850: ++dk_xfer[am->amiga_dk]; ! 851: dk_wds[am->amiga_dk] += bp->b_bcount >> 6; ! 852: } ! 853: return; ! 854: } ! 855: #ifdef DEBUG ! 856: if (sddebug & SDB_ERROR) ! 857: printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n", ! 858: unit, bp->b_flags & B_READ? "read" : "write", ! 859: bp->b_un.b_addr, bp->b_cylin, bp->b_bcount, ! 860: sdtab[unit].b_errcnt); ! 861: #endif ! 862: bp->b_flags |= B_ERROR; ! 863: bp->b_error = EIO; ! 864: sdfinish(unit, sc, bp); ! 865: } ! 866: ! 867: void ! 868: sdintr(unit, stat) ! 869: register int unit; ! 870: int stat; ! 871: { ! 872: register struct sd_softc *sc = &sd_softc[unit]; ! 873: register struct buf *bp = sdtab[unit].b_actf; ! 874: register struct amiga_device *am = sc->sc_ad; ! 875: int cond; ! 876: ! 877: if (bp == NULL) { ! 878: printf("sd%d: bp == NULL\n", unit); ! 879: return; ! 880: } ! 881: if (am->amiga_dk >= 0) ! 882: dk_busy &=~ (1 << am->amiga_dk); ! 883: if (stat) { ! 884: #ifdef DEBUG ! 885: if (sddebug & SDB_ERROR) ! 886: printf("sd%d: sdintr: bad scsi status 0x%x\n", ! 887: unit, stat); ! 888: #endif ! 889: cond = sderror(unit, sc, am, stat); ! 890: if (cond) { ! 891: if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) { ! 892: #ifdef DEBUG ! 893: if (sddebug & SDB_ERROR) ! 894: printf("sd%d: retry #%d\n", ! 895: unit, sdtab[unit].b_errcnt); ! 896: #endif ! 897: sdstart(unit); ! 898: return; ! 899: } ! 900: bp->b_flags |= B_ERROR; ! 901: bp->b_error = EIO; ! 902: } ! 903: } ! 904: sdfinish(unit, sc, bp); ! 905: } ! 906: ! 907: #if 1 ! 908: u_int ! 909: sdminphys (bp) ! 910: struct buf *bp; ! 911: { ! 912: register int unit = sdunit(bp->b_dev); ! 913: register struct sd_softc *sc = &sd_softc[unit]; ! 914: register struct partition *pinfo = &sc->sc_label.d_partitions[sdpart(bp->b_dev)]; ! 915: register daddr_t bn; ! 916: register int sz, s; ! 917: ! 918: /* first restrict by max amount of physio possible */ ! 919: bp->b_bcount = min(MAXPHYS, bp->b_bcount); ! 920: ! 921: /* then restrict by partition size (code replicated from sdstrategy). ! 922: Should minphys() really fiddle around with b_resid and b_flags ??? XXXX */ ! 923: ! 924: bn = bp->b_blkno; ! 925: sz = howmany(bp->b_bcount, DEV_BSIZE); ! 926: if (bn < 0 || bn + sz > pinfo->p_size) ! 927: { ! 928: sz = pinfo->p_size - bn; ! 929: if (sz == 0) ! 930: { ! 931: bp->b_resid = bp->b_bcount; ! 932: goto done; ! 933: } ! 934: if (sz < 0) ! 935: { ! 936: bp->b_error = EINVAL; ! 937: bp->b_flags |= B_ERROR; ! 938: goto done; ! 939: } ! 940: bp->b_bcount = dbtob(sz); ! 941: } ! 942: ! 943: return bp->b_bcount; ! 944: done: ! 945: return 0; ! 946: } ! 947: ! 948: ! 949: int ! 950: sdread(dev, uio, flags) ! 951: dev_t dev; ! 952: struct uio *uio; ! 953: int flags; ! 954: { ! 955: register int unit = sdunit(dev); ! 956: register int pid; ! 957: ! 958: if ((pid = sd_softc[unit].sc_format_pid) && ! 959: pid != uio->uio_procp->p_pid) ! 960: return (EPERM); ! 961: ! 962: return (physio(sdstrategy, NULL, dev, B_READ, sdminphys, uio)); ! 963: } ! 964: ! 965: int ! 966: sdwrite(dev, uio, flags) ! 967: dev_t dev; ! 968: struct uio *uio; ! 969: int flags; ! 970: { ! 971: register int unit = sdunit(dev); ! 972: register int pid; ! 973: ! 974: if ((pid = sd_softc[unit].sc_format_pid) && ! 975: pid != uio->uio_procp->p_pid) ! 976: return (EPERM); ! 977: ! 978: return (physio(sdstrategy, NULL, dev, B_WRITE, sdminphys, uio)); ! 979: } ! 980: #endif ! 981: ! 982: int ! 983: sdioctl(dev, cmd, data, flag, p) ! 984: dev_t dev; ! 985: int cmd; ! 986: caddr_t data; ! 987: int flag; ! 988: struct proc *p; ! 989: { ! 990: register int unit = sdunit(dev); ! 991: register struct sd_softc *sc = &sd_softc[unit]; ! 992: struct disklabel *dl; ! 993: int error; ! 994: ! 995: switch (cmd) { ! 996: default: ! 997: return (EINVAL); ! 998: ! 999: case DIOCGDINFO: ! 1000: *(struct disklabel *)data = sc->sc_label; ! 1001: return 0; ! 1002: ! 1003: case DIOCSDINFO: ! 1004: if ((flag & FWRITE) == 0) ! 1005: return EBADF; ! 1006: ! 1007: dl = (struct disklabel *)data; ! 1008: if (error = setdisklabel(&sc->sc_label, dl, 0, 0)); ! 1009: return error; ! 1010: sc->sc_have_label = 1; ! 1011: return 0; ! 1012: ! 1013: case DIOCWLABEL: ! 1014: if ((flag & FWRITE) == 0) ! 1015: return EBADF; ! 1016: ! 1017: sc->sc_write_label = *(int *)data; ! 1018: return 0; ! 1019: ! 1020: case DIOCWDINFO: ! 1021: if ((flag & FWRITE) == 0) ! 1022: return EBADF; ! 1023: ! 1024: dl = (struct disklabel *)data; ! 1025: ! 1026: if (error = setdisklabel (&sc->sc_label, dl, 0, 0)) ! 1027: return error; ! 1028: ! 1029: sc->sc_have_label = 1; ! 1030: ! 1031: #if 0 ! 1032: old_wlabel = as->wlabel; ! 1033: as->wlabel = 1; ! 1034: error = writedisklabel(dev, asstrategy, &as->label, ! 1035: as->dospart); ! 1036: as->wlabel = old_wlabel; ! 1037: #endif ! 1038: return EINVAL; ! 1039: ! 1040: case SDIOCSFORMAT: ! 1041: /* take this device into or out of "format" mode */ ! 1042: if (suser(p->p_ucred, &p->p_acflag)) ! 1043: return(EPERM); ! 1044: ! 1045: if (*(int *)data) { ! 1046: if (sc->sc_format_pid) ! 1047: return (EPERM); ! 1048: sc->sc_format_pid = p->p_pid; ! 1049: } else ! 1050: sc->sc_format_pid = 0; ! 1051: return (0); ! 1052: ! 1053: case SDIOCGFORMAT: ! 1054: /* find out who has the device in format mode */ ! 1055: *(int *)data = sc->sc_format_pid; ! 1056: return (0); ! 1057: ! 1058: case SDIOCSCSICOMMAND: ! 1059: /* ! 1060: * Save what user gave us as SCSI cdb to use with next ! 1061: * read or write to the char device. ! 1062: */ ! 1063: if (sc->sc_format_pid != p->p_pid) ! 1064: return (EPERM); ! 1065: if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) ! 1066: return (EINVAL); ! 1067: bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0])); ! 1068: return (0); ! 1069: ! 1070: case SDIOCSENSE: ! 1071: /* ! 1072: * return the SCSI sense data saved after the last ! 1073: * operation that completed with "check condition" status. ! 1074: */ ! 1075: bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0])); ! 1076: return (0); ! 1077: ! 1078: } ! 1079: /*NOTREACHED*/ ! 1080: } ! 1081: ! 1082: int ! 1083: sdsize(dev) ! 1084: dev_t dev; ! 1085: { ! 1086: register int unit = sdunit(dev); ! 1087: register struct sd_softc *sc = &sd_softc[unit]; ! 1088: ! 1089: if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) ! 1090: return(-1); ! 1091: return(sc->sc_label.d_partitions[sdpart(dev)].p_size); ! 1092: } ! 1093: ! 1094: /* ! 1095: * Non-interrupt driven, non-dma dump routine. ! 1096: */ ! 1097: int ! 1098: sddump(dev) ! 1099: dev_t dev; ! 1100: { ! 1101: int part = sdpart(dev); ! 1102: int unit = sdunit(dev); ! 1103: register struct sd_softc *sc = &sd_softc[unit]; ! 1104: register struct amiga_device *am = sc->sc_ad; ! 1105: register daddr_t baddr; ! 1106: register int maddr; ! 1107: register int pages, i; ! 1108: int stat; ! 1109: extern int lowram; ! 1110: ! 1111: /* ! 1112: * Hmm... all vax drivers dump maxfree pages which is physmem minus ! 1113: * the message buffer. Is there a reason for not dumping the ! 1114: * message buffer? Savecore expects to read 'dumpsize' pages of ! 1115: * dump, where dumpsys() sets dumpsize to physmem! ! 1116: */ ! 1117: pages = physmem; ! 1118: ! 1119: /* is drive ok? */ ! 1120: if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) ! 1121: return (ENXIO); ! 1122: /* dump parameters in range? */ ! 1123: if (dumplo < 0 || dumplo >= sc->sc_label.d_partitions[part].p_size) ! 1124: return (EINVAL); ! 1125: if (dumplo + ctod(pages) > sc->sc_label.d_partitions[part].p_size) ! 1126: pages = dtoc(sc->sc_label.d_partitions[part].p_size - dumplo); ! 1127: maddr = lowram; ! 1128: baddr = dumplo + sc->sc_label.d_partitions[part].p_offset; ! 1129: /* scsi bus idle? */ ! 1130: if (!scsireq(&sc->sc_dq)) { ! 1131: scsireset(/*am->amiga_ctlr*/); ! 1132: sdreset(sc, sc->sc_ad); ! 1133: printf("[ drive %d reset ] ", unit); ! 1134: } ! 1135: for (i = 0; i < pages; i++) { ! 1136: #define NPGMB (1024*1024/NBPG) ! 1137: /* print out how many Mbs we have dumped */ ! 1138: if (i && (i % NPGMB) == 0) ! 1139: printf("%d ", i / NPGMB); ! 1140: #undef NPBMG ! 1141: pmap_enter(pmap_kernel(), vmmap, maddr, VM_PROT_READ, TRUE); ! 1142: stat = scsi_tt_write(am->amiga_slave, ! 1143: vmmap, NBPG, baddr, sc->sc_bshift); ! 1144: if (stat) { ! 1145: printf("sddump: scsi write error 0x%x\n", stat); ! 1146: return (EIO); ! 1147: } ! 1148: maddr += NBPG; ! 1149: baddr += ctod(1); ! 1150: } ! 1151: return (0); ! 1152: } ! 1153: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.