int sdactivate(struct device *self, int act) { struct sd_softc *sc = (struct sd_softc *)self; int rv = 0; switch (act) { case DVACT_SUSPEND: /* * Stop the disk. Stopping the disk should flush the * cache, but we are paranoid so we flush the cache * first. */ if ((sc->flags & SDF_DIRTY) != 0) sd_flush(sc, SCSI_AUTOCONF); scsi_start(sc->sc_link, SSS_STOP, SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_AUTOCONF); break; case DVACT_RESUME: scsi_start(sc->sc_link, SSS_START, SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_AUTOCONF); break; case DVACT_DEACTIVATE: sc->flags |= SDF_DYING; scsi_xsh_del(&sc->sc_xsh); break; } return (rv); }
/* * Close the device. Only called if we are the last occurrence of an open * device. Convenient now but usually a pain. */ int sdclose(dev_t dev, int flag, int fmt, struct proc *p) { struct sd_softc *sc; int part = DISKPART(dev); int error; sc = sdlookup(DISKUNIT(dev)); if (sc == NULL) return (ENXIO); if (sc->flags & SDF_DYING) { device_unref(&sc->sc_dev); return (ENXIO); } if ((error = sdlock(sc)) != 0) { device_unref(&sc->sc_dev); return (error); } switch (fmt) { case S_IFCHR: sc->sc_dk.dk_copenmask &= ~(1 << part); break; case S_IFBLK: sc->sc_dk.dk_bopenmask &= ~(1 << part); break; } sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; if (sc->sc_dk.dk_openmask == 0) { if ((sc->flags & SDF_DIRTY) != 0) sd_flush(sc, 0); if ((sc->sc_link->flags & SDEV_REMOVABLE) != 0) scsi_prevent(sc->sc_link, PR_ALLOW, SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY | SCSI_SILENT); sc->sc_link->flags &= ~(SDEV_OPEN | SDEV_MEDIA_LOADED); if (sc->sc_link->flags & SDEV_EJECTING) { scsi_start(sc->sc_link, SSS_STOP|SSS_LOEJ, 0); sc->sc_link->flags &= ~SDEV_EJECTING; } timeout_del(&sc->sc_timeout); } sdunlock(sc); device_unref(&sc->sc_dev); return 0; }
void sd_shutdown(void *arg) { struct sd_softc *sc = (struct sd_softc *)arg; /* * If the disk cache needs to be flushed, and the disk supports * it, flush it. We're cold at this point, so we poll for * completion. */ if ((sc->flags & SDF_DIRTY) != 0) sd_flush(sc, SCSI_AUTOCONF); }
int sdactivate(struct device *self, int act) { struct sd_softc *sc = (struct sd_softc *)self; int rv = 0; switch (act) { case DVACT_SUSPEND: /* * We flush the cache, since we our next step before * DVACT_POWERDOWN might be a hibernate operation. */ if ((sc->flags & SDF_DIRTY) != 0) sd_flush(sc, SCSI_AUTOCONF); break; case DVACT_POWERDOWN: /* * Stop the disk. Stopping the disk should flush the * cache, but we are paranoid so we flush the cache * first. */ if ((sc->flags & SDF_DIRTY) != 0) sd_flush(sc, SCSI_AUTOCONF); if (boothowto & RB_POWERDOWN) scsi_start(sc->sc_link, SSS_STOP, SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_AUTOCONF); break; case DVACT_RESUME: scsi_start(sc->sc_link, SSS_START, SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_AUTOCONF); break; case DVACT_DEACTIVATE: sc->flags |= SDF_DYING; scsi_xsh_del(&sc->sc_xsh); break; } return (rv); }
/* * Close the device. Only called if we are the last occurrence of an open * device. Convenient now but usually a pain. */ int sdclose(dev_t dev, int flag, int fmt, struct proc *p) { struct sd_softc *sc; int part = DISKPART(dev); sc = sdlookup(DISKUNIT(dev)); if (sc == NULL) return (ENXIO); if (sc->flags & SDF_DYING) { device_unref(&sc->sc_dev); return (ENXIO); } disk_lock_nointr(&sc->sc_dk); disk_closepart(&sc->sc_dk, part, fmt); if (sc->sc_dk.dk_openmask == 0) { if ((sc->flags & SDF_DIRTY) != 0) sd_flush(sc, 0); if ((sc->sc_link->flags & SDEV_REMOVABLE) != 0) scsi_prevent(sc->sc_link, PR_ALLOW, SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY | SCSI_SILENT); sc->sc_link->flags &= ~(SDEV_OPEN | SDEV_MEDIA_LOADED); if (sc->sc_link->flags & SDEV_EJECTING) { scsi_start(sc->sc_link, SSS_STOP|SSS_LOEJ, 0); sc->sc_link->flags &= ~SDEV_EJECTING; } timeout_del(&sc->sc_timeout); scsi_xsh_del(&sc->sc_xsh); } disk_unlock(&sc->sc_dk); device_unref(&sc->sc_dev); return 0; }
void sd_shutdown(void *arg) { struct sd_softc *sc = (struct sd_softc *)arg; /* * If the disk cache needs to be flushed, and the disk supports * it, flush it. We're cold at this point, so we poll for * completion. */ if ((sc->flags & SDF_DIRTY) != 0) sd_flush(sc, SCSI_AUTOCONF); if (boothowto & RB_POWERDOWN) scsi_start(sc->sc_link, SSS_STOP, SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_AUTOCONF); /* * There should be no outstanding IO at this point, but lets stop * it just in case. */ timeout_del(&sc->sc_timeout); scsi_xsh_del(&sc->sc_xsh); }
/* * Perform special action on behalf of the user * Knows about the internals of this device */ int sdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct sd_softc *sc; struct disklabel *lp; int error = 0; int part = DISKPART(dev); sc = sdlookup(DISKUNIT(dev)); if (sc == NULL) return (ENXIO); if (sc->flags & SDF_DYING) { device_unref(&sc->sc_dev); return (ENXIO); } SC_DEBUG(sc->sc_link, SDEV_DB2, ("sdioctl 0x%lx\n", cmd)); /* * If the device is not valid.. abandon ship */ if ((sc->sc_link->flags & SDEV_MEDIA_LOADED) == 0) { switch (cmd) { case DIOCLOCK: case DIOCEJECT: case SCIOCIDENTIFY: case SCIOCCOMMAND: case SCIOCDEBUG: if (part == RAW_PART) break; /* FALLTHROUGH */ default: if ((sc->sc_link->flags & SDEV_OPEN) == 0) { error = ENODEV; goto exit; } else { error = EIO; goto exit; } } } switch (cmd) { case DIOCRLDINFO: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); sdgetdisklabel(dev, sc, lp, 0); bcopy(lp, sc->sc_dk.dk_label, sizeof(*lp)); free(lp, M_TEMP); goto exit; case DIOCGPDINFO: sdgetdisklabel(dev, sc, (struct disklabel *)addr, 1); goto exit; case DIOCGDINFO: *(struct disklabel *)addr = *(sc->sc_dk.dk_label); goto exit; case DIOCGPART: ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label; ((struct partinfo *)addr)->part = &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)]; goto exit; case DIOCWDINFO: case DIOCSDINFO: if ((flag & FWRITE) == 0) { error = EBADF; goto exit; } if ((error = disk_lock(&sc->sc_dk)) != 0) goto exit; error = setdisklabel(sc->sc_dk.dk_label, (struct disklabel *)addr, sc->sc_dk.dk_openmask); if (error == 0) { if (cmd == DIOCWDINFO) error = writedisklabel(DISKLABELDEV(dev), sdstrategy, sc->sc_dk.dk_label); } disk_unlock(&sc->sc_dk); goto exit; case DIOCLOCK: error = scsi_prevent(sc->sc_link, (*(int *)addr) ? PR_PREVENT : PR_ALLOW, 0); goto exit; case MTIOCTOP: if (((struct mtop *)addr)->mt_op != MTOFFL) { error = EIO; goto exit; } /* FALLTHROUGH */ case DIOCEJECT: if ((sc->sc_link->flags & SDEV_REMOVABLE) == 0) { error = ENOTTY; goto exit; } sc->sc_link->flags |= SDEV_EJECTING; goto exit; case DIOCINQ: error = scsi_do_ioctl(sc->sc_link, cmd, addr, flag); if (error == ENOTTY) error = sd_ioctl_inquiry(sc, (struct dk_inquiry *)addr); goto exit; case DIOCSCACHE: if (!ISSET(flag, FWRITE)) { error = EBADF; goto exit; } /* FALLTHROUGH */ case DIOCGCACHE: error = sd_ioctl_cache(sc, cmd, (struct dk_cache *)addr); goto exit; case DIOCCACHESYNC: if (!ISSET(flag, FWRITE)) { error = EBADF; goto exit; } if ((sc->flags & SDF_DIRTY) != 0 || *(int *)addr != 0) error = sd_flush(sc, 0); return (error); default: if (part != RAW_PART) { error = ENOTTY; goto exit; } error = scsi_do_ioctl(sc->sc_link, cmd, addr, flag); } exit: device_unref(&sc->sc_dev); return (error); }