Annotation of sys/scsi/sd.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: sd.c,v 1.136 2007/06/23 19:19:49 krw Exp $ */
! 2: /* $NetBSD: sd.c,v 1.111 1997/04/02 02:29:41 mycroft Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Charles M. Hannum.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: /*
! 41: * Originally written by Julian Elischer (julian@dialix.oz.au)
! 42: * for TRW Financial Systems for use under the MACH(2.5) operating system.
! 43: *
! 44: * TRW Financial Systems, in accordance with their agreement with Carnegie
! 45: * Mellon University, makes this software available to CMU to distribute
! 46: * or use in any manner that they see fit as long as this message is kept with
! 47: * the software. For this reason TFS also grants any other persons or
! 48: * organisations permission to use or modify this software.
! 49: *
! 50: * TFS supplies this software to be publicly redistributed
! 51: * on the understanding that TFS is not responsible for the correct
! 52: * functioning of this software in any circumstances.
! 53: *
! 54: * Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992
! 55: */
! 56:
! 57: #include <sys/types.h>
! 58: #include <sys/param.h>
! 59: #include <sys/systm.h>
! 60: #include <sys/timeout.h>
! 61: #include <sys/file.h>
! 62: #include <sys/stat.h>
! 63: #include <sys/ioctl.h>
! 64: #include <sys/mtio.h>
! 65: #include <sys/buf.h>
! 66: #include <sys/uio.h>
! 67: #include <sys/malloc.h>
! 68: #include <sys/errno.h>
! 69: #include <sys/device.h>
! 70: #include <sys/disklabel.h>
! 71: #include <sys/disk.h>
! 72: #include <sys/proc.h>
! 73: #include <sys/conf.h>
! 74: #include <sys/scsiio.h>
! 75:
! 76: #include <scsi/scsi_all.h>
! 77: #include <scsi/scsi_disk.h>
! 78: #include <scsi/scsiconf.h>
! 79: #include <scsi/sdvar.h>
! 80:
! 81: #include <ufs/ffs/fs.h> /* for BBSIZE and SBSIZE */
! 82:
! 83: #include <sys/vnode.h>
! 84:
! 85: int sdmatch(struct device *, void *, void *);
! 86: void sdattach(struct device *, struct device *, void *);
! 87: int sdactivate(struct device *, enum devact);
! 88: int sddetach(struct device *, int);
! 89:
! 90: void sdminphys(struct buf *);
! 91: void sdgetdisklabel(dev_t, struct sd_softc *, struct disklabel *, int);
! 92: void sdstart(void *);
! 93: void sdrestart(void *);
! 94: void sddone(struct scsi_xfer *);
! 95: void sd_shutdown(void *);
! 96: int sd_reassign_blocks(struct sd_softc *, u_long);
! 97: int sd_interpret_sense(struct scsi_xfer *);
! 98: int sd_get_parms(struct sd_softc *, struct disk_parms *, int);
! 99: void sd_flush(struct sd_softc *, int);
! 100: void sd_kill_buffers(struct sd_softc *);
! 101:
! 102: void viscpy(u_char *, u_char *, int);
! 103:
! 104: int sd_ioctl_inquiry(struct sd_softc *, struct dk_inquiry *);
! 105:
! 106: struct cfattach sd_ca = {
! 107: sizeof(struct sd_softc), sdmatch, sdattach,
! 108: sddetach, sdactivate
! 109: };
! 110:
! 111: struct cfdriver sd_cd = {
! 112: NULL, "sd", DV_DISK
! 113: };
! 114:
! 115: struct dkdriver sddkdriver = { sdstrategy };
! 116:
! 117: struct scsi_device sd_switch = {
! 118: sd_interpret_sense, /* check out error handler first */
! 119: sdstart, /* have a queue, served by this */
! 120: NULL, /* have no async handler */
! 121: sddone, /* deal with stats at interrupt time */
! 122: };
! 123:
! 124: const struct scsi_inquiry_pattern sd_patterns[] = {
! 125: {T_DIRECT, T_FIXED,
! 126: "", "", ""},
! 127: {T_DIRECT, T_REMOV,
! 128: "", "", ""},
! 129: {T_RDIRECT, T_FIXED,
! 130: "", "", ""},
! 131: {T_RDIRECT, T_REMOV,
! 132: "", "", ""},
! 133: {T_OPTICAL, T_FIXED,
! 134: "", "", ""},
! 135: {T_OPTICAL, T_REMOV,
! 136: "", "", ""},
! 137: };
! 138:
! 139: #define sdlock(softc) disk_lock(&(softc)->sc_dk)
! 140: #define sdunlock(softc) disk_unlock(&(softc)->sc_dk)
! 141: #define sdlookup(unit) (struct sd_softc *)device_lookup(&sd_cd, (unit))
! 142:
! 143: int
! 144: sdmatch(struct device *parent, void *match, void *aux)
! 145: {
! 146: struct scsi_attach_args *sa = aux;
! 147: int priority;
! 148:
! 149: (void)scsi_inqmatch(sa->sa_inqbuf,
! 150: sd_patterns, sizeof(sd_patterns)/sizeof(sd_patterns[0]),
! 151: sizeof(sd_patterns[0]), &priority);
! 152:
! 153: return (priority);
! 154: }
! 155:
! 156: /*
! 157: * The routine called by the low level scsi routine when it discovers
! 158: * a device suitable for this driver.
! 159: */
! 160: void
! 161: sdattach(struct device *parent, struct device *self, void *aux)
! 162: {
! 163: int error, result;
! 164: struct sd_softc *sd = (struct sd_softc *)self;
! 165: struct disk_parms *dp = &sd->params;
! 166: struct scsi_attach_args *sa = aux;
! 167: struct scsi_link *sc_link = sa->sa_sc_link;
! 168:
! 169: SC_DEBUG(sc_link, SDEV_DB2, ("sdattach:\n"));
! 170:
! 171: /*
! 172: * Store information needed to contact our base driver
! 173: */
! 174: sd->sc_link = sc_link;
! 175: sc_link->device = &sd_switch;
! 176: sc_link->device_softc = sd;
! 177:
! 178: /*
! 179: * Initialize and attach the disk structure.
! 180: */
! 181: sd->sc_dk.dk_driver = &sddkdriver;
! 182: sd->sc_dk.dk_name = sd->sc_dev.dv_xname;
! 183: disk_attach(&sd->sc_dk);
! 184:
! 185: if ((sc_link->flags & SDEV_ATAPI) && (sc_link->flags & SDEV_REMOVABLE))
! 186: sc_link->quirks |= SDEV_NOSYNCCACHE;
! 187:
! 188: if (!(sc_link->inqdata.flags & SID_RelAdr))
! 189: sc_link->quirks |= SDEV_ONLYBIG;
! 190:
! 191: /*
! 192: * Note if this device is ancient. This is used in sdminphys().
! 193: */
! 194: if (!(sc_link->flags & SDEV_ATAPI) &&
! 195: SCSISPC(sa->sa_inqbuf->version) == 0)
! 196: sd->flags |= SDF_ANCIENT;
! 197:
! 198: /*
! 199: * Use the subdriver to request information regarding
! 200: * the drive. We cannot use interrupts yet, so the
! 201: * request must specify this.
! 202: */
! 203: printf("\n");
! 204:
! 205: timeout_set(&sd->sc_timeout, sdrestart, sd);
! 206:
! 207: /* Spin up non-UMASS devices ready or not. */
! 208: if ((sd->sc_link->flags & SDEV_UMASS) == 0)
! 209: scsi_start(sc_link, SSS_START, scsi_autoconf | SCSI_SILENT |
! 210: SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE);
! 211:
! 212: /* Check that it is still responding and ok. */
! 213: error = scsi_test_unit_ready(sd->sc_link, TEST_READY_RETRIES,
! 214: scsi_autoconf | SCSI_IGNORE_ILLEGAL_REQUEST |
! 215: SCSI_IGNORE_MEDIA_CHANGE | SCSI_SILENT);
! 216:
! 217: if (error)
! 218: result = SDGP_RESULT_OFFLINE;
! 219: else
! 220: result = sd_get_parms(sd, &sd->params,
! 221: scsi_autoconf | SCSI_SILENT | SCSI_IGNORE_MEDIA_CHANGE);
! 222:
! 223: printf("%s: ", sd->sc_dev.dv_xname);
! 224: switch (result) {
! 225: case SDGP_RESULT_OK:
! 226: printf("%lldMB, %lu cyl, %lu head, %lu sec, %lu bytes/sec, %lld sec total",
! 227: dp->disksize / (1048576 / dp->blksize), dp->cyls,
! 228: dp->heads, dp->sectors, dp->blksize, dp->disksize);
! 229: break;
! 230:
! 231: case SDGP_RESULT_OFFLINE:
! 232: printf("drive offline");
! 233: break;
! 234:
! 235: #ifdef DIAGNOSTIC
! 236: default:
! 237: panic("sdattach: unknown result (%#x) from get_parms", result);
! 238: break;
! 239: #endif
! 240: }
! 241: printf("\n");
! 242:
! 243: /*
! 244: * Establish a shutdown hook so that we can ensure that
! 245: * our data has actually made it onto the platter at
! 246: * shutdown time. Note that this relies on the fact
! 247: * that the shutdown hook code puts us at the head of
! 248: * the list (thus guaranteeing that our hook runs before
! 249: * our ancestors').
! 250: */
! 251: if ((sd->sc_sdhook =
! 252: shutdownhook_establish(sd_shutdown, sd)) == NULL)
! 253: printf("%s: WARNING: unable to establish shutdown hook\n",
! 254: sd->sc_dev.dv_xname);
! 255: }
! 256:
! 257: int
! 258: sdactivate(struct device *self, enum devact act)
! 259: {
! 260: int rv = 0;
! 261:
! 262: switch (act) {
! 263: case DVACT_ACTIVATE:
! 264: break;
! 265:
! 266: case DVACT_DEACTIVATE:
! 267: /*
! 268: * Nothing to do; we key off the device's DVF_ACTIVATE.
! 269: */
! 270: break;
! 271: }
! 272:
! 273: return (rv);
! 274: }
! 275:
! 276:
! 277: int
! 278: sddetach(struct device *self, int flags)
! 279: {
! 280: struct sd_softc *sd = (struct sd_softc *)self;
! 281: int bmaj, cmaj, mn;
! 282:
! 283: sd_kill_buffers(sd);
! 284:
! 285: /* Locate the lowest minor number to be detached. */
! 286: mn = DISKMINOR(self->dv_unit, 0);
! 287:
! 288: for (bmaj = 0; bmaj < nblkdev; bmaj++)
! 289: if (bdevsw[bmaj].d_open == sdopen)
! 290: vdevgone(bmaj, mn, mn + MAXPARTITIONS - 1, VBLK);
! 291: for (cmaj = 0; cmaj < nchrdev; cmaj++)
! 292: if (cdevsw[cmaj].d_open == sdopen)
! 293: vdevgone(cmaj, mn, mn + MAXPARTITIONS - 1, VCHR);
! 294:
! 295: /* Get rid of the shutdown hook. */
! 296: if (sd->sc_sdhook != NULL)
! 297: shutdownhook_disestablish(sd->sc_sdhook);
! 298:
! 299: /* Detach disk. */
! 300: disk_detach(&sd->sc_dk);
! 301:
! 302: return (0);
! 303: }
! 304:
! 305: /*
! 306: * Open the device. Make sure the partition info is as up-to-date as can be.
! 307: */
! 308: int
! 309: sdopen(dev_t dev, int flag, int fmt, struct proc *p)
! 310: {
! 311: struct scsi_link *sc_link;
! 312: struct sd_softc *sd;
! 313: int error = 0, part, rawopen, unit;
! 314:
! 315: unit = DISKUNIT(dev);
! 316: part = DISKPART(dev);
! 317:
! 318: rawopen = (part == RAW_PART) && (fmt == S_IFCHR);
! 319:
! 320: sd = sdlookup(unit);
! 321: if (sd == NULL)
! 322: return (ENXIO);
! 323:
! 324: sc_link = sd->sc_link;
! 325: SC_DEBUG(sc_link, SDEV_DB1,
! 326: ("sdopen: dev=0x%x (unit %d (of %d), partition %d)\n", dev, unit,
! 327: sd_cd.cd_ndevs, part));
! 328:
! 329: if ((error = sdlock(sd)) != 0) {
! 330: device_unref(&sd->sc_dev);
! 331: return (error);
! 332: }
! 333:
! 334: if (sd->sc_dk.dk_openmask != 0) {
! 335: /*
! 336: * If any partition is open, but the disk has been invalidated,
! 337: * disallow further opens of non-raw partition.
! 338: */
! 339: if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
! 340: if (rawopen)
! 341: goto out;
! 342: error = EIO;
! 343: goto bad;
! 344: }
! 345: } else {
! 346: /* Spin up non-UMASS devices ready or not. */
! 347: if ((sd->sc_link->flags & SDEV_UMASS) == 0)
! 348: scsi_start(sc_link, SSS_START, (rawopen ? SCSI_SILENT :
! 349: 0) | SCSI_IGNORE_ILLEGAL_REQUEST |
! 350: SCSI_IGNORE_MEDIA_CHANGE);
! 351:
! 352: /* Use sd_interpret_sense() for sense errors.
! 353: *
! 354: * But only after spinning the disk up! Just in case a broken
! 355: * device returns "Initialization command required." and causes
! 356: * a loop of scsi_start() calls.
! 357: */
! 358: sc_link->flags |= SDEV_OPEN;
! 359:
! 360: /* Check that it is still responding and ok. */
! 361: error = scsi_test_unit_ready(sc_link,
! 362: TEST_READY_RETRIES, (rawopen ? SCSI_SILENT : 0) |
! 363: SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE);
! 364:
! 365: if (error) {
! 366: if (rawopen) {
! 367: error = 0;
! 368: goto out;
! 369: } else
! 370: goto bad;
! 371: }
! 372:
! 373: /*
! 374: * Try to prevent the unloading of a removable device while
! 375: * it's open. But allow the open to proceed if the device can't
! 376: * be locked in.
! 377: */
! 378: if ((sc_link->flags & SDEV_REMOVABLE) != 0)
! 379: scsi_prevent(sc_link, PR_PREVENT,
! 380: SCSI_IGNORE_ILLEGAL_REQUEST |
! 381: SCSI_IGNORE_MEDIA_CHANGE);
! 382:
! 383: /* Load the physical device parameters. */
! 384: sc_link->flags |= SDEV_MEDIA_LOADED;
! 385: if (sd_get_parms(sd, &sd->params, (rawopen ? SCSI_SILENT : 0))
! 386: == SDGP_RESULT_OFFLINE) {
! 387: sc_link->flags &= ~SDEV_MEDIA_LOADED;
! 388: error = ENXIO;
! 389: goto bad;
! 390: }
! 391: SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded\n"));
! 392:
! 393: /* Load the partition info if not already loaded. */
! 394: sdgetdisklabel(dev, sd, sd->sc_dk.dk_label, 0);
! 395: SC_DEBUG(sc_link, SDEV_DB3, ("Disklabel loaded\n"));
! 396: }
! 397:
! 398: /* Check that the partition exists. */
! 399: if (part != RAW_PART &&
! 400: (part >= sd->sc_dk.dk_label->d_npartitions ||
! 401: sd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
! 402: error = ENXIO;
! 403: goto bad;
! 404: }
! 405:
! 406: out: /* Insure only one open at a time. */
! 407: switch (fmt) {
! 408: case S_IFCHR:
! 409: sd->sc_dk.dk_copenmask |= (1 << part);
! 410: break;
! 411: case S_IFBLK:
! 412: sd->sc_dk.dk_bopenmask |= (1 << part);
! 413: break;
! 414: }
! 415: sd->sc_dk.dk_openmask = sd->sc_dk.dk_copenmask | sd->sc_dk.dk_bopenmask;
! 416: SC_DEBUG(sc_link, SDEV_DB3, ("open complete\n"));
! 417:
! 418: /* It's OK to fall through because dk_openmask is now non-zero. */
! 419: bad:
! 420: if (sd->sc_dk.dk_openmask == 0) {
! 421: if ((sd->sc_link->flags & SDEV_REMOVABLE) != 0)
! 422: scsi_prevent(sc_link, PR_ALLOW,
! 423: SCSI_IGNORE_ILLEGAL_REQUEST |
! 424: SCSI_IGNORE_MEDIA_CHANGE);
! 425: sc_link->flags &= ~(SDEV_OPEN | SDEV_MEDIA_LOADED);
! 426: }
! 427:
! 428: sdunlock(sd);
! 429: device_unref(&sd->sc_dev);
! 430: return (error);
! 431: }
! 432:
! 433: /*
! 434: * Close the device. Only called if we are the last occurrence of an open
! 435: * device. Convenient now but usually a pain.
! 436: */
! 437: int
! 438: sdclose(dev_t dev, int flag, int fmt, struct proc *p)
! 439: {
! 440: struct sd_softc *sd;
! 441: int part = DISKPART(dev);
! 442: int error;
! 443:
! 444: sd = sdlookup(DISKUNIT(dev));
! 445: if (sd == NULL)
! 446: return ENXIO;
! 447:
! 448: if ((error = sdlock(sd)) != 0) {
! 449: device_unref(&sd->sc_dev);
! 450: return (error);
! 451: }
! 452:
! 453: switch (fmt) {
! 454: case S_IFCHR:
! 455: sd->sc_dk.dk_copenmask &= ~(1 << part);
! 456: break;
! 457: case S_IFBLK:
! 458: sd->sc_dk.dk_bopenmask &= ~(1 << part);
! 459: break;
! 460: }
! 461: sd->sc_dk.dk_openmask = sd->sc_dk.dk_copenmask | sd->sc_dk.dk_bopenmask;
! 462:
! 463: if (sd->sc_dk.dk_openmask == 0) {
! 464: if ((sd->flags & SDF_DIRTY) != 0)
! 465: sd_flush(sd, 0);
! 466:
! 467: if ((sd->sc_link->flags & SDEV_REMOVABLE) != 0)
! 468: scsi_prevent(sd->sc_link, PR_ALLOW,
! 469: SCSI_IGNORE_ILLEGAL_REQUEST |
! 470: SCSI_IGNORE_NOT_READY);
! 471: sd->sc_link->flags &= ~(SDEV_OPEN | SDEV_MEDIA_LOADED);
! 472:
! 473: if (sd->sc_link->flags & SDEV_EJECTING) {
! 474: scsi_start(sd->sc_link, SSS_STOP|SSS_LOEJ, 0);
! 475: sd->sc_link->flags &= ~SDEV_EJECTING;
! 476: }
! 477:
! 478: timeout_del(&sd->sc_timeout);
! 479: }
! 480:
! 481: sdunlock(sd);
! 482: device_unref(&sd->sc_dev);
! 483: return 0;
! 484: }
! 485:
! 486: /*
! 487: * Actually translate the requested transfer into one the physical driver
! 488: * can understand. The transfer is described by a buf and will include
! 489: * only one physical transfer.
! 490: */
! 491: void
! 492: sdstrategy(struct buf *bp)
! 493: {
! 494: struct sd_softc *sd;
! 495: int s;
! 496:
! 497: sd = sdlookup(DISKUNIT(bp->b_dev));
! 498: if (sd == NULL) {
! 499: bp->b_error = ENXIO;
! 500: goto bad;
! 501: }
! 502:
! 503: SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdstrategy: %ld bytes @ blk %d\n",
! 504: bp->b_bcount, bp->b_blkno));
! 505: /*
! 506: * If the device has been made invalid, error out
! 507: */
! 508: if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
! 509: if (sd->sc_link->flags & SDEV_OPEN)
! 510: bp->b_error = EIO;
! 511: else
! 512: bp->b_error = ENODEV;
! 513: goto bad;
! 514: }
! 515: /*
! 516: * If it's a null transfer, return immediately
! 517: */
! 518: if (bp->b_bcount == 0)
! 519: goto done;
! 520:
! 521: /*
! 522: * The transfer must be a whole number of sectors.
! 523: */
! 524: if ((bp->b_bcount % sd->sc_dk.dk_label->d_secsize) != 0) {
! 525: bp->b_error = EINVAL;
! 526: goto bad;
! 527: }
! 528: /*
! 529: * Do bounds checking, adjust transfer. if error, process.
! 530: * If end of partition, just return.
! 531: */
! 532: if (DISKPART(bp->b_dev) != RAW_PART &&
! 533: bounds_check_with_label(bp, sd->sc_dk.dk_label,
! 534: (sd->flags & (SDF_WLABEL|SDF_LABELLING)) != 0) <= 0)
! 535: goto done;
! 536:
! 537: s = splbio();
! 538:
! 539: /*
! 540: * Place it in the queue of disk activities for this disk
! 541: */
! 542: disksort(&sd->buf_queue, bp);
! 543:
! 544: /*
! 545: * Tell the device to get going on the transfer if it's
! 546: * not doing anything, otherwise just wait for completion
! 547: */
! 548: sdstart(sd);
! 549:
! 550: splx(s);
! 551:
! 552: device_unref(&sd->sc_dev);
! 553: return;
! 554:
! 555: bad:
! 556: bp->b_flags |= B_ERROR;
! 557: done:
! 558: /*
! 559: * Correctly set the buf to indicate a completed xfer
! 560: */
! 561: bp->b_resid = bp->b_bcount;
! 562: s = splbio();
! 563: biodone(bp);
! 564: splx(s);
! 565: if (sd != NULL)
! 566: device_unref(&sd->sc_dev);
! 567: }
! 568:
! 569: /*
! 570: * sdstart looks to see if there is a buf waiting for the device
! 571: * and that the device is not already busy. If both are true,
! 572: * It dequeues the buf and creates a scsi command to perform the
! 573: * transfer in the buf. The transfer request will call scsi_done
! 574: * on completion, which will in turn call this routine again
! 575: * so that the next queued transfer is performed.
! 576: * The bufs are queued by the strategy routine (sdstrategy)
! 577: *
! 578: * This routine is also called after other non-queued requests
! 579: * have been made of the scsi driver, to ensure that the queue
! 580: * continues to be drained.
! 581: *
! 582: * must be called at the correct (highish) spl level
! 583: * sdstart() is called at splbio from sdstrategy, sdrestart and scsi_done
! 584: */
! 585: void
! 586: sdstart(void *v)
! 587: {
! 588: struct sd_softc *sd = (struct sd_softc *)v;
! 589: struct scsi_link *sc_link = sd->sc_link;
! 590: struct buf *bp = 0;
! 591: struct buf *dp;
! 592: struct scsi_rw_big cmd_big;
! 593: struct scsi_rw_12 cmd_12;
! 594: struct scsi_rw_16 cmd_16;
! 595: struct scsi_rw cmd_small;
! 596: struct scsi_generic *cmdp;
! 597: daddr64_t blkno;
! 598: int nblks, cmdlen, error;
! 599: struct partition *p;
! 600:
! 601: SC_DEBUG(sc_link, SDEV_DB2, ("sdstart\n"));
! 602:
! 603: splassert(IPL_BIO);
! 604:
! 605: /*
! 606: * Check if the device has room for another command
! 607: */
! 608: while (sc_link->openings > 0) {
! 609: /*
! 610: * there is excess capacity, but a special waits
! 611: * It'll need the adapter as soon as we clear out of the
! 612: * way and let it run (user level wait).
! 613: */
! 614: if (sc_link->flags & SDEV_WAITING) {
! 615: sc_link->flags &= ~SDEV_WAITING;
! 616: wakeup((caddr_t)sc_link);
! 617: return;
! 618: }
! 619:
! 620: /*
! 621: * See if there is a buf with work for us to do..
! 622: */
! 623: dp = &sd->buf_queue;
! 624: if ((bp = dp->b_actf) == NULL) /* yes, an assign */
! 625: return;
! 626: dp->b_actf = bp->b_actf;
! 627:
! 628: /*
! 629: * If the device has become invalid, abort all the
! 630: * reads and writes until all files have been closed and
! 631: * re-opened
! 632: */
! 633: if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
! 634: bp->b_error = EIO;
! 635: bp->b_flags |= B_ERROR;
! 636: bp->b_resid = bp->b_bcount;
! 637: biodone(bp);
! 638: continue;
! 639: }
! 640:
! 641: /*
! 642: * We have a buf, now we should make a command
! 643: *
! 644: * First, translate the block to absolute and put it in terms
! 645: * of the logical blocksize of the device.
! 646: */
! 647: blkno =
! 648: bp->b_blkno / (sd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
! 649: p = &sd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
! 650: blkno += DL_GETPOFFSET(p);
! 651: nblks = howmany(bp->b_bcount, sd->sc_dk.dk_label->d_secsize);
! 652:
! 653: /*
! 654: * Fill out the scsi command. If the transfer will
! 655: * fit in a "small" cdb, use it.
! 656: */
! 657: if (!(sc_link->flags & SDEV_ATAPI) &&
! 658: !(sc_link->quirks & SDEV_ONLYBIG) &&
! 659: ((blkno & 0x1fffff) == blkno) &&
! 660: ((nblks & 0xff) == nblks)) {
! 661: /*
! 662: * We can fit in a 6 byte cdb.
! 663: */
! 664: bzero(&cmd_small, sizeof(cmd_small));
! 665: cmd_small.opcode = (bp->b_flags & B_READ) ?
! 666: READ_COMMAND : WRITE_COMMAND;
! 667: _lto3b(blkno, cmd_small.addr);
! 668: cmd_small.length = nblks;
! 669: cmdlen = sizeof(cmd_small);
! 670: cmdp = (struct scsi_generic *)&cmd_small;
! 671: } else if (((blkno & 0xffffffff) == blkno) &&
! 672: ((nblks & 0xffff) == nblks)) {
! 673: /*
! 674: * We can fit in a 10 byte cdb.
! 675: */
! 676: bzero(&cmd_big, sizeof(cmd_big));
! 677: cmd_big.opcode = (bp->b_flags & B_READ) ?
! 678: READ_BIG : WRITE_BIG;
! 679: _lto4b(blkno, cmd_big.addr);
! 680: _lto2b(nblks, cmd_big.length);
! 681: cmdlen = sizeof(cmd_big);
! 682: cmdp = (struct scsi_generic *)&cmd_big;
! 683: } else if (((blkno & 0xffffffff) == blkno) &&
! 684: ((nblks & 0xffffffff) == nblks)) {
! 685: /*
! 686: * We can fit in a 12 byte cdb.
! 687: */
! 688: bzero(&cmd_12, sizeof(cmd_12));
! 689: cmd_12.opcode = (bp->b_flags & B_READ) ?
! 690: READ_12 : WRITE_12;
! 691: _lto4b(blkno, cmd_12.addr);
! 692: _lto4b(nblks, cmd_12.length);
! 693: cmdlen = sizeof(cmd_12);
! 694: cmdp = (struct scsi_generic *)&cmd_12;
! 695: } else {
! 696: /*
! 697: * Need a 16 byte cdb. There's nothing bigger.
! 698: */
! 699: bzero(&cmd_16, sizeof(cmd_16));
! 700: cmd_16.opcode = (bp->b_flags & B_READ) ?
! 701: READ_16 : WRITE_16;
! 702: _lto8b(blkno, cmd_16.addr);
! 703: _lto4b(nblks, cmd_16.length);
! 704: cmdlen = sizeof(cmd_16);
! 705: cmdp = (struct scsi_generic *)&cmd_16;
! 706: }
! 707:
! 708: /* Instrumentation. */
! 709: disk_busy(&sd->sc_dk);
! 710:
! 711: /*
! 712: * Call the routine that chats with the adapter.
! 713: * Note: we cannot sleep as we may be an interrupt
! 714: */
! 715: error = scsi_scsi_cmd(sc_link, cmdp, cmdlen,
! 716: (u_char *)bp->b_data, bp->b_bcount,
! 717: SDRETRIES, 60000, bp, SCSI_NOSLEEP |
! 718: ((bp->b_flags & B_READ) ? SCSI_DATA_IN : SCSI_DATA_OUT));
! 719: switch (error) {
! 720: case 0:
! 721: /*
! 722: * Mark the disk dirty so that the cache will be
! 723: * flushed on close.
! 724: */
! 725: if ((bp->b_flags & B_READ) == 0)
! 726: sd->flags |= SDF_DIRTY;
! 727: timeout_del(&sd->sc_timeout);
! 728: break;
! 729: case EAGAIN:
! 730: /*
! 731: * The device can't start another i/o. Try again later.
! 732: */
! 733: dp->b_actf = bp;
! 734: disk_unbusy(&sd->sc_dk, 0, 0);
! 735: timeout_add(&sd->sc_timeout, 1);
! 736: return;
! 737: default:
! 738: disk_unbusy(&sd->sc_dk, 0, 0);
! 739: printf("%s: not queued, error %d\n",
! 740: sd->sc_dev.dv_xname, error);
! 741: break;
! 742: }
! 743: }
! 744: }
! 745:
! 746: void
! 747: sdrestart(void *v)
! 748: {
! 749: int s;
! 750:
! 751: s = splbio();
! 752: sdstart(v);
! 753: splx(s);
! 754: }
! 755:
! 756: void
! 757: sddone(struct scsi_xfer *xs)
! 758: {
! 759: struct sd_softc *sd = xs->sc_link->device_softc;
! 760:
! 761: if (sd->flags & SDF_FLUSHING) {
! 762: /* Flush completed, no longer dirty. */
! 763: sd->flags &= ~(SDF_FLUSHING|SDF_DIRTY);
! 764: }
! 765:
! 766: if (xs->bp != NULL)
! 767: disk_unbusy(&sd->sc_dk, (xs->bp->b_bcount - xs->bp->b_resid),
! 768: (xs->bp->b_flags & B_READ));
! 769: }
! 770:
! 771: void
! 772: sdminphys(struct buf *bp)
! 773: {
! 774: struct sd_softc *sd;
! 775: long max;
! 776:
! 777: sd = sdlookup(DISKUNIT(bp->b_dev));
! 778: if (sd == NULL)
! 779: return; /* XXX - right way to fail this? */
! 780:
! 781: /*
! 782: * If the device is ancient, we want to make sure that
! 783: * the transfer fits into a 6-byte cdb.
! 784: *
! 785: * XXX Note that the SCSI-I spec says that 256-block transfers
! 786: * are allowed in a 6-byte read/write, and are specified
! 787: * by setting the "length" to 0. However, we're conservative
! 788: * here, allowing only 255-block transfers in case an
! 789: * ancient device gets confused by length == 0. A length of 0
! 790: * in a 10-byte read/write actually means 0 blocks.
! 791: */
! 792: if (sd->flags & SDF_ANCIENT) {
! 793: max = sd->sc_dk.dk_label->d_secsize * 0xff;
! 794:
! 795: if (bp->b_bcount > max)
! 796: bp->b_bcount = max;
! 797: }
! 798:
! 799: (*sd->sc_link->adapter->scsi_minphys)(bp);
! 800:
! 801: device_unref(&sd->sc_dev);
! 802: }
! 803:
! 804: int
! 805: sdread(dev_t dev, struct uio *uio, int ioflag)
! 806: {
! 807: return (physio(sdstrategy, NULL, dev, B_READ, sdminphys, uio));
! 808: }
! 809:
! 810: int
! 811: sdwrite(dev_t dev, struct uio *uio, int ioflag)
! 812: {
! 813: return (physio(sdstrategy, NULL, dev, B_WRITE, sdminphys, uio));
! 814: }
! 815:
! 816: /*
! 817: * Perform special action on behalf of the user
! 818: * Knows about the internals of this device
! 819: */
! 820: int
! 821: sdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
! 822: {
! 823: struct sd_softc *sd;
! 824: struct disklabel *lp;
! 825: int error = 0;
! 826: int part = DISKPART(dev);
! 827:
! 828: sd = sdlookup(DISKUNIT(dev));
! 829: if (sd == NULL)
! 830: return ENXIO;
! 831:
! 832: SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdioctl 0x%lx\n", cmd));
! 833:
! 834: /*
! 835: * If the device is not valid.. abandon ship
! 836: */
! 837: if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
! 838: switch (cmd) {
! 839: case DIOCWLABEL:
! 840: case DIOCLOCK:
! 841: case DIOCEJECT:
! 842: case SCIOCIDENTIFY:
! 843: case SCIOCCOMMAND:
! 844: case SCIOCDEBUG:
! 845: if (part == RAW_PART)
! 846: break;
! 847: /* FALLTHROUGH */
! 848: default:
! 849: if ((sd->sc_link->flags & SDEV_OPEN) == 0) {
! 850: error = ENODEV;
! 851: goto exit;
! 852: } else {
! 853: error = EIO;
! 854: goto exit;
! 855: }
! 856: }
! 857: }
! 858:
! 859: switch (cmd) {
! 860: case DIOCRLDINFO:
! 861: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
! 862: sdgetdisklabel(dev, sd, lp, 0);
! 863: bcopy(lp, sd->sc_dk.dk_label, sizeof(*lp));
! 864: free(lp, M_TEMP);
! 865: goto exit;
! 866: case DIOCGPDINFO:
! 867: sdgetdisklabel(dev, sd, (struct disklabel *)addr, 1);
! 868: goto exit;
! 869:
! 870: case DIOCGDINFO:
! 871: *(struct disklabel *)addr = *(sd->sc_dk.dk_label);
! 872: goto exit;
! 873:
! 874: case DIOCGPART:
! 875: ((struct partinfo *)addr)->disklab = sd->sc_dk.dk_label;
! 876: ((struct partinfo *)addr)->part =
! 877: &sd->sc_dk.dk_label->d_partitions[DISKPART(dev)];
! 878: goto exit;
! 879:
! 880: case DIOCWDINFO:
! 881: case DIOCSDINFO:
! 882: if ((flag & FWRITE) == 0) {
! 883: error = EBADF;
! 884: goto exit;
! 885: }
! 886:
! 887: if ((error = sdlock(sd)) != 0)
! 888: goto exit;
! 889: sd->flags |= SDF_LABELLING;
! 890:
! 891: error = setdisklabel(sd->sc_dk.dk_label,
! 892: (struct disklabel *)addr, /*sd->sc_dk.dk_openmask : */0);
! 893: if (error == 0) {
! 894: if (cmd == DIOCWDINFO)
! 895: error = writedisklabel(DISKLABELDEV(dev),
! 896: sdstrategy, sd->sc_dk.dk_label);
! 897: }
! 898:
! 899: sd->flags &= ~SDF_LABELLING;
! 900: sdunlock(sd);
! 901: goto exit;
! 902:
! 903: case DIOCWLABEL:
! 904: if ((flag & FWRITE) == 0) {
! 905: error = EBADF;
! 906: goto exit;
! 907: }
! 908: if (*(int *)addr)
! 909: sd->flags |= SDF_WLABEL;
! 910: else
! 911: sd->flags &= ~SDF_WLABEL;
! 912: goto exit;
! 913:
! 914: case DIOCLOCK:
! 915: error = scsi_prevent(sd->sc_link,
! 916: (*(int *)addr) ? PR_PREVENT : PR_ALLOW, 0);
! 917: goto exit;
! 918:
! 919: case MTIOCTOP:
! 920: if (((struct mtop *)addr)->mt_op != MTOFFL) {
! 921: error = EIO;
! 922: goto exit;
! 923: }
! 924: /* FALLTHROUGH */
! 925: case DIOCEJECT:
! 926: if ((sd->sc_link->flags & SDEV_REMOVABLE) == 0) {
! 927: error = ENOTTY;
! 928: goto exit;
! 929: }
! 930: sd->sc_link->flags |= SDEV_EJECTING;
! 931: goto exit;
! 932:
! 933: case DIOCINQ:
! 934: error = scsi_do_ioctl(sd->sc_link, dev, cmd, addr, flag, p);
! 935: if (error == ENOTTY)
! 936: error = sd_ioctl_inquiry(sd,
! 937: (struct dk_inquiry *)addr);
! 938: goto exit;
! 939:
! 940: default:
! 941: if (part != RAW_PART) {
! 942: error = ENOTTY;
! 943: goto exit;
! 944: }
! 945: error = scsi_do_ioctl(sd->sc_link, dev, cmd, addr, flag, p);
! 946: }
! 947:
! 948: exit:
! 949: device_unref(&sd->sc_dev);
! 950: return (error);
! 951: }
! 952:
! 953: int
! 954: sd_ioctl_inquiry(struct sd_softc *sd, struct dk_inquiry *di)
! 955: {
! 956: struct scsi_inquiry_vpd vpd;
! 957:
! 958: bzero(di, sizeof(struct dk_inquiry));
! 959: scsi_strvis(di->vendor, sd->sc_link->inqdata.vendor,
! 960: sizeof(sd->sc_link->inqdata.vendor));
! 961: scsi_strvis(di->product, sd->sc_link->inqdata.product,
! 962: sizeof(sd->sc_link->inqdata.product));
! 963: scsi_strvis(di->revision, sd->sc_link->inqdata.revision,
! 964: sizeof(sd->sc_link->inqdata.revision));
! 965:
! 966: /* the serial vpd page is optional */
! 967: if (scsi_inquire_vpd(sd->sc_link, &vpd, sizeof(vpd),
! 968: SI_PG_SERIAL, 0) == 0)
! 969: scsi_strvis(di->serial, vpd.serial, sizeof(vpd.serial));
! 970:
! 971: return (0);
! 972: }
! 973:
! 974: /*
! 975: * Load the label information on the named device
! 976: */
! 977: void
! 978: sdgetdisklabel(dev_t dev, struct sd_softc *sd, struct disklabel *lp,
! 979: int spoofonly)
! 980: {
! 981: size_t len;
! 982: char *errstring, packname[sizeof(lp->d_packname) + 1];
! 983: char product[17], vendor[9];
! 984:
! 985: bzero(lp, sizeof(struct disklabel));
! 986:
! 987: lp->d_secsize = sd->params.blksize;
! 988: lp->d_ntracks = sd->params.heads;
! 989: lp->d_nsectors = sd->params.sectors;
! 990: lp->d_ncylinders = sd->params.cyls;
! 991: lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
! 992: if (lp->d_secpercyl == 0) {
! 993: lp->d_secpercyl = 100;
! 994: /* as long as it's not 0 - readdisklabel divides by it */
! 995: }
! 996:
! 997: lp->d_type = DTYPE_SCSI;
! 998: if ((sd->sc_link->inqdata.device & SID_TYPE) == T_OPTICAL)
! 999: strncpy(lp->d_typename, "SCSI optical",
! 1000: sizeof(lp->d_typename));
! 1001: else
! 1002: strncpy(lp->d_typename, "SCSI disk",
! 1003: sizeof(lp->d_typename));
! 1004:
! 1005: /*
! 1006: * Try to fit '<vendor> <product>' into d_packname. If that doesn't fit
! 1007: * then leave out '<vendor> ' and use only as much of '<product>' as
! 1008: * does fit.
! 1009: */
! 1010: viscpy(vendor, sd->sc_link->inqdata.vendor, 8);
! 1011: viscpy(product, sd->sc_link->inqdata.product, 16);
! 1012: len = snprintf(packname, sizeof(packname), "%s %s", vendor, product);
! 1013: if (len > sizeof(lp->d_packname)) {
! 1014: strlcpy(packname, product, sizeof(packname));
! 1015: len = strlen(packname);
! 1016: }
! 1017: /*
! 1018: * It is safe to use len as the count of characters to copy because
! 1019: * packname is sizeof(lp->d_packname)+1, the string in packname is
! 1020: * always null terminated and len does not count the terminating null.
! 1021: * d_packname is not a null terminated string.
! 1022: */
! 1023: bcopy(packname, lp->d_packname, len);
! 1024:
! 1025: DL_SETDSIZE(lp, sd->params.disksize);
! 1026: lp->d_rpm = sd->params.rot_rate;
! 1027: lp->d_interleave = 1;
! 1028: lp->d_version = 1;
! 1029: lp->d_flags = 0;
! 1030:
! 1031: /* XXX - these values for BBSIZE and SBSIZE assume ffs */
! 1032: lp->d_bbsize = BBSIZE;
! 1033: lp->d_sbsize = SBSIZE;
! 1034:
! 1035: lp->d_magic = DISKMAGIC;
! 1036: lp->d_magic2 = DISKMAGIC;
! 1037: lp->d_checksum = dkcksum(lp);
! 1038:
! 1039: /*
! 1040: * Call the generic disklabel extraction routine
! 1041: */
! 1042: errstring = readdisklabel(DISKLABELDEV(dev), sdstrategy, lp, spoofonly);
! 1043: if (errstring) {
! 1044: /*printf("%s: %s\n", sd->sc_dev.dv_xname, errstring);*/
! 1045: }
! 1046: }
! 1047:
! 1048:
! 1049: void
! 1050: sd_shutdown(void *arg)
! 1051: {
! 1052: struct sd_softc *sd = (struct sd_softc *)arg;
! 1053:
! 1054: /*
! 1055: * If the disk cache needs to be flushed, and the disk supports
! 1056: * it, flush it. We're cold at this point, so we poll for
! 1057: * completion.
! 1058: */
! 1059: if ((sd->flags & SDF_DIRTY) != 0)
! 1060: sd_flush(sd, SCSI_AUTOCONF);
! 1061:
! 1062: timeout_del(&sd->sc_timeout);
! 1063: }
! 1064:
! 1065: /*
! 1066: * Tell the device to map out a defective block
! 1067: */
! 1068: int
! 1069: sd_reassign_blocks(struct sd_softc *sd, u_long blkno)
! 1070: {
! 1071: struct scsi_reassign_blocks scsi_cmd;
! 1072: struct scsi_reassign_blocks_data rbdata;
! 1073:
! 1074: bzero(&scsi_cmd, sizeof(scsi_cmd));
! 1075: bzero(&rbdata, sizeof(rbdata));
! 1076: scsi_cmd.opcode = REASSIGN_BLOCKS;
! 1077:
! 1078: _lto2b(sizeof(rbdata.defect_descriptor[0]), rbdata.length);
! 1079: _lto4b(blkno, rbdata.defect_descriptor[0].dlbaddr);
! 1080:
! 1081: return scsi_scsi_cmd(sd->sc_link, (struct scsi_generic *)&scsi_cmd,
! 1082: sizeof(scsi_cmd), (u_char *)&rbdata, sizeof(rbdata), SDRETRIES,
! 1083: 5000, NULL, SCSI_DATA_OUT);
! 1084: }
! 1085:
! 1086: /*
! 1087: * Check Errors
! 1088: */
! 1089: int
! 1090: sd_interpret_sense(struct scsi_xfer *xs)
! 1091: {
! 1092: struct scsi_sense_data *sense = &xs->sense;
! 1093: struct scsi_link *sc_link = xs->sc_link;
! 1094: struct sd_softc *sd = sc_link->device_softc;
! 1095: u_int8_t serr = sense->error_code & SSD_ERRCODE;
! 1096: int retval;
! 1097:
! 1098: /*
! 1099: * Let the generic code handle everything except a few categories of
! 1100: * LUN not ready errors on open devices.
! 1101: */
! 1102: if (((sc_link->flags & SDEV_OPEN) == 0) ||
! 1103: (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED) ||
! 1104: ((sense->flags & SSD_KEY) != SKEY_NOT_READY) ||
! 1105: (sense->extra_len < 6))
! 1106: return (EJUSTRETURN);
! 1107:
! 1108: switch (ASC_ASCQ(sense)) {
! 1109: case SENSE_NOT_READY_BECOMING_READY:
! 1110: SC_DEBUG(sc_link, SDEV_DB1, ("becoming ready.\n"));
! 1111: retval = scsi_delay(xs, 5);
! 1112: break;
! 1113:
! 1114: case SENSE_NOT_READY_INIT_REQUIRED:
! 1115: SC_DEBUG(sc_link, SDEV_DB1, ("spinning up\n"));
! 1116: retval = scsi_start(sd->sc_link, SSS_START,
! 1117: SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_URGENT | SCSI_NOSLEEP);
! 1118: if (retval == 0)
! 1119: retval = ERESTART;
! 1120: else
! 1121: SC_DEBUG(sc_link, SDEV_DB1, ("spin up failed (%#x)\n",
! 1122: retval));
! 1123: break;
! 1124:
! 1125: default:
! 1126: retval = EJUSTRETURN;
! 1127: break;
! 1128: }
! 1129:
! 1130: return (retval);
! 1131: }
! 1132:
! 1133: daddr64_t
! 1134: sdsize(dev_t dev)
! 1135: {
! 1136: struct sd_softc *sd;
! 1137: int part, omask;
! 1138: int64_t size;
! 1139:
! 1140: sd = sdlookup(DISKUNIT(dev));
! 1141: if (sd == NULL)
! 1142: return -1;
! 1143:
! 1144: part = DISKPART(dev);
! 1145: omask = sd->sc_dk.dk_openmask & (1 << part);
! 1146:
! 1147: if (omask == 0 && sdopen(dev, 0, S_IFBLK, NULL) != 0) {
! 1148: size = -1;
! 1149: goto exit;
! 1150: }
! 1151: if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) == 0)
! 1152: size = -1;
! 1153: else if (sd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
! 1154: size = -1;
! 1155: else
! 1156: size = DL_GETPSIZE(&sd->sc_dk.dk_label->d_partitions[part]) *
! 1157: (sd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
! 1158: if (omask == 0 && sdclose(dev, 0, S_IFBLK, NULL) != 0)
! 1159: size = -1;
! 1160:
! 1161: exit:
! 1162: device_unref(&sd->sc_dev);
! 1163: return size;
! 1164: }
! 1165:
! 1166: /* #define SD_DUMP_NOT_TRUSTED if you just want to watch */
! 1167: static struct scsi_xfer sx;
! 1168: static int sddoingadump;
! 1169:
! 1170: /*
! 1171: * dump all of physical memory into the partition specified, starting
! 1172: * at offset 'dumplo' into the partition.
! 1173: */
! 1174: int
! 1175: sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
! 1176: {
! 1177: struct sd_softc *sd; /* disk unit to do the I/O */
! 1178: struct disklabel *lp; /* disk's disklabel */
! 1179: int unit, part;
! 1180: int sectorsize; /* size of a disk sector */
! 1181: daddr64_t nsects; /* number of sectors in partition */
! 1182: daddr64_t sectoff; /* sector offset of partition */
! 1183: int totwrt; /* total number of sectors left to write */
! 1184: int nwrt; /* current number of sectors to write */
! 1185: struct scsi_rw_big cmd; /* write command */
! 1186: struct scsi_xfer *xs; /* ... convenience */
! 1187: int retval;
! 1188:
! 1189: /* Check if recursive dump; if so, punt. */
! 1190: if (sddoingadump)
! 1191: return EFAULT;
! 1192:
! 1193: /* Mark as active early. */
! 1194: sddoingadump = 1;
! 1195:
! 1196: unit = DISKUNIT(dev); /* Decompose unit & partition. */
! 1197: part = DISKPART(dev);
! 1198:
! 1199: /* Check for acceptable drive number. */
! 1200: if (unit >= sd_cd.cd_ndevs || (sd = sd_cd.cd_devs[unit]) == NULL)
! 1201: return ENXIO;
! 1202:
! 1203: /*
! 1204: * XXX Can't do this check, since the media might have been
! 1205: * XXX marked `invalid' by successful unmounting of all
! 1206: * XXX filesystems.
! 1207: */
! 1208: #if 0
! 1209: /* Make sure it was initialized. */
! 1210: if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) != SDEV_MEDIA_LOADED)
! 1211: return ENXIO;
! 1212: #endif
! 1213:
! 1214: /* Convert to disk sectors. Request must be a multiple of size. */
! 1215: lp = sd->sc_dk.dk_label;
! 1216: sectorsize = lp->d_secsize;
! 1217: if ((size % sectorsize) != 0)
! 1218: return EFAULT;
! 1219: totwrt = size / sectorsize;
! 1220: blkno = dbtob(blkno) / sectorsize; /* blkno in DEV_BSIZE units */
! 1221:
! 1222: nsects = DL_GETPSIZE(&lp->d_partitions[part]);
! 1223: sectoff = DL_GETPOFFSET(&lp->d_partitions[part]);
! 1224:
! 1225: /* Check transfer bounds against partition size. */
! 1226: if ((blkno < 0) || ((blkno + totwrt) > nsects))
! 1227: return EINVAL;
! 1228:
! 1229: /* Offset block number to start of partition. */
! 1230: blkno += sectoff;
! 1231:
! 1232: xs = &sx;
! 1233:
! 1234: while (totwrt > 0) {
! 1235: nwrt = totwrt; /* XXX */
! 1236: #ifndef SD_DUMP_NOT_TRUSTED
! 1237: /*
! 1238: * Fill out the scsi command
! 1239: */
! 1240: bzero(&cmd, sizeof(cmd));
! 1241: cmd.opcode = WRITE_BIG;
! 1242: _lto4b(blkno, cmd.addr);
! 1243: _lto2b(nwrt, cmd.length);
! 1244: /*
! 1245: * Fill out the scsi_xfer structure
! 1246: * Note: we cannot sleep as we may be an interrupt
! 1247: * don't use scsi_scsi_cmd() as it may want
! 1248: * to wait for an xs.
! 1249: */
! 1250: bzero(xs, sizeof(sx));
! 1251: xs->flags |= SCSI_AUTOCONF | SCSI_DATA_OUT;
! 1252: xs->sc_link = sd->sc_link;
! 1253: xs->retries = SDRETRIES;
! 1254: xs->timeout = 10000; /* 10000 millisecs for a disk ! */
! 1255: xs->cmd = (struct scsi_generic *)&cmd;
! 1256: xs->cmdlen = sizeof(cmd);
! 1257: xs->resid = nwrt * sectorsize;
! 1258: xs->error = XS_NOERROR;
! 1259: xs->bp = NULL;
! 1260: xs->data = va;
! 1261: xs->datalen = nwrt * sectorsize;
! 1262:
! 1263: /*
! 1264: * Pass all this info to the scsi driver.
! 1265: */
! 1266: retval = (*(sd->sc_link->adapter->scsi_cmd)) (xs);
! 1267: if (retval != COMPLETE)
! 1268: return ENXIO;
! 1269: #else /* SD_DUMP_NOT_TRUSTED */
! 1270: /* Let's just talk about this first... */
! 1271: printf("sd%d: dump addr 0x%x, blk %d\n", unit, va, blkno);
! 1272: delay(500 * 1000); /* half a second */
! 1273: #endif /* SD_DUMP_NOT_TRUSTED */
! 1274:
! 1275: /* update block count */
! 1276: totwrt -= nwrt;
! 1277: blkno += nwrt;
! 1278: va += sectorsize * nwrt;
! 1279: }
! 1280: sddoingadump = 0;
! 1281: return 0;
! 1282: }
! 1283:
! 1284: /*
! 1285: * Copy up to len chars from src to dst, ignoring non-printables.
! 1286: * Must be room for len+1 chars in dst so we can write the NUL.
! 1287: * Does not assume src is NUL-terminated.
! 1288: */
! 1289: void
! 1290: viscpy(u_char *dst, u_char *src, int len)
! 1291: {
! 1292: while (len > 0 && *src != '\0') {
! 1293: if (*src < 0x20 || *src >= 0x80) {
! 1294: src++;
! 1295: continue;
! 1296: }
! 1297: *dst++ = *src++;
! 1298: len--;
! 1299: }
! 1300: *dst = '\0';
! 1301: }
! 1302:
! 1303: /*
! 1304: * Fill out the disk parameter structure. Return SDGP_RESULT_OK if the
! 1305: * structure is correctly filled in, SDGP_RESULT_OFFLINE otherwise. The caller
! 1306: * is responsible for clearing the SDEV_MEDIA_LOADED flag if the structure
! 1307: * cannot be completed.
! 1308: */
! 1309: int
! 1310: sd_get_parms(struct sd_softc *sd, struct disk_parms *dp, int flags)
! 1311: {
! 1312: union scsi_mode_sense_buf *buf = NULL;
! 1313: struct page_rigid_geometry *rigid;
! 1314: struct page_flex_geometry *flex;
! 1315: struct page_reduced_geometry *reduced;
! 1316: u_int32_t heads = 0, sectors = 0, cyls = 0, blksize, ssblksize;
! 1317: u_int16_t rpm = 0;
! 1318:
! 1319: dp->disksize = scsi_size(sd->sc_link, flags, &ssblksize);
! 1320:
! 1321: /*
! 1322: * Many UMASS devices choke when asked about their geometry. Most
! 1323: * don't have a meaningful geometry anyway, so just fake it if
! 1324: * scsi_size() worked.
! 1325: */
! 1326: if ((sd->sc_link->flags & SDEV_UMASS) && (dp->disksize > 0))
! 1327: goto validate; /* N.B. buf will be NULL at validate. */
! 1328:
! 1329: buf = malloc(sizeof(*buf), M_TEMP, M_NOWAIT);
! 1330: if (buf == NULL)
! 1331: goto validate;
! 1332:
! 1333: switch (sd->sc_link->inqdata.device & SID_TYPE) {
! 1334: case T_OPTICAL:
! 1335: /* No more information needed or available. */
! 1336: break;
! 1337:
! 1338: case T_RDIRECT:
! 1339: /* T_RDIRECT supports only PAGE_REDUCED_GEOMETRY (6). */
! 1340: scsi_do_mode_sense(sd->sc_link, PAGE_REDUCED_GEOMETRY, buf,
! 1341: (void **)&reduced, NULL, NULL, &blksize, sizeof(*reduced),
! 1342: flags | SCSI_SILENT, NULL);
! 1343: if (DISK_PGCODE(reduced, PAGE_REDUCED_GEOMETRY)) {
! 1344: if (dp->disksize == 0)
! 1345: dp->disksize = _5btol(reduced->sectors);
! 1346: if (blksize == 0)
! 1347: blksize = _2btol(reduced->bytes_s);
! 1348: }
! 1349: break;
! 1350:
! 1351: default:
! 1352: /*
! 1353: * NOTE: Some devices leave off the last four bytes of
! 1354: * PAGE_RIGID_GEOMETRY and PAGE_FLEX_GEOMETRY mode sense pages.
! 1355: * The only information in those four bytes is RPM information
! 1356: * so accept the page. The extra bytes will be zero and RPM will
! 1357: * end up with the default value of 3600.
! 1358: */
! 1359: rigid = NULL;
! 1360: if (((sd->sc_link->flags & SDEV_ATAPI) == 0) ||
! 1361: ((sd->sc_link->flags & SDEV_REMOVABLE) == 0))
! 1362: scsi_do_mode_sense(sd->sc_link, PAGE_RIGID_GEOMETRY,
! 1363: buf, (void **)&rigid, NULL, NULL, &blksize,
! 1364: sizeof(*rigid) - 4, flags | SCSI_SILENT, NULL);
! 1365: if (DISK_PGCODE(rigid, PAGE_RIGID_GEOMETRY)) {
! 1366: heads = rigid->nheads;
! 1367: cyls = _3btol(rigid->ncyl);
! 1368: rpm = _2btol(rigid->rpm);
! 1369: if (heads * cyls > 0)
! 1370: sectors = dp->disksize / (heads * cyls);
! 1371: } else {
! 1372: scsi_do_mode_sense(sd->sc_link, PAGE_FLEX_GEOMETRY,
! 1373: buf, (void **)&flex, NULL, NULL, &blksize,
! 1374: sizeof(*flex) - 4, flags | SCSI_SILENT, NULL);
! 1375: if (DISK_PGCODE(flex, PAGE_FLEX_GEOMETRY)) {
! 1376: sectors = flex->ph_sec_tr;
! 1377: heads = flex->nheads;
! 1378: cyls = _2btol(flex->ncyl);
! 1379: rpm = _2btol(flex->rpm);
! 1380: if (blksize == 0)
! 1381: blksize = _2btol(flex->bytes_s);
! 1382: if (dp->disksize == 0)
! 1383: dp->disksize = heads * cyls * sectors;
! 1384: }
! 1385: }
! 1386: break;
! 1387: }
! 1388:
! 1389: validate:
! 1390: if (buf)
! 1391: free(buf, M_TEMP);
! 1392:
! 1393: if (dp->disksize == 0)
! 1394: return (SDGP_RESULT_OFFLINE);
! 1395:
! 1396: if (ssblksize > 0)
! 1397: dp->blksize = ssblksize;
! 1398: else
! 1399: dp->blksize = (blksize == 0) ? 512 : blksize;
! 1400:
! 1401: /*
! 1402: * Restrict blksize values to powers of two between 512 and 64k.
! 1403: */
! 1404: switch (dp->blksize) {
! 1405: case 0x200: /* == 512, == DEV_BSIZE on all architectures. */
! 1406: case 0x400:
! 1407: case 0x800:
! 1408: case 0x1000:
! 1409: case 0x2000:
! 1410: case 0x4000:
! 1411: case 0x8000:
! 1412: case 0x10000:
! 1413: break;
! 1414: default:
! 1415: SC_DEBUG(sd->sc_link, SDEV_DB1,
! 1416: ("sd_get_parms: bad blksize: %#x\n", dp->blksize));
! 1417: return (SDGP_RESULT_OFFLINE);
! 1418: }
! 1419:
! 1420: /*
! 1421: * XXX THINK ABOUT THIS!! Using values such that sectors * heads *
! 1422: * cyls is <= disk_size can lead to wasted space. We need a more
! 1423: * careful calculation/validation to make everything work out
! 1424: * optimally.
! 1425: */
! 1426: if (dp->disksize > 0xffffffff && (dp->heads * dp->sectors) < 0xffff) {
! 1427: dp->heads = 511;
! 1428: dp->sectors = 255;
! 1429: cyls = 0;
! 1430: } else {
! 1431: /*
! 1432: * Use standard geometry values for anything we still don't
! 1433: * know.
! 1434: */
! 1435: dp->heads = (heads == 0) ? 255 : heads;
! 1436: dp->sectors = (sectors == 0) ? 63 : sectors;
! 1437: dp->rot_rate = (rpm == 0) ? 3600 : rpm;
! 1438: }
! 1439:
! 1440: dp->cyls = (cyls == 0) ? dp->disksize / (dp->heads * dp->sectors) :
! 1441: cyls;
! 1442:
! 1443: return (SDGP_RESULT_OK);
! 1444: }
! 1445:
! 1446: void
! 1447: sd_flush(struct sd_softc *sd, int flags)
! 1448: {
! 1449: struct scsi_link *sc_link = sd->sc_link;
! 1450: struct scsi_synchronize_cache sync_cmd;
! 1451:
! 1452: /*
! 1453: * If the device is SCSI-2, issue a SYNCHRONIZE CACHE.
! 1454: * We issue with address 0 length 0, which should be
! 1455: * interpreted by the device as "all remaining blocks
! 1456: * starting at address 0". We ignore ILLEGAL REQUEST
! 1457: * in the event that the command is not supported by
! 1458: * the device, and poll for completion so that we know
! 1459: * that the cache has actually been flushed.
! 1460: *
! 1461: * Unless, that is, the device can't handle the SYNCHRONIZE CACHE
! 1462: * command, as indicated by our quirks flags.
! 1463: *
! 1464: * XXX What about older devices?
! 1465: */
! 1466: if (SCSISPC(sc_link->inqdata.version) >= 2 &&
! 1467: (sc_link->quirks & SDEV_NOSYNCCACHE) == 0) {
! 1468: bzero(&sync_cmd, sizeof(sync_cmd));
! 1469: sync_cmd.opcode = SYNCHRONIZE_CACHE;
! 1470:
! 1471: if (scsi_scsi_cmd(sc_link,
! 1472: (struct scsi_generic *)&sync_cmd, sizeof(sync_cmd),
! 1473: NULL, 0, SDRETRIES, 100000, NULL,
! 1474: flags|SCSI_IGNORE_ILLEGAL_REQUEST))
! 1475: printf("%s: WARNING: cache synchronization failed\n",
! 1476: sd->sc_dev.dv_xname);
! 1477: else
! 1478: sd->flags |= SDF_FLUSHING;
! 1479: }
! 1480: }
! 1481:
! 1482: /*
! 1483: * Remove unprocessed buffers from queue.
! 1484: */
! 1485: void
! 1486: sd_kill_buffers(struct sd_softc *sd)
! 1487: {
! 1488: struct buf *dp, *bp;
! 1489: int s;
! 1490:
! 1491: s = splbio();
! 1492: for (dp = &sd->buf_queue; (bp = dp->b_actf) != NULL; ) {
! 1493: dp->b_actf = bp->b_actf;
! 1494:
! 1495: bp->b_error = ENXIO;
! 1496: bp->b_flags |= B_ERROR;
! 1497: biodone(bp);
! 1498: }
! 1499: splx(s);
! 1500: }
CVSweb