diff --git a/sys/dev/files.dev b/sys/dev/files.dev index 43c259d2d52e..0e53d67500c2 100644 --- a/sys/dev/files.dev +++ b/sys/dev/files.dev @@ -1,4 +1,4 @@ -# $NetBSD: files.dev,v 1.1 2015/08/21 02:18:18 uebayasi Exp $ +# $NetBSD: files.dev,v 1.2 2016/12/10 10:26:38 mlelstv Exp $ file dev/bio.c bio needs-flag file dev/ccd.c ccd @@ -6,7 +6,7 @@ file dev/cgd.c cgd file dev/cgd_crypto.c cgd file dev/clock_subr.c kern # XXX file dev/clockctl.c clockctl -file dev/dksubr.c cgd | xbd | ccd | raid | dm | ld +file dev/dksubr.c cgd | xbd | ccd | raid | dm | ld | sd | cd file dev/dkwedge/dk.c kern # XXX file dev/dkwedge/dkwedge_apple.c dkwedge_method_apple file dev/dkwedge/dkwedge_bsdlabel.c dkwedge_method_bsdlabel diff --git a/sys/dev/scsipi/cd.c b/sys/dev/scsipi/cd.c index bfd9d4676c41..d6923b45aa50 100644 --- a/sys/dev/scsipi/cd.c +++ b/sys/dev/scsipi/cd.c @@ -1,4 +1,4 @@ -/* $NetBSD: cd.c,v 1.333 2016/11/20 15:37:19 mlelstv Exp $ */ +/* $NetBSD: cd.c,v 1.334 2016/12/10 10:26:38 mlelstv Exp $ */ /*- * Copyright (c) 1998, 2001, 2003, 2004, 2005, 2008 The NetBSD Foundation, @@ -50,7 +50,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: cd.c,v 1.333 2016/11/20 15:37:19 mlelstv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cd.c,v 1.334 2016/12/10 10:26:38 mlelstv Exp $"); #include #include @@ -114,22 +114,26 @@ struct cd_formatted_toc { }; struct cdbounce { - struct buf *obp; /* original buf */ - int doff; /* byte offset in orig. buf */ - int soff; /* byte offset in bounce buf */ - int resid; /* residual i/o in orig. buf */ - int bcount; /* actual obp bytes in bounce */ + struct buf *obp; /* original buf */ + struct buf *lbp; /* first buffer */ + struct buf *rbp; /* second buffer */ + int lerr; /* error returned for first buffer */ + int rerr; /* error returned for second buffer */ + int head; /* bytes skipped at the start */ + int lcount; /* bytes copied to first buffer */ + int rcount; /* bytes copied to second buffer */ }; static void cdstart(struct scsipi_periph *); static void cdrestart(void *); static void cdminphys(struct buf *); -static void cdgetdefaultlabel(struct cd_softc *, struct cd_formatted_toc *, - struct disklabel *); -static void cdgetdisklabel(struct cd_softc *); static void cddone(struct scsipi_xfer *, int); -static void cdbounce(struct buf *); static int cd_interpret_sense(struct scsipi_xfer *); +static int cd_diskstart(device_t, struct buf *); +static void cd_iosize(device_t, int *); +static int cd_lastclose(device_t); +static int cd_firstopen(device_t, dev_t, int, int); +static void cd_label(device_t, struct disklabel *); static u_long cd_size(struct cd_softc *, int); static int cd_play(struct cd_softc *, int, int); static int cd_play_tracks(struct cd_softc *, struct cd_formatted_toc *, @@ -230,8 +234,14 @@ const struct cdevsw cd_cdevsw = { }; static struct dkdriver cddkdriver = { + .d_open = cdopen, + .d_close = cdclose, .d_strategy = cdstrategy, - .d_minphys = cdminphys + .d_minphys = cdminphys, + .d_diskstart = cd_diskstart, + .d_firstopen = cd_firstopen, + .d_lastclose = cd_lastclose, + .d_label = cd_label, }; static const struct scsipi_periphsw cd_switch = { @@ -262,20 +272,37 @@ static void cdattach(device_t parent, device_t self, void *aux) { struct cd_softc *cd = device_private(self); + struct dk_softc *dksc = &cd->sc_dksc; struct scsipibus_attach_args *sa = aux; struct scsipi_periph *periph = sa->sa_periph; + int dtype; SC_DEBUG(periph, SCSIPI_DB2, ("cdattach: ")); - cd->sc_dev = self; + switch (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sa->sa_periph))) { + case SCSIPI_BUSTYPE_SCSI: + dtype = DKTYPE_SCSI; + if (periph->periph_version == 0) + cd->flags |= CDF_ANCIENT; + break; + case SCSIPI_BUSTYPE_ATAPI: + dtype = DKTYPE_ATAPI; + break; + default: + dtype = DKTYPE_UNKNOWN; + break; + } - mutex_init(&cd->sc_lock, MUTEX_DEFAULT, IPL_NONE); + /* + * Initialize and attach the disk structure. + */ + dk_init(dksc, self, dtype); + disk_init(&dksc->sc_dkdev, dksc->sc_xname, &cddkdriver); - if (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sa->sa_periph)) == - SCSIPI_BUSTYPE_SCSI && periph->periph_version == 0) - cd->flags |= CDF_ANCIENT; + dk_attach(dksc); + disk_attach(&dksc->sc_dkdev); - bufq_alloc(&cd->buf_queue, "disksort", BUFQ_SORT_RAWBLOCK); + bufq_alloc(&dksc->sc_bufq, "disksort", BUFQ_SORT_RAWBLOCK); callout_init(&cd->sc_callout, 0); @@ -284,7 +311,7 @@ cdattach(device_t parent, device_t self, void *aux) */ cd->sc_periph = periph; - periph->periph_dev = cd->sc_dev; + periph->periph_dev = dksc->sc_dev; periph->periph_switch = &cd_switch; /* @@ -296,17 +323,8 @@ cdattach(device_t parent, device_t self, void *aux) SCSIPI_CHAN_MAX_PERIPH(periph->periph_channel); periph->periph_flags |= PERIPH_GROW_OPENINGS; - /* - * Initialize and attach the disk structure. - */ - disk_init(&cd->sc_dk, device_xname(cd->sc_dev), &cddkdriver); - disk_attach(&cd->sc_dk); - - aprint_normal("\n"); aprint_naive("\n"); - - rnd_attach_source(&cd->rnd_source, device_xname(cd->sc_dev), - RND_TYPE_DISK, RND_FLAG_DEFAULT); + aprint_normal("\n"); if (!pmf_device_register(self, NULL, NULL)) aprint_error_dev(self, "couldn't establish power handler\n"); @@ -316,16 +334,18 @@ static int cddetach(device_t self, int flags) { struct cd_softc *cd = device_private(self); + struct dk_softc *dksc = &cd->sc_dksc; struct scsipi_periph *periph = cd->sc_periph; struct scsipi_channel *chan = periph->periph_channel; - int bmaj, cmaj, i, mn; + int bmaj, cmaj, i, mn, rc; - if (cd->sc_dk.dk_openmask != 0 && (flags & DETACH_FORCE) == 0) - return EBUSY; + if ((rc = disk_begindetach(&dksc->sc_dkdev, cd_lastclose, self, flags)) != 0) + return rc; /* locate the major number */ bmaj = bdevsw_lookup_major(&cd_bdevsw); cmaj = cdevsw_lookup_major(&cd_cdevsw); + /* Nuke the vnodes for any open instances */ for (i = 0; i < MAXPARTITIONS; i++) { mn = CDMINOR(device_unit(self), i); @@ -336,30 +356,112 @@ cddetach(device_t self, int flags) /* kill any pending restart */ callout_stop(&cd->sc_callout); - mutex_enter(chan_mtx(chan)); - - /* Kill off any queued buffers. */ - bufq_drain(cd->buf_queue); + dk_drain(dksc); /* Kill off any pending commands. */ + mutex_enter(chan_mtx(chan)); scsipi_kill_pending(cd->sc_periph); - mutex_exit(chan_mtx(chan)); - bufq_free(cd->buf_queue); - - mutex_destroy(&cd->sc_lock); + bufq_free(dksc->sc_bufq); /* Detach from the disk list. */ - disk_detach(&cd->sc_dk); - disk_destroy(&cd->sc_dk); + disk_detach(&dksc->sc_dkdev); + disk_destroy(&dksc->sc_dkdev); - /* Unhook the entropy source. */ - rnd_detach_source(&cd->rnd_source); + dk_detach(dksc); + + callout_destroy(&cd->sc_callout); + + pmf_device_deregister(self); return (0); } +/* + * Serialized by caller + */ +static int +cd_firstopen(device_t self, dev_t dev, int flag, int fmt) +{ + struct cd_softc *cd = device_private(self); + struct scsipi_periph *periph = cd->sc_periph; + struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter; + int error, silent; + int part; + + part = CDPART(dev); + + error = scsipi_adapter_addref(adapt); + if (error) + return error; + + if ((part == RAW_PART && fmt == S_IFCHR) || (flag & FSILENT)) + silent = XS_CTL_SILENT; + else + silent = 0; + + /* make cdclose() loud again */ + cd->flags &= ~CDF_EJECTED; + + /* Check that it is still responding and ok. */ + error = scsipi_test_unit_ready(periph, + XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE | + XS_CTL_SILENT); + + /* + * Start the pack spinning if necessary. Always allow the + * raw parition to be opened, for raw IOCTLs. Data transfers + * will check for SDEV_MEDIA_LOADED. + */ + if (error == EIO) { + error = scsipi_start(periph, SSS_START, silent); + if (error == EINVAL) + error = EIO; + } + if (error) + goto bad; + + /* Lock the pack in. */ + error = scsipi_prevent(periph, SPAMR_PREVENT_DT, + XS_CTL_IGNORE_ILLEGAL_REQUEST | + XS_CTL_IGNORE_MEDIA_CHANGE); + SC_DEBUG(periph, SCSIPI_DB1, + ("cdopen: scsipi_prevent, error=%d\n", error)); + if (error) + goto bad; + + if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) { + int param_error; + + /* Load the physical device parameters. */ + param_error = cd_get_parms(cd, 0); + if (param_error == CDGP_RESULT_OFFLINE) { + error = ENXIO; + goto bad2; + } + periph->periph_flags |= PERIPH_MEDIA_LOADED; + + SC_DEBUG(periph, SCSIPI_DB3, ("Params loaded ")); + + cd_set_geometry(cd); + } + + periph->periph_flags |= PERIPH_OPEN; + return 0; + +bad2: + scsipi_prevent(periph, SPAMR_ALLOW, + XS_CTL_IGNORE_ILLEGAL_REQUEST | + XS_CTL_IGNORE_MEDIA_CHANGE | + XS_CTL_SILENT); + +bad: + scsipi_adapter_delref(adapt); + return error; + +} + /* * open the device. Make sure the partition info is a up-to-date as can be. */ @@ -367,152 +469,72 @@ static int cdopen(dev_t dev, int flag, int fmt, struct lwp *l) { struct cd_softc *cd; + struct dk_softc *dksc; struct scsipi_periph *periph; - struct scsipi_adapter *adapt; - int part; + int unit, part; int error; - int rawpart; - cd = device_lookup_private(&cd_cd, CDUNIT(dev)); + unit = CDUNIT(dev); + cd = device_lookup_private(&cd_cd, unit); if (cd == NULL) return (ENXIO); + dksc = &cd->sc_dksc; periph = cd->sc_periph; - adapt = periph->periph_channel->chan_adapter; part = CDPART(dev); SC_DEBUG(periph, SCSIPI_DB1, - ("cdopen: dev=0x%"PRIu64" (unit %"PRIu32" (of %d), partition %"PRId32")\n",dev, - CDUNIT(dev), cd_cd.cd_ndevs, CDPART(dev))); + ("cdopen: dev=0x%"PRIu64" (unit %"PRIu32" (of %d), partition %d)\n", + dev, unit, cd_cd.cd_ndevs, CDPART(dev))); /* - * If this is the first open of this device, add a reference - * to the adapter. + * If any partition is open, but the disk has been invalidated, + * disallow further opens of non-raw partition */ - if (cd->sc_dk.dk_openmask == 0 && - (error = scsipi_adapter_addref(adapt)) != 0) - return (error); - - mutex_enter(&cd->sc_lock); - - rawpart = (part == RAW_PART && fmt == S_IFCHR); - if ((periph->periph_flags & PERIPH_OPEN) != 0) { - /* - * If any partition is open, but the disk has been invalidated, - * disallow further opens. - */ - if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 && - !rawpart) { - error = EIO; - goto bad3; - } - } else { - /* Check that it is still responding and ok. */ - error = scsipi_test_unit_ready(periph, - XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE | - XS_CTL_SILENT); - - /* - * Start the pack spinning if necessary. Always allow the - * raw parition to be opened, for raw IOCTLs. Data transfers - * will check for SDEV_MEDIA_LOADED. - */ - if (error == EIO) { - int error2; - int silent; - - if (rawpart) - silent = XS_CTL_SILENT; - else - silent = 0; - - error2 = scsipi_start(periph, SSS_START, silent); - switch (error2) { - case 0: - error = 0; - break; - case EIO: - case EINVAL: - break; - default: - error = error2; - break; - } - } - if (error) { - if (rawpart) - goto out; - goto bad3; - } - - periph->periph_flags |= PERIPH_OPEN; - - /* Lock the pack in. */ - error = scsipi_prevent(periph, SPAMR_PREVENT_DT, - XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE); - SC_DEBUG(periph, SCSIPI_DB1, - ("cdopen: scsipi_prevent, error=%d\n", error)); - if (error) { - if (rawpart) - goto out; - goto bad; - } - - if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) { - /* Load the physical device parameters. */ - if (cd_get_parms(cd, 0) != 0) { - if (rawpart) - goto out; - error = ENXIO; - goto bad; - } - periph->periph_flags |= PERIPH_MEDIA_LOADED; - SC_DEBUG(periph, SCSIPI_DB3, ("Params loaded ")); - - /* Fabricate a disk label. */ - cdgetdisklabel(cd); - SC_DEBUG(periph, SCSIPI_DB3, ("Disklabel fabricated ")); - - cd_set_geometry(cd); - } + if ((periph->periph_flags & (PERIPH_OPEN | PERIPH_MEDIA_LOADED)) == + PERIPH_OPEN) { + if (part != RAW_PART || fmt != S_IFCHR) + return EIO; } - /* Check that the partition exists. */ - if (part != RAW_PART && - (part >= cd->sc_dk.dk_label->d_npartitions || - cd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { - error = ENXIO; - goto bad; - } - -out: /* Insure only one open at a time. */ - switch (fmt) { - case S_IFCHR: - cd->sc_dk.dk_copenmask |= (1 << part); - break; - case S_IFBLK: - cd->sc_dk.dk_bopenmask |= (1 << part); - break; - } - cd->sc_dk.dk_openmask = - cd->sc_dk.dk_copenmask | cd->sc_dk.dk_bopenmask; + error = dk_open(dksc, dev, flag, fmt, l); SC_DEBUG(periph, SCSIPI_DB3, ("open complete\n")); - mutex_exit(&cd->sc_lock); - return (0); -bad: - if (cd->sc_dk.dk_openmask == 0) { - scsipi_prevent(periph, SPAMR_ALLOW, - XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE); - periph->periph_flags &= ~PERIPH_OPEN; - } + return error; +} -bad3: - mutex_exit(&cd->sc_lock); - if (cd->sc_dk.dk_openmask == 0) - scsipi_adapter_delref(adapt); - return (error); +/* + * Serialized by caller + */ +static int +cd_lastclose(device_t self) +{ + struct cd_softc *cd = device_private(self); + struct scsipi_periph *periph = cd->sc_periph; + struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter; + int silent; + + if (cd->flags & CDF_EJECTED) + silent = XS_CTL_SILENT; + else + silent = 0; + + cdcachesync(periph, silent); + + scsipi_wait_drain(periph); + + scsipi_prevent(periph, SPAMR_ALLOW, + XS_CTL_IGNORE_ILLEGAL_REQUEST | + XS_CTL_IGNORE_NOT_READY | + XS_CTL_SILENT); + periph->periph_flags &= ~PERIPH_OPEN; + + scsipi_wait_drain(periph); + + scsipi_adapter_delref(adapt); + + return 0; } /* @@ -522,49 +544,149 @@ bad3: static int cdclose(dev_t dev, int flag, int fmt, struct lwp *l) { - struct cd_softc *cd = device_lookup_private(&cd_cd, CDUNIT(dev)); - struct scsipi_periph *periph = cd->sc_periph; - struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter; - int part = CDPART(dev); - int silent = 0; + struct cd_softc *cd; + struct dk_softc *dksc; + int unit; - if (part == RAW_PART && ((cd->sc_dk.dk_label->d_npartitions == 0) || - (part < cd->sc_dk.dk_label->d_npartitions && - cd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED))) - silent = XS_CTL_SILENT; + unit = CDUNIT(dev); + cd = device_lookup_private(&cd_cd, unit); + dksc = &cd->sc_dksc; - mutex_enter(&cd->sc_lock); + return dk_close(dksc, dev, flag, fmt, l); +} - switch (fmt) { - case S_IFCHR: - cd->sc_dk.dk_copenmask &= ~(1 << part); - break; - case S_IFBLK: - cd->sc_dk.dk_bopenmask &= ~(1 << part); - break; - } - cd->sc_dk.dk_openmask = - cd->sc_dk.dk_copenmask | cd->sc_dk.dk_bopenmask; +static void +cd_bounce_buffer_done(struct buf *bp) +{ + struct cdbounce *bounce = bp->b_private; + struct buf *obp = bounce->obp; - if (cd->sc_dk.dk_openmask == 0) { - /* synchronise caches on last close */ - cdcachesync(periph, silent); - - /* drain outstanding calls */ - scsipi_wait_drain(periph); - - scsipi_prevent(periph, SPAMR_ALLOW, - XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE | - XS_CTL_IGNORE_NOT_READY | silent); - periph->periph_flags &= ~PERIPH_OPEN; - - scsipi_wait_drain(periph); - - scsipi_adapter_delref(adapt); + if (bp == bounce->lbp) { + if ((bounce->lerr = bp->b_error) == 0) + memcpy(obp->b_data, (char *)bp->b_data + bounce->head, bounce->lcount); + bounce->lbp = NULL; } - mutex_exit(&cd->sc_lock); - return (0); + if (bp == bounce->rbp) { + if ((bounce->rerr = bp->b_error) == 0) + memcpy((char *)obp->b_data + bounce->lcount, bp->b_data, bounce->rcount); + bounce->rbp = NULL; + } + + free(bp->b_data, M_DEVBUF); + putiobuf(bp); + + if (bounce->lbp != NULL || bounce->rbp != NULL) + return; + + obp->b_error = bounce->rerr; + if (bounce->lerr) + obp->b_error = bounce->lerr; + + obp->b_resid = 0; + if (obp->b_error) + obp->b_resid = obp->b_bcount; + + free(bounce, M_DEVBUF); + biodone(obp); +} + +static int +cd_make_bounce_buffer(struct cd_softc *cd, struct buf *bp, daddr_t blkno, int count, struct buf **nbpp, void *priv) +{ + struct buf *nbp; + + /* We don't support bouncing writes */ + if ((bp->b_flags & B_READ) == 0) + return EACCES; /* XXX */ + + nbp = getiobuf(NULL, false); + if (nbp == NULL) + return ENOMEM; + + nbp->b_data = malloc(count, M_DEVBUF, M_NOWAIT); + if (nbp->b_data == NULL) { + putiobuf(nbp); + return ENOMEM; + } + + /* Set up the IOP to the bounce buffer */ + nbp->b_error = 0; + nbp->b_dev = bp->b_dev; + nbp->b_proc = bp->b_proc; + nbp->b_bcount = count; + nbp->b_bufsize = count; + nbp->b_blkno = blkno; + nbp->b_flags = bp->b_flags | B_READ; + nbp->b_oflags = bp->b_oflags; + nbp->b_cflags = bp->b_cflags; + nbp->b_iodone = cd_bounce_buffer_done; + nbp->b_private = priv; + + BIO_COPYPRIO(nbp, bp); + + *nbpp = nbp; + return 0; +} + +static int +cd_make_bounce(struct cd_softc *cd, struct buf *bp, struct cdbounce **bouncep) +{ + struct dk_softc *dksc = &cd->sc_dksc; + unsigned secsize = dksc->sc_dkdev.dk_geom.dg_secsize; + struct cdbounce *bounce; + int bps, nblks, skip, total, count; + daddr_t blkno; + struct buf *lbp, *rbp; + int error; + + bounce = malloc(sizeof(struct cdbounce), M_DEVBUF, M_NOWAIT|M_ZERO); + if (bounce == NULL) + return ENOMEM; + + bps = howmany(secsize, DEV_BSIZE); + nblks = howmany(bp->b_bcount, DEV_BSIZE); + + skip = bp->b_blkno % bps; + + blkno = bp->b_blkno - skip; + total = roundup(nblks + skip, bps) * DEV_BSIZE; + + count = total; + cd_iosize(dksc->sc_dev, &count); + + bounce->head = skip * DEV_BSIZE; + bounce->lcount = count - bounce->head; + bounce->rcount = bp->b_bcount - bounce->lcount; + + error = cd_make_bounce_buffer(cd, bp, blkno, count, &lbp, bounce); + if (error) + goto bad; + + blkno += howmany(count, DEV_BSIZE); + count = total - count; + + if (count > 0) { + bounce->lbp->b_private = bounce; + error = cd_make_bounce_buffer(cd, bp, blkno, count, &rbp, bounce); + if (error) { + putiobuf(bounce->lbp); + goto bad; + } + } else + rbp = NULL; + + bounce->obp = bp; + bounce->lbp = lbp; + bounce->rbp = rbp; + + *bouncep = bounce; + + return 0; + +bad: + free(bounce, M_DEVBUF); + return error; } /* @@ -576,345 +698,220 @@ static void cdstrategy(struct buf *bp) { struct cd_softc *cd = device_lookup_private(&cd_cd,CDUNIT(bp->b_dev)); - struct disklabel *lp; + struct dk_softc *dksc = &cd->sc_dksc; struct scsipi_periph *periph = cd->sc_periph; - struct scsipi_channel *chan = periph->periph_channel; - daddr_t blkno; + int error; SC_DEBUG(cd->sc_periph, SCSIPI_DB2, ("cdstrategy ")); SC_DEBUG(cd->sc_periph, SCSIPI_DB1, ("%d bytes @ blk %" PRId64 "\n", bp->b_bcount, bp->b_blkno)); + /* * If the device has been made invalid, error out * maybe the media changed */ if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) { if (periph->periph_flags & PERIPH_OPEN) - bp->b_error = EIO; + error = EIO; else - bp->b_error = ENODEV; - goto done; - } - - lp = cd->sc_dk.dk_label; - - /* - * The transfer must be a whole number of blocks, offset must not - * be negative. - */ - if ((bp->b_bcount % lp->d_secsize) != 0 || - bp->b_blkno < 0 ) { - bp->b_error = EINVAL; - goto done; - } - /* - * If it's a null transfer, return immediately - */ - if (bp->b_bcount == 0) - goto done; - - /* - * Do bounds checking, adjust transfer. if error, process. - * If end of partition, just return. - */ - if (CDPART(bp->b_dev) == RAW_PART) { - if (bounds_check_with_mediasize(bp, DEV_BSIZE, - cd->params.disksize512) <= 0) - goto done; - } else { - if (bounds_check_with_label(&cd->sc_dk, bp, - (cd->flags & (CDF_WLABEL|CDF_LABELLING)) != 0) <= 0) - goto done; + error = ENODEV; + goto bad; } /* - * Now convert the block number to absolute and put it in - * terms of the device's logical block size. + * If label and device don't agree in sector size use a bounce buffer */ - blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); - if (CDPART(bp->b_dev) != RAW_PART) - blkno += lp->d_partitions[CDPART(bp->b_dev)].p_offset; + if (dksc->sc_dkdev.dk_label->d_secsize != dksc->sc_dkdev.dk_geom.dg_secsize) { + struct cdbounce *bounce; - bp->b_rawblkno = blkno; + error = cd_make_bounce(cd, bp, &bounce); + if (error) + goto bad; - /* - * If the disklabel sector size does not match the device - * sector size we may need to do some extra work. - */ - if (lp->d_secsize != cd->params.blksize) { + dk_strategy(dksc, bounce->lbp); + if (bounce->rbp != NULL) + dk_strategy(dksc, bounce->rbp); - /* - * If the xfer is not a multiple of the device block size - * or it is not block aligned, we need to bounce it. - */ - if ((bp->b_bcount % cd->params.blksize) != 0 || - ((blkno * lp->d_secsize) % cd->params.blksize) != 0) { - struct cdbounce *bounce; - struct buf *nbp; - long count; - - if ((bp->b_flags & B_READ) == 0) { - - /* XXXX We don't support bouncing writes. */ - bp->b_error = EACCES; - goto done; - } - - bounce = malloc(sizeof(*bounce), M_DEVBUF, M_NOWAIT); - if (!bounce) { - /* No memory -- fail the iop. */ - bp->b_error = ENOMEM; - goto done; - } - - bounce->obp = bp; - bounce->resid = bp->b_bcount; - bounce->doff = 0; - count = ((blkno * lp->d_secsize) % cd->params.blksize); - bounce->soff = count; - count += bp->b_bcount; - count = roundup(count, cd->params.blksize); - bounce->bcount = bounce->resid; - if (count > MAXPHYS) { - bounce->bcount = MAXPHYS - bounce->soff; - count = MAXPHYS; - } - - blkno = ((blkno * lp->d_secsize) / cd->params.blksize); - nbp = getiobuf(NULL, false); - if (!nbp) { - /* No memory -- fail the iop. */ - free(bounce, M_DEVBUF); - bp->b_error = ENOMEM; - goto done; - } - nbp->b_data = malloc(count, M_DEVBUF, M_NOWAIT); - if (!nbp->b_data) { - /* No memory -- fail the iop. */ - free(bounce, M_DEVBUF); - putiobuf(nbp); - bp->b_error = ENOMEM; - goto done; - } - - /* Set up the IOP to the bounce buffer. */ - nbp->b_error = 0; - nbp->b_proc = bp->b_proc; - nbp->b_bcount = count; - nbp->b_bufsize = count; - nbp->b_rawblkno = blkno; - nbp->b_flags = bp->b_flags | B_READ; - nbp->b_oflags = bp->b_oflags; - nbp->b_cflags = bp->b_cflags; - nbp->b_iodone = cdbounce; - - /* store bounce state in b_private and use new buf */ - nbp->b_private = bounce; - - BIO_COPYPRIO(nbp, bp); - - bp = nbp; - - } else { - /* Xfer is aligned -- just adjust the start block */ - bp->b_rawblkno = (blkno * lp->d_secsize) / - cd->params.blksize; - } + return; } - mutex_enter(chan_mtx(chan)); - - /* - * Place it in the queue of disk activities for this disk. - * - * XXX Only do disksort() if the current operating mode does not - * XXX include tagged queueing. - */ - bufq_put(cd->buf_queue, bp); - - /* - * Tell the device to get going on the transfer if it's - * not doing anything, otherwise just wait for completion - */ - cdstart(periph); - - mutex_exit(chan_mtx(chan)); + + dk_strategy(dksc, bp); return; -done: - /* - * Correctly set the buf to indicate a completed xfer - */ +bad: + bp->b_error = error; bp->b_resid = bp->b_bcount; biodone(bp); } /* - * cdstart looks to see if there is a buf waiting for the device - * and that the device is not already busy. If both are true, - * It deques the buf and creates a scsi command to perform the - * transfer in the buf. The transfer request will call scsipi_done - * on completion, which will in turn call this routine again - * so that the next queued transfer is performed. - * The bufs are queued by the strategy routine (cdstrategy) + * Issue single I/O command * - * This routine is also called after other non-queued requests - * have been made of the scsi driver, to ensure that the queue - * continues to be drained. + * Called from dk_start and implicitely from dk_strategy + */ +static int +cd_diskstart(device_t dev, struct buf *bp) +{ + struct cd_softc *cd = device_private(dev); + struct scsipi_periph *periph = cd->sc_periph; + struct scsipi_channel *chan = periph->periph_channel; + struct scsipi_rw_10 cmd_big; + struct scsi_rw_6 cmd_small; + struct scsipi_generic *cmdp; + struct scsipi_xfer *xs; + int error, flags, nblks, cmdlen; + + SC_DEBUG(periph, SCSIPI_DB2, ("cdstart ")); + + mutex_enter(chan_mtx(chan)); + + if (periph->periph_active >= periph->periph_openings) { + error = EAGAIN; + goto out; + } + + /* + * there is excess capacity, but a special waits + * It'll need the adapter as soon as we clear out of the + * way and let it run (user level wait). + */ + if (periph->periph_flags & PERIPH_WAITING) { + periph->periph_flags &= ~PERIPH_WAITING; + cv_broadcast(periph_cv_periph(periph)); + error = EAGAIN; + goto out; + } + + /* + * If the device has become invalid, abort all the + * reads and writes until all files have been closed and + * re-opened + */ + if (__predict_false( + (periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) { + error = EIO; + goto out; + } + + nblks = howmany(bp->b_bcount, cd->params.blksize); + + /* + * Fill out the scsi command. If the transfer will + * fit in a "small" cdb, use it. + */ + if (((bp->b_rawblkno & 0x1fffff) == bp->b_rawblkno) && + ((nblks & 0xff) == nblks) && + !(periph->periph_quirks & PQUIRK_ONLYBIG)) { + /* + * We can fit in a small cdb. + */ + memset(&cmd_small, 0, sizeof(cmd_small)); + cmd_small.opcode = (bp->b_flags & B_READ) ? + SCSI_READ_6_COMMAND : SCSI_WRITE_6_COMMAND; + _lto3b(bp->b_rawblkno, cmd_small.addr); + cmd_small.length = nblks & 0xff; + cmdlen = sizeof(cmd_small); + cmdp = (struct scsipi_generic *)&cmd_small; + } else { + /* + * Need a large cdb. + */ + memset(&cmd_big, 0, sizeof(cmd_big)); + cmd_big.opcode = (bp->b_flags & B_READ) ? + READ_10 : WRITE_10; + _lto4b(bp->b_rawblkno, cmd_big.addr); + _lto2b(nblks, cmd_big.length); + cmdlen = sizeof(cmd_big); + cmdp = (struct scsipi_generic *)&cmd_big; + } + + /* + * Figure out what flags to use. + */ + flags = XS_CTL_NOSLEEP|XS_CTL_ASYNC|XS_CTL_SIMPLE_TAG; + if (bp->b_flags & B_READ) + flags |= XS_CTL_DATA_IN; + else + flags |= XS_CTL_DATA_OUT; + + /* + * Call the routine that chats with the adapter. + * Note: we cannot sleep as we may be an interrupt + */ + xs = scsipi_make_xs_locked(periph, cmdp, cmdlen, + (u_char *)bp->b_data, bp->b_bcount, + CDRETRIES, 30000, bp, flags); + if (__predict_false(xs == NULL)) { + /* + * out of memory. Keep this buffer in the queue, and + * retry later. + */ + callout_reset(&cd->sc_callout, hz / 2, cdrestart, + periph); + error = 0; + goto out; + } + + error = scsipi_execute_xs(xs); + /* with a scsipi_xfer preallocated, scsipi_command can't fail */ + KASSERT(error == 0); + +out: + mutex_exit(chan_mtx(chan)); + + return error; +} + +/* + * Recover I/O request after memory shortage * - * must be called with channel lock held - * cdstart() is called from cdstrategy, cdrestart and scsipi_done + * Called from callout + */ +static void +cdrestart(void *v) +{ + struct cd_softc *cd = v; + struct dk_softc *dksc = &cd->sc_dksc; + + dk_start(dksc, NULL); +} + +/* + * Recover I/O request after memory shortage + * + * Called from scsipi midlayer when resources have been freed + * with channel lock held */ static void cdstart(struct scsipi_periph *periph) { struct cd_softc *cd = device_private(periph->periph_dev); - struct buf *bp = 0; - struct scsipi_rw_10 cmd_big; - struct scsi_rw_6 cmd_small; - struct scsipi_generic *cmdp; - struct scsipi_xfer *xs; - int flags, nblks, cmdlen, error __diagused; - - SC_DEBUG(periph, SCSIPI_DB2, ("cdstart ")); - - /* - * Check if the device has room for another command - */ - while (periph->periph_active < periph->periph_openings) { - /* - * there is excess capacity, but a special waits - * It'll need the adapter as soon as we clear out of the - * way and let it run (user level wait). - */ - if (periph->periph_flags & PERIPH_WAITING) { - periph->periph_flags &= ~PERIPH_WAITING; - cv_broadcast(periph_cv_periph(periph)); - return; - } - - /* - * If the device has become invalid, abort all the - * reads and writes until all files have been closed and - * re-opened - */ - if (__predict_false( - (periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) { - if ((bp = bufq_get(cd->buf_queue)) != NULL) { - bp->b_error = EIO; - bp->b_resid = bp->b_bcount; - biodone(bp); - continue; - } else { - return; - } - } - - /* - * See if there is a buf with work for us to do.. - */ - if ((bp = bufq_peek(cd->buf_queue)) == NULL) - return; - - /* - * We have a buf, now we should make a command. - */ - - nblks = howmany(bp->b_bcount, cd->params.blksize); - - /* - * Fill out the scsi command. If the transfer will - * fit in a "small" cdb, use it. - */ - if (((bp->b_rawblkno & 0x1fffff) == bp->b_rawblkno) && - ((nblks & 0xff) == nblks) && - !(periph->periph_quirks & PQUIRK_ONLYBIG)) { - /* - * We can fit in a small cdb. - */ - memset(&cmd_small, 0, sizeof(cmd_small)); - cmd_small.opcode = (bp->b_flags & B_READ) ? - SCSI_READ_6_COMMAND : SCSI_WRITE_6_COMMAND; - _lto3b(bp->b_rawblkno, cmd_small.addr); - cmd_small.length = nblks & 0xff; - cmdlen = sizeof(cmd_small); - cmdp = (struct scsipi_generic *)&cmd_small; - } else { - /* - * Need a large cdb. - */ - memset(&cmd_big, 0, sizeof(cmd_big)); - cmd_big.opcode = (bp->b_flags & B_READ) ? - READ_10 : WRITE_10; - _lto4b(bp->b_rawblkno, cmd_big.addr); - _lto2b(nblks, cmd_big.length); - cmdlen = sizeof(cmd_big); - cmdp = (struct scsipi_generic *)&cmd_big; - } - - /* Instrumentation. */ - disk_busy(&cd->sc_dk); - - /* - * Figure out what flags to use. - */ - flags = XS_CTL_NOSLEEP|XS_CTL_ASYNC|XS_CTL_SIMPLE_TAG; - if (bp->b_flags & B_READ) - flags |= XS_CTL_DATA_IN; - else - flags |= XS_CTL_DATA_OUT; - - /* - * Call the routine that chats with the adapter. - * Note: we cannot sleep as we may be an interrupt - */ - xs = scsipi_make_xs_locked(periph, cmdp, cmdlen, - (u_char *)bp->b_data, bp->b_bcount, - CDRETRIES, 30000, bp, flags); - if (__predict_false(xs == NULL)) { - /* - * out of memory. Keep this buffer in the queue, and - * retry later. - */ - callout_reset(&cd->sc_callout, hz / 2, cdrestart, - periph); - return; - } - /* - * need to dequeue the buffer before queuing the command, - * because cdstart may be called recursively from the - * HBA driver - */ -#ifdef DIAGNOSTIC - if (bufq_get(cd->buf_queue) != bp) - panic("cdstart(): dequeued wrong buf"); -#else - bufq_get(cd->buf_queue); -#endif - error = scsipi_execute_xs(xs); - /* with a scsipi_xfer preallocated, scsipi_command can't fail */ - KASSERT(error == 0); - } -} - -static void -cdrestart(void *v) -{ - struct scsipi_periph *periph = (struct scsipi_periph *)v; + struct dk_softc *dksc = &cd->sc_dksc; struct scsipi_channel *chan = periph->periph_channel; - mutex_enter(chan_mtx(chan)); - cdstart((struct scsipi_periph *)v); + /* + * release channel lock as dk_start may need to acquire + * other locks + * + * cdstart is called from scsipi_put_xs and all its callers + * release the lock afterwards. So releasing it here + * doesn't matter. + */ mutex_exit(chan_mtx(chan)); + + dk_start(dksc, NULL); + + mutex_enter(chan_mtx(chan)); } static void cddone(struct scsipi_xfer *xs, int error) { struct cd_softc *cd = device_private(xs->xs_periph->periph_dev); + struct dk_softc *dksc = &cd->sc_dksc; struct buf *bp = xs->bp; if (bp) { - /* note, bp->b_resid is NOT initialised */ bp->b_error = error; bp->b_resid = xs->resid; if (error) { @@ -922,102 +919,10 @@ cddone(struct scsipi_xfer *xs, int error) bp->b_resid = bp->b_bcount; } - disk_unbusy(&cd->sc_dk, bp->b_bcount - bp->b_resid, - (bp->b_flags & B_READ)); - rnd_add_uint32(&cd->rnd_source, bp->b_rawblkno); - - biodone(bp); + dk_done(dksc, bp); } } -static void -cdbounce(struct buf *bp) -{ - struct cdbounce *bounce = (struct cdbounce *)bp->b_private; - struct buf *obp = bounce->obp; - struct cd_softc *cd = - device_lookup_private(&cd_cd, CDUNIT(obp->b_dev)); - struct disklabel *lp = cd->sc_dk.dk_label; - - if (bp->b_error != 0) { - /* EEK propagate the error and free the memory */ - goto done; - } - - KASSERT(obp->b_flags & B_READ); - - /* copy bounce buffer to final destination */ - memcpy((char *)obp->b_data + bounce->doff, - (char *)bp->b_data + bounce->soff, bounce->bcount); - - /* check if we need more I/O, i.e. bounce put us over MAXPHYS */ - KASSERT(bounce->resid >= bounce->bcount); - bounce->resid -= bounce->bcount; - if (bounce->resid > 0) { - struct buf *nbp; - daddr_t blkno; - long count; - - blkno = obp->b_rawblkno + - ((obp->b_bcount - bounce->resid) / lp->d_secsize); - count = ((blkno * lp->d_secsize) % cd->params.blksize); - blkno = (blkno * lp->d_secsize) / cd->params.blksize; - bounce->soff = count; - bounce->doff += bounce->bcount; - count += bounce->resid; - count = roundup(count, cd->params.blksize); - bounce->bcount = bounce->resid; - if (count > MAXPHYS) { - bounce->bcount = MAXPHYS - bounce->soff; - count = MAXPHYS; - } - - nbp = getiobuf(NULL, false); - if (!nbp) { - /* No memory -- fail the iop. */ - bp->b_error = ENOMEM; - goto done; - } - - /* Set up the IOP to the bounce buffer. */ - nbp->b_error = 0; - nbp->b_proc = obp->b_proc; - nbp->b_bcount = count; - nbp->b_bufsize = count; - nbp->b_data = bp->b_data; - nbp->b_rawblkno = blkno; - nbp->b_flags = obp->b_flags | B_READ; - nbp->b_oflags = obp->b_oflags; - nbp->b_cflags = obp->b_cflags; - nbp->b_iodone = cdbounce; - - /* store bounce state in b_private and use new buf */ - nbp->b_private = bounce; - - BIO_COPYPRIO(nbp, obp); - - bp->b_data = NULL; - putiobuf(bp); - - /* enqueue the request and return */ - mutex_enter(chan_mtx(cd->sc_periph->periph_channel)); - bufq_put(cd->buf_queue, nbp); - cdstart(cd->sc_periph); - mutex_exit(chan_mtx(cd->sc_periph->periph_channel)); - - return; - } - -done: - obp->b_error = bp->b_error; - obp->b_resid = bp->b_resid; - free(bp->b_data, M_DEVBUF); - free(bounce, M_DEVBUF); - bp->b_data = NULL; - putiobuf(bp); - biodone(obp); -} - static int cd_interpret_sense(struct scsipi_xfer *xs) { @@ -1105,6 +1010,7 @@ static void cdminphys(struct buf *bp) { struct cd_softc *cd = device_lookup_private(&cd_cd, CDUNIT(bp->b_dev)); + struct dk_softc *dksc = &cd->sc_dksc; long xmax; /* @@ -1119,13 +1025,28 @@ cdminphys(struct buf *bp) * in a 10-byte read/write actually means 0 blocks. */ if (cd->flags & CDF_ANCIENT) { - xmax = cd->sc_dk.dk_label->d_secsize * 0xff; + xmax = dksc->sc_dkdev.dk_geom.dg_secsize * 0xff; if (bp->b_bcount > xmax) bp->b_bcount = xmax; } - (*cd->sc_periph->periph_channel->chan_adapter->adapt_minphys)(bp); + scsipi_adapter_minphys(cd->sc_periph->periph_channel, bp); +} + +static void +cd_iosize(device_t dev, int *count) +{ + struct buf B; + int bmaj; + + bmaj = bdevsw_lookup_major(&cd_bdevsw); + B.b_dev = MAKECDDEV(bmaj,device_unit(dev),RAW_PART); + B.b_bcount = *count; + + cdminphys(&B); + + *count = B.b_bcount; } static int @@ -1201,7 +1122,7 @@ cdreadmsaddr(struct cd_softc *cd, struct cd_formatted_toc *toc, int *addr) return 0; } -/* synchronise caches code from sd.c, move to scsipi_ioctl.c ? */ +/* synchronise caches code from cd.c, move to scsipi_ioctl.c ? */ static int cdcachesync(struct scsipi_periph *periph, int flags) { struct scsi_synchronize_cache_10 cmd; @@ -1271,13 +1192,11 @@ static int cdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) { struct cd_softc *cd = device_lookup_private(&cd_cd, CDUNIT(dev)); + struct dk_softc *dksc = &cd->sc_dksc; struct scsipi_periph *periph = cd->sc_periph; struct cd_formatted_toc toc; int part = CDPART(dev); int error; -#ifdef __HAVE_OLD_DISKLABEL - struct disklabel *newlabel = NULL; -#endif SC_DEBUG(cd->sc_periph, SCSIPI_DB2, ("cdioctl 0x%lx ", cmd)); @@ -1285,128 +1204,11 @@ cdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) * If the device is not valid, some IOCTLs can still be * handled on the raw partition. Check this here. */ - if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) { - switch (cmd) { - case DIOCWLABEL: - case DIOCLOCK: - case ODIOCEJECT: - case DIOCEJECT: - case DIOCCACHESYNC: - case DIOCTUR: - case SCIOCIDENTIFY: - case OSCIOCIDENTIFY: - case SCIOCCOMMAND: - case SCIOCDEBUG: - case CDIOCGETVOL: - case CDIOCSETVOL: - case CDIOCSETMONO: - case CDIOCSETSTEREO: - case CDIOCSETMUTE: - case CDIOCSETLEFT: - case CDIOCSETRIGHT: - case CDIOCCLOSE: - case CDIOCEJECT: - case CDIOCALLOW: - case CDIOCPREVENT: - case CDIOCSETDEBUG: - case CDIOCCLRDEBUG: - case CDIOCRESET: - case SCIOCRESET: - case CDIOCLOADUNLOAD: - case DVD_AUTH: - case DVD_READ_STRUCT: - case DIOCGSTRATEGY: - case DIOCSSTRATEGY: - if (part == RAW_PART) - break; - /* FALLTHROUGH */ - default: - if ((periph->periph_flags & PERIPH_OPEN) == 0) - return (ENODEV); - else - return (EIO); - } - } + if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 && + part != RAW_PART) + return (EIO); - error = disk_ioctl(&cd->sc_dk, dev, cmd, addr, flag, l); - if (error != EPASSTHROUGH) - return (error); - - error = 0; switch (cmd) { - case DIOCWDINFO: - case DIOCSDINFO: -#ifdef __HAVE_OLD_DISKLABEL - case ODIOCWDINFO: - case ODIOCSDINFO: -#endif - { - struct disklabel *lp; - - if ((flag & FWRITE) == 0) - return (EBADF); - -#ifdef __HAVE_OLD_DISKLABEL - if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { - newlabel = malloc(sizeof (*newlabel), M_TEMP, - M_WAITOK | M_ZERO); - if (newlabel == NULL) - return (EIO); - memcpy(newlabel, addr, sizeof (struct olddisklabel)); - lp = newlabel; - } else -#endif - lp = addr; - - mutex_enter(&cd->sc_lock); - cd->flags |= CDF_LABELLING; - - error = setdisklabel(cd->sc_dk.dk_label, - lp, /*cd->sc_dk.dk_openmask : */0, - cd->sc_dk.dk_cpulabel); - if (error == 0) { - /* XXX ? */ - } - - cd->flags &= ~CDF_LABELLING; - mutex_exit(&cd->sc_lock); -#ifdef __HAVE_OLD_DISKLABEL - if (newlabel != NULL) - free(newlabel, M_TEMP); -#endif - return (error); - } - - case DIOCWLABEL: - return (EBADF); - - case DIOCGDEFLABEL: - cdgetdefaultlabel(cd, &toc, addr); - return (0); - -#ifdef __HAVE_OLD_DISKLABEL - case ODIOCGDEFLABEL: - newlabel = malloc(sizeof (*newlabel), M_TEMP, M_WAITOK); - if (newlabel == NULL) - return (EIO); - cdgetdefaultlabel(cd, &toc, newlabel); - if (newlabel->d_npartitions > OLDMAXPARTITIONS) - error = ENOTTY; - else - memcpy(addr, newlabel, sizeof (struct olddisklabel)); - free(newlabel, M_TEMP); - return error; -#endif - - case DIOCTUR: { - /* test unit ready */ - error = scsipi_test_unit_ready(cd->sc_periph, XS_CTL_SILENT); - *((int*)addr) = (error == 0); - if (error == ENODEV || error == EIO || error == 0) - return 0; - return error; - } - case CDIOCPLAYTRACKS: { /* PLAY_MSF command */ struct ioc_play_track *args = addr; @@ -1557,13 +1359,12 @@ cdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) XS_CTL_IGNORE_NOT_READY | XS_CTL_IGNORE_MEDIA_CHANGE)); case DIOCEJECT: if (*(int *)addr == 0) { + int pmask = 1 << part; /* * Don't force eject: check that we are the only * partition open. If so, unlock it. */ - if ((cd->sc_dk.dk_openmask & ~(1 << part)) == 0 && - cd->sc_dk.dk_bopenmask + cd->sc_dk.dk_copenmask == - cd->sc_dk.dk_openmask) { + if (DK_BUSY(dksc, pmask) == 0) { error = scsipi_prevent(periph, SPAMR_ALLOW, XS_CTL_IGNORE_NOT_READY); if (error) @@ -1576,22 +1377,9 @@ cdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) case CDIOCEJECT: /* FALLTHROUGH */ case ODIOCEJECT: error = scsipi_start(periph, SSS_STOP|SSS_LOEJ, 0); - if (error == 0) { - int i; - - /* - * We have just successfully ejected the medium, - * all partitions cached are meaningless now. - * Make sure cdclose() will do silent operations - * now by marking all partitions unused. - * Before any real access, a new (default-)disk- - * label will be generated anyway. - */ - for (i = 0; i < cd->sc_dk.dk_label->d_npartitions; - i++) - cd->sc_dk.dk_label->d_partitions[i].p_fstype = - FS_UNUSED; - } + if (error == 0) + /* Make sure cdclose() will do silent operations */ + cd->flags |= CDF_EJECTED; return error; case DIOCCACHESYNC: /* SYNCHRONISE CACHES command */ @@ -1639,51 +1427,11 @@ cdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) case MMCSETUPWRITEPARAMS : /* MODE SENSE page 5, MODE_SELECT page 5 commands */ return mmc_setup_writeparams(periph, (struct mmc_writeparams *) addr); - case DIOCGSTRATEGY: - { - struct disk_strategy *dks = addr; - int s; - - s = splbio(); - strlcpy(dks->dks_name, bufq_getstrategyname(cd->buf_queue), - sizeof(dks->dks_name)); - splx(s); - dks->dks_paramlen = 0; - - return 0; - } - case DIOCSSTRATEGY: - { - struct disk_strategy *dks = addr; - struct bufq_state *new; - struct bufq_state *old; - int s; - - if ((flag & FWRITE) == 0) { - return EBADF; - } - if (dks->dks_param != NULL) { - return EINVAL; - } - dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */ - error = bufq_alloc(&new, dks->dks_name, - BUFQ_EXACT|BUFQ_SORT_RAWBLOCK); - if (error) { - return error; - } - s = splbio(); - old = cd->buf_queue; - bufq_move(new, old); - cd->buf_queue = new; - splx(s); - bufq_free(old); - - return 0; - } default: - if (part != RAW_PART) - return (ENOTTY); - return (scsipi_do_ioctl(periph, dev, cmd, addr, flag, l)); + error = dk_ioctl(dksc, dev, cmd, addr, flag, l); + if (error == ENOTTY) + error = scsipi_do_ioctl(periph, dev, cmd, addr, flag, l); + return (error); } #ifdef DIAGNOSTIC @@ -1692,40 +1440,17 @@ cdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) } static void -cdgetdefaultlabel(struct cd_softc *cd, struct cd_formatted_toc *toc, - struct disklabel *lp) +cd_label(device_t self, struct disklabel *lp) { + struct cd_softc *cd = device_private(self); + struct cd_formatted_toc toc; int lastsession; - memset(lp, 0, sizeof(struct disklabel)); - - lp->d_secsize = cd->params.blksize; - lp->d_ntracks = 1; - lp->d_nsectors = 100; - lp->d_ncylinders = (cd->params.disksize / 100) + 1; - lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; - - switch (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(cd->sc_periph))) { - case SCSIPI_BUSTYPE_SCSI: - lp->d_type = DKTYPE_SCSI; - break; - case SCSIPI_BUSTYPE_ATAPI: - lp->d_type = DKTYPE_ATAPI; - break; - } - /* - * XXX - * We could probe the mode pages to figure out what kind of disc it is. - * Is this worthwhile? - */ strncpy(lp->d_typename, "optical media", 16); - strncpy(lp->d_packname, "fictitious", 16); - lp->d_secperunit = cd->params.disksize; lp->d_rpm = 300; - lp->d_interleave = 1; - lp->d_flags = D_REMOVABLE | D_SCSI_MMC; + lp->d_flags |= D_REMOVABLE | D_SCSI_MMC; - if (cdreadmsaddr(cd, toc, &lastsession) != 0) + if (cdreadmsaddr(cd, &toc, &lastsession) != 0) lastsession = 0; lp->d_partitions[0].p_offset = 0; @@ -1736,51 +1461,6 @@ cdgetdefaultlabel(struct cd_softc *cd, struct cd_formatted_toc *toc, lp->d_partitions[RAW_PART].p_offset = 0; lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; lp->d_partitions[RAW_PART].p_fstype = FS_UDF; - - lp->d_npartitions = RAW_PART + 1; - - lp->d_magic = DISKMAGIC; - lp->d_magic2 = DISKMAGIC; - lp->d_checksum = dkcksum(lp); -} - -/* - * Load the label information on the named device - * Actually fabricate a disklabel - * - * EVENTUALLY take information about different - * data tracks from the TOC and put it in the disklabel - */ -static void -cdgetdisklabel(struct cd_softc *cd) -{ - struct disklabel *lp = cd->sc_dk.dk_label; - struct cd_formatted_toc toc; - const char *errstring; - int bmajor; - - memset(cd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel)); - - cdgetdefaultlabel(cd, &toc, lp); - - /* - * Call the generic disklabel extraction routine - * - * bmajor follows ata_raid code - */ - bmajor = devsw_name2blk(device_xname(cd->sc_dev), NULL, 0); - errstring = readdisklabel(MAKECDDEV(bmajor, - device_unit(cd->sc_dev), RAW_PART), - cdstrategy, lp, cd->sc_dk.dk_cpulabel); - - /* if all went OK, we are passed a NULL error string */ - if (errstring == NULL) - return; - - /* Reset to default label -- after printing error and the warning */ - aprint_error_dev(cd->sc_dev, "%s\n", errstring); - memset(cd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel)); - cdgetdefaultlabel(cd, &toc, lp); } /* @@ -3920,12 +3600,15 @@ mmc_setup_writeparams(struct scsipi_periph *periph, static void cd_set_geometry(struct cd_softc *cd) { - struct disk_geom *dg = &cd->sc_dk.dk_geom; + struct dk_softc *dksc = &cd->sc_dksc; + struct disk_geom *dg = &dksc->sc_dkdev.dk_geom; memset(dg, 0, sizeof(*dg)); dg->dg_secperunit = cd->params.disksize; dg->dg_secsize = cd->params.blksize; + dg->dg_nsectors = 100; + dg->dg_ntracks = 1; - disk_set_info(cd->sc_dev, &cd->sc_dk, NULL); + disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL); } diff --git a/sys/dev/scsipi/cdvar.h b/sys/dev/scsipi/cdvar.h index 4e30e2992a4d..44a27987df99 100644 --- a/sys/dev/scsipi/cdvar.h +++ b/sys/dev/scsipi/cdvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: cdvar.h,v 1.32 2015/04/14 20:32:36 riastradh Exp $ */ +/* $NetBSD: cdvar.h,v 1.33 2016/12/10 10:26:38 mlelstv Exp $ */ /* * Copyright (c) 1997 Manuel Bouyer. All rights reserved. @@ -24,19 +24,16 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include +#include #define CDRETRIES 4 struct cd_softc { - device_t sc_dev; - struct disk sc_dk; - kmutex_t sc_lock; + struct dk_softc sc_dksc; int flags; -#define CDF_WLABEL 0x04 /* label is writable */ -#define CDF_LABELLING 0x08 /* writing label */ #define CDF_ANCIENT 0x10 /* disk is ancient; for minphys */ +#define CDF_EJECTED 0x20 /* be silent when flushing cache */ struct scsipi_periph *sc_periph; @@ -46,8 +43,9 @@ struct cd_softc { u_long disksize512; /* total number sectors */ } params; - struct bufq_state *buf_queue; struct callout sc_callout; - - krndsource_t rnd_source; }; + +#define CDGP_RESULT_OK 0 /* parameters obtained */ +#define CDGP_RESULT_OFFLINE 1 /* no media, or otherwise losing */ +#define CDGP_RESULT_UNFORMATTED 2 /* unformatted media (max params) */ diff --git a/sys/dev/scsipi/sd.c b/sys/dev/scsipi/sd.c index f00da0d1224d..965212e0ed4c 100644 --- a/sys/dev/scsipi/sd.c +++ b/sys/dev/scsipi/sd.c @@ -1,4 +1,4 @@ -/* $NetBSD: sd.c,v 1.319 2016/11/20 15:37:19 mlelstv Exp $ */ +/* $NetBSD: sd.c,v 1.320 2016/12/10 10:26:38 mlelstv Exp $ */ /*- * Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc. @@ -47,14 +47,12 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.319 2016/11/20 15:37:19 mlelstv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.320 2016/12/10 10:26:38 mlelstv Exp $"); #ifdef _KERNEL_OPT #include "opt_scsi.h" #endif -#define SD_MPSAFE D_MPSAFE - #include #include #include @@ -73,7 +71,6 @@ __KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.319 2016/11/20 15:37:19 mlelstv Exp $"); #include #include #include -#include #include #include @@ -96,15 +93,18 @@ __KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.319 2016/11/20 15:37:19 mlelstv Exp $"); #define SD_DEFAULT_BLKSIZE 512 static void sdminphys(struct buf *); -static void sdgetdefaultlabel(struct sd_softc *, struct disklabel *); -static int sdgetdisklabel(struct sd_softc *); static void sdstart(struct scsipi_periph *); static void sdrestart(void *); static void sddone(struct scsipi_xfer *, int); static bool sd_suspend(device_t, const pmf_qual_t *); static bool sd_shutdown(device_t, int); static int sd_interpret_sense(struct scsipi_xfer *); -static int sdlastclose(device_t); +static int sd_diskstart(device_t, struct buf *); +static int sd_dumpblocks(device_t, void *, daddr_t, int); +static void sd_iosize(device_t, int *); +static int sd_lastclose(device_t); +static int sd_firstopen(device_t, dev_t, int, int); +static void sd_label(device_t, struct disklabel *); static int sd_mode_sense(struct sd_softc *, u_int8_t, void *, size_t, int, int, int *); @@ -167,7 +167,7 @@ const struct bdevsw sd_bdevsw = { .d_dump = sddump, .d_psize = sdsize, .d_discard = nodiscard, - .d_flag = D_DISK | SD_MPSAFE + .d_flag = D_DISK | D_MPSAFE }; const struct cdevsw sd_cdevsw = { @@ -182,12 +182,20 @@ const struct cdevsw sd_cdevsw = { .d_mmap = nommap, .d_kqfilter = nokqfilter, .d_discard = nodiscard, - .d_flag = D_DISK | SD_MPSAFE + .d_flag = D_DISK | D_MPSAFE }; static struct dkdriver sddkdriver = { + .d_open = sdopen, + .d_close = sdclose, .d_strategy = sdstrategy, - .d_minphys = sdminphys + .d_minphys = sdminphys, + .d_diskstart = sd_diskstart, + .d_dumpblocks = sd_dumpblocks, + .d_iosize = sd_iosize, + .d_firstopen = sd_firstopen, + .d_lastclose = sd_lastclose, + .d_label = sd_label, }; static const struct scsipi_periphsw sd_switch = { @@ -236,25 +244,44 @@ static void sdattach(device_t parent, device_t self, void *aux) { struct sd_softc *sd = device_private(self); + struct dk_softc *dksc = &sd->sc_dksc; struct scsipibus_attach_args *sa = aux; struct scsipi_periph *periph = sa->sa_periph; - int error, result; + int error, result, dtype; struct disk_parms *dp = &sd->params; char pbuf[9]; SC_DEBUG(periph, SCSIPI_DB2, ("sdattach: ")); - sd->sc_dev = self; sd->type = (sa->sa_inqbuf.type & SID_TYPE); strncpy(sd->name, sa->sa_inqbuf.product, sizeof(sd->name)); + if (sd->type == T_SIMPLE_DIRECT) periph->periph_quirks |= PQUIRK_ONLYBIG | PQUIRK_NOBIGMODESENSE; - if (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sa->sa_periph)) == - SCSIPI_BUSTYPE_SCSI && periph->periph_version == 0) - sd->flags |= SDF_ANCIENT; + switch (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sa->sa_periph))) { + case SCSIPI_BUSTYPE_SCSI: + dtype = DKTYPE_SCSI; + if (periph->periph_version == 0) + sd->flags |= SDF_ANCIENT; + break; + case SCSIPI_BUSTYPE_ATAPI: + dtype = DKTYPE_ATAPI; + break; + default: + dtype = DKTYPE_UNKNOWN; + break; + } - bufq_alloc(&sd->buf_queue, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK); + /* Initialize dk and disk structure. */ + dk_init(dksc, self, dtype); + disk_init(&dksc->sc_dkdev, dksc->sc_xname, &sddkdriver); + + /* Attach dk and disk subsystems */ + dk_attach(dksc); + disk_attach(&dksc->sc_dkdev); + + bufq_alloc(&dksc->sc_bufq, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK); callout_init(&sd->sc_callout, 0); @@ -263,7 +290,7 @@ sdattach(device_t parent, device_t self, void *aux) */ sd->sc_periph = periph; - periph->periph_dev = sd->sc_dev; + periph->periph_dev = dksc->sc_dev; periph->periph_switch = &sd_switch; /* @@ -275,12 +302,6 @@ sdattach(device_t parent, device_t self, void *aux) SCSIPI_CHAN_MAX_PERIPH(periph->periph_channel); periph->periph_flags |= PERIPH_GROW_OPENINGS; - /* - * Initialize and attach the disk structure. - */ - disk_init(&sd->sc_dk, device_xname(sd->sc_dev), &sddkdriver); - disk_attach(&sd->sc_dk); - /* * Use the subdriver to request information regarding the drive. */ @@ -293,12 +314,12 @@ sdattach(device_t parent, device_t self, void *aux) error = scsipi_test_unit_ready(periph, XS_CTL_DISCOVERY | XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE | XS_CTL_SILENT_NODEV); - if (error) result = SDGP_RESULT_OFFLINE; else result = sd_get_parms(sd, &sd->params, XS_CTL_DISCOVERY); - aprint_normal_dev(sd->sc_dev, ""); + + aprint_normal_dev(dksc->sc_dev, ""); switch (result) { case SDGP_RESULT_OK: format_bytes(pbuf, sizeof(pbuf), @@ -325,6 +346,9 @@ sdattach(device_t parent, device_t self, void *aux) } aprint_normal("\n"); + /* Discover wedges on this disk. */ + dkwedge_discover(&dksc->sc_dkdev); + /* * Establish a shutdown hook so that we can ensure that * our data has actually made it onto the platter at @@ -335,36 +359,18 @@ sdattach(device_t parent, device_t self, void *aux) */ if (!pmf_device_register1(self, sd_suspend, NULL, sd_shutdown)) aprint_error_dev(self, "couldn't establish power handler\n"); - - /* - * attach the device into the random source list - */ - rnd_attach_source(&sd->rnd_source, device_xname(sd->sc_dev), - RND_TYPE_DISK, RND_FLAG_DEFAULT); - - /* Discover wedges on this disk. */ - dkwedge_discover(&sd->sc_dk); - - /* - * Disk insertion and removal times can be a useful source - * of entropy, though the estimator should never _count_ - * these bits, on insertion, because the deltas to the - * nonexistent) previous event should never allow it. - */ - rnd_add_uint32(&sd->rnd_source, 0); } static int sddetach(device_t self, int flags) { struct sd_softc *sd = device_private(self); + struct dk_softc *dksc = &sd->sc_dksc; struct scsipi_periph *periph = sd->sc_periph; struct scsipi_channel *chan = periph->periph_channel; int bmaj, cmaj, i, mn, rc; - rnd_add_uint32(&sd->rnd_source, 0); - - if ((rc = disk_begindetach(&sd->sc_dk, sdlastclose, self, flags)) != 0) + if ((rc = disk_begindetach(&dksc->sc_dkdev, sd_lastclose, self, flags)) != 0) return rc; /* locate the major number */ @@ -381,35 +387,119 @@ sddetach(device_t self, int flags) /* kill any pending restart */ callout_stop(&sd->sc_callout); - /* Delete all of our wedges. */ - dkwedge_delall(&sd->sc_dk); - - mutex_enter(chan_mtx(chan)); - - /* Kill off any queued buffers. */ - bufq_drain(sd->buf_queue); + dk_drain(dksc); /* Kill off any pending commands. */ - scsipi_kill_pending(sd->sc_periph); - + mutex_enter(chan_mtx(chan)); + scsipi_kill_pending(periph); mutex_exit(chan_mtx(chan)); - bufq_free(sd->buf_queue); + bufq_free(dksc->sc_bufq); + + /* Delete all of our wedges. */ + dkwedge_delall(&dksc->sc_dkdev); /* Detach from the disk list. */ - disk_detach(&sd->sc_dk); - disk_destroy(&sd->sc_dk); + disk_detach(&dksc->sc_dkdev); + disk_destroy(&dksc->sc_dkdev); + + dk_detach(dksc); callout_destroy(&sd->sc_callout); pmf_device_deregister(self); - /* Unhook the entropy source. */ - rnd_detach_source(&sd->rnd_source); - return (0); } +/* + * Serialized by caller + */ +static int +sd_firstopen(device_t self, dev_t dev, int flag, int fmt) +{ + struct sd_softc *sd = device_private(self); + struct scsipi_periph *periph = sd->sc_periph; + struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter; + int error, silent; + int part, removable; + + part = SDPART(dev); + + error = scsipi_adapter_addref(adapt); + if (error) + return error; + + if ((part == RAW_PART && fmt == S_IFCHR) || (flag & FSILENT)) + silent = XS_CTL_SILENT; + else + silent = 0; + + /* Check that it is still responding and ok. */ + error = scsipi_test_unit_ready(periph, + XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE | + silent); + + /* + * Start the pack spinning if necessary. Always allow the + * raw parition to be opened, for raw IOCTLs. Data transfers + * will check for SDEV_MEDIA_LOADED. + */ + if (error == EIO) { + error = scsipi_start(periph, SSS_START, silent); + if (error == EINVAL) + error = EIO; + } + if (error) + goto bad; + + removable = (periph->periph_flags & PERIPH_REMOVABLE) != 0; + if (removable) { + /* Lock the pack in. */ + error = scsipi_prevent(periph, SPAMR_PREVENT_DT, + XS_CTL_IGNORE_ILLEGAL_REQUEST | + XS_CTL_IGNORE_MEDIA_CHANGE | + XS_CTL_SILENT); + if (error) + goto bad; + } + + if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) { + int param_error; + + /* + * Load the physical device parameters. + * + * Note that if media is present but unformatted, + * we allow the open (so that it can be formatted!). + * The drive should refuse real I/O, if the media is + * unformatted. + */ + param_error = sd_get_parms(sd, &sd->params, 0); + if (param_error == SDGP_RESULT_OFFLINE) { + error = ENXIO; + goto bad2; + } + periph->periph_flags |= PERIPH_MEDIA_LOADED; + + SC_DEBUG(periph, SCSIPI_DB3, ("Params loaded ")); + } + + periph->periph_flags |= PERIPH_OPEN; + return 0; + +bad2: + if (removable) + scsipi_prevent(periph, SPAMR_ALLOW, + XS_CTL_IGNORE_ILLEGAL_REQUEST | + XS_CTL_IGNORE_MEDIA_CHANGE | + XS_CTL_SILENT); + +bad: + scsipi_adapter_delref(adapt); + return error; +} + /* * open the device. Make sure the partition info is a up-to-date as can be. */ @@ -417,8 +507,8 @@ static int sdopen(dev_t dev, int flag, int fmt, struct lwp *l) { struct sd_softc *sd; + struct dk_softc *dksc; struct scsipi_periph *periph; - struct scsipi_adapter *adapt; int unit, part; int error; @@ -426,182 +516,43 @@ sdopen(dev_t dev, int flag, int fmt, struct lwp *l) sd = device_lookup_private(&sd_cd, unit); if (sd == NULL) return (ENXIO); + dksc = &sd->sc_dksc; - if (!device_is_active(sd->sc_dev)) + if (!device_is_active(dksc->sc_dev)) return (ENODEV); + periph = sd->sc_periph; part = SDPART(dev); - mutex_enter(&sd->sc_dk.dk_openlock); - - /* - * If there are wedges, and this is not RAW_PART, then we - * need to fail. - */ - if (sd->sc_dk.dk_nwedges != 0 && part != RAW_PART) { - error = EBUSY; - goto bad1; - } - - periph = sd->sc_periph; - adapt = periph->periph_channel->chan_adapter; - SC_DEBUG(periph, SCSIPI_DB1, - ("sdopen: dev=0x%"PRIx64" (unit %d (of %d), partition %d)\n", dev, unit, - sd_cd.cd_ndevs, part)); + ("sdopen: dev=0x%"PRIx64" (unit %d (of %d), partition %d)\n", + dev, unit, sd_cd.cd_ndevs, SDPART(dev))); /* - * If this is the first open of this device, add a reference - * to the adapter. + * If any partition is open, but the disk has been invalidated, + * disallow further opens of non-raw partition */ - if (sd->sc_dk.dk_openmask == 0 && - (error = scsipi_adapter_addref(adapt)) != 0) - goto bad1; - - if ((periph->periph_flags & PERIPH_OPEN) != 0) { - /* - * If any partition is open, but the disk has been invalidated, - * disallow further opens of non-raw partition - */ - if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 && - (part != RAW_PART || fmt != S_IFCHR)) { - error = EIO; - goto bad2; - } - } else { - int silent; - - if ((part == RAW_PART && fmt == S_IFCHR) || (flag & FSILENT)) - silent = XS_CTL_SILENT; - else - silent = 0; - - /* Check that it is still responding and ok. */ - error = scsipi_test_unit_ready(periph, - XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE | - silent); - - /* - * Start the pack spinning if necessary. Always allow the - * raw parition to be opened, for raw IOCTLs. Data transfers - * will check for SDEV_MEDIA_LOADED. - */ - if (error == EIO) { - int error2; - - error2 = scsipi_start(periph, SSS_START, silent); - switch (error2) { - case 0: - error = 0; - break; - case EIO: - case EINVAL: - break; - default: - error = error2; - break; - } - } - if (error) { - if (silent && (flag & FSILENT) == 0) - goto out; - goto bad2; - } - - periph->periph_flags |= PERIPH_OPEN; - - if (periph->periph_flags & PERIPH_REMOVABLE) { - /* Lock the pack in. */ - error = scsipi_prevent(periph, SPAMR_PREVENT_DT, - XS_CTL_IGNORE_ILLEGAL_REQUEST | - XS_CTL_IGNORE_MEDIA_CHANGE | - XS_CTL_SILENT); - if (error) - goto bad3; - } - - if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) { - int param_error; - periph->periph_flags |= PERIPH_MEDIA_LOADED; - - /* - * Load the physical device parameters. - * - * Note that if media is present but unformatted, - * we allow the open (so that it can be formatted!). - * The drive should refuse real I/O, if the media is - * unformatted. - */ - if ((param_error = sd_get_parms(sd, &sd->params, 0)) - == SDGP_RESULT_OFFLINE) { - error = ENXIO; - periph->periph_flags &= ~PERIPH_MEDIA_LOADED; - goto bad3; - } - SC_DEBUG(periph, SCSIPI_DB3, ("Params loaded ")); - - /* Load the partition info if not already loaded. */ - if (param_error == 0) { - if ((sdgetdisklabel(sd) != 0) && (part != RAW_PART)) { - error = EIO; - goto bad3; - } - SC_DEBUG(periph, SCSIPI_DB3, - ("Disklabel loaded ")); - } - } + if ((periph->periph_flags & (PERIPH_OPEN | PERIPH_MEDIA_LOADED)) == + PERIPH_OPEN) { + if (part != RAW_PART || fmt != S_IFCHR) + return EIO; } - /* Check that the partition exists. */ - if (part != RAW_PART && - (part >= sd->sc_dk.dk_label->d_npartitions || - sd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { - error = ENXIO; - goto bad3; - } - - out: /* Insure only one open at a time. */ - switch (fmt) { - case S_IFCHR: - sd->sc_dk.dk_copenmask |= (1 << part); - break; - case S_IFBLK: - sd->sc_dk.dk_bopenmask |= (1 << part); - break; - } - sd->sc_dk.dk_openmask = - sd->sc_dk.dk_copenmask | sd->sc_dk.dk_bopenmask; + error = dk_open(dksc, dev, flag, fmt, l); SC_DEBUG(periph, SCSIPI_DB3, ("open complete\n")); - mutex_exit(&sd->sc_dk.dk_openlock); - return (0); - bad3: - if (sd->sc_dk.dk_openmask == 0) { - if (periph->periph_flags & PERIPH_REMOVABLE) - scsipi_prevent(periph, SPAMR_ALLOW, - XS_CTL_IGNORE_ILLEGAL_REQUEST | - XS_CTL_IGNORE_MEDIA_CHANGE | - XS_CTL_SILENT); - periph->periph_flags &= ~PERIPH_OPEN; - } - - bad2: - if (sd->sc_dk.dk_openmask == 0) - scsipi_adapter_delref(adapt); - - bad1: - mutex_exit(&sd->sc_dk.dk_openlock); - return (error); + return error; } /* - * Caller must hold sd->sc_dk.dk_openlock. + * Serialized by caller */ static int -sdlastclose(device_t self) +sd_lastclose(device_t self) { struct sd_softc *sd = device_private(self); + struct dk_softc *dksc = &sd->sc_dksc; struct scsipi_periph *periph = sd->sc_periph; struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter; @@ -611,7 +562,7 @@ sdlastclose(device_t self) */ if ((sd->flags & SDF_DIRTY) != 0) { if (sd_flush(sd, 0)) { - aprint_error_dev(sd->sc_dev, + aprint_error_dev(dksc->sc_dev, "cache synchronization failed\n"); sd->flags &= ~SDF_FLUSHING; } else @@ -641,26 +592,15 @@ sdlastclose(device_t self) static int sdclose(dev_t dev, int flag, int fmt, struct lwp *l) { - struct sd_softc *sd = device_lookup_private(&sd_cd, SDUNIT(dev)); - int part = SDPART(dev); + struct sd_softc *sd; + struct dk_softc *dksc; + int unit; - mutex_enter(&sd->sc_dk.dk_openlock); - switch (fmt) { - case S_IFCHR: - sd->sc_dk.dk_copenmask &= ~(1 << part); - break; - case S_IFBLK: - sd->sc_dk.dk_bopenmask &= ~(1 << part); - break; - } - sd->sc_dk.dk_openmask = - sd->sc_dk.dk_copenmask | sd->sc_dk.dk_bopenmask; + unit = SDUNIT(dev); + sd = device_lookup_private(&sd_cd, unit); + dksc = &sd->sc_dksc; - if (sd->sc_dk.dk_openmask == 0) - sdlastclose(sd->sc_dev); - - mutex_exit(&sd->sc_dk.dk_openlock); - return (0); + return dk_close(dksc, dev, flag, fmt, l); } /* @@ -672,285 +612,209 @@ static void sdstrategy(struct buf *bp) { struct sd_softc *sd = device_lookup_private(&sd_cd, SDUNIT(bp->b_dev)); + struct dk_softc *dksc = &sd->sc_dksc; struct scsipi_periph *periph = sd->sc_periph; - struct scsipi_channel *chan = periph->periph_channel; - struct disklabel *lp; - daddr_t blkno; - bool sector_aligned; SC_DEBUG(sd->sc_periph, SCSIPI_DB2, ("sdstrategy ")); SC_DEBUG(sd->sc_periph, SCSIPI_DB1, ("%d bytes @ blk %" PRId64 "\n", bp->b_bcount, bp->b_blkno)); + /* * If the device has been made invalid, error out */ if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 || - !device_is_active(sd->sc_dev)) { + !device_is_active(dksc->sc_dev)) { if (periph->periph_flags & PERIPH_OPEN) bp->b_error = EIO; else bp->b_error = ENODEV; - goto done; + + bp->b_resid = bp->b_bcount; + biodone(bp); + return; } - lp = sd->sc_dk.dk_label; - - /* - * The transfer must be a whole number of blocks, offset must not be - * negative. - */ - if (lp->d_secsize == DEV_BSIZE) { - sector_aligned = (bp->b_bcount & (DEV_BSIZE - 1)) == 0; - } else { - sector_aligned = (bp->b_bcount % lp->d_secsize) == 0; - } - if (!sector_aligned || bp->b_blkno < 0) { - bp->b_error = EINVAL; - goto done; - } - /* - * If it's a null transfer, return immediatly - */ - if (bp->b_bcount == 0) - goto done; - - /* - * Do bounds checking, adjust transfer. if error, process. - * If end of partition, just return. - */ - if (SDPART(bp->b_dev) == RAW_PART) { - if (bounds_check_with_mediasize(bp, DEV_BSIZE, - sd->params.disksize512) <= 0) - goto done; - } else { - if (bounds_check_with_label(&sd->sc_dk, bp, - (sd->flags & (SDF_WLABEL|SDF_LABELLING)) != 0) <= 0) - goto done; - } - - /* - * Now convert the block number to absolute and put it in - * terms of the device's logical block size. - */ - if (lp->d_secsize == DEV_BSIZE) - blkno = bp->b_blkno; - else if (lp->d_secsize > DEV_BSIZE) - blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); - else - blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize); - - if (SDPART(bp->b_dev) != RAW_PART) - blkno += lp->d_partitions[SDPART(bp->b_dev)].p_offset; - - bp->b_rawblkno = blkno; - - mutex_enter(chan_mtx(chan)); - - /* - * Place it in the queue of disk activities for this disk. - * - * XXX Only do disksort() if the current operating mode does not - * XXX include tagged queueing. - */ - bufq_put(sd->buf_queue, bp); - - /* - * Tell the device to get going on the transfer if it's - * not doing anything, otherwise just wait for completion - */ - sdstart(periph); - - mutex_exit(chan_mtx(chan)); - return; - -done: - /* - * Correctly set the buf to indicate a completed xfer - */ - bp->b_resid = bp->b_bcount; - biodone(bp); + dk_strategy(dksc, bp); } /* - * sdstart looks to see if there is a buf waiting for the device - * and that the device is not already busy. If both are true, - * It dequeues the buf and creates a scsi command to perform the - * transfer in the buf. The transfer request will call scsipi_done - * on completion, which will in turn call this routine again - * so that the next queued transfer is performed. - * The bufs are queued by the strategy routine (sdstrategy) + * Issue single I/O command * - * This routine is also called after other non-queued requests - * have been made of the scsi driver, to ensure that the queue - * continues to be drained. - * - * must be called with channel lock held - * sdstart() is called from sdstrategy, sdrestart and scsipi_done + * Called from dk_start and implicitely from dk_strategy */ -static void -sdstart(struct scsipi_periph *periph) +static int +sd_diskstart(device_t dev, struct buf *bp) { - struct sd_softc *sd = device_private(periph->periph_dev); - struct disklabel *lp = sd->sc_dk.dk_label; - struct buf *bp = 0; + struct sd_softc *sd = device_private(dev); + struct scsipi_periph *periph = sd->sc_periph; + struct scsipi_channel *chan = periph->periph_channel; struct scsipi_rw_16 cmd16; struct scsipi_rw_10 cmd_big; struct scsi_rw_6 cmd_small; struct scsipi_generic *cmdp; struct scsipi_xfer *xs; - int nblks, cmdlen, error __diagused, flags; + int error, flags, nblks, cmdlen; - SC_DEBUG(periph, SCSIPI_DB2, ("sdstart ")); + mutex_enter(chan_mtx(chan)); + + if (periph->periph_active >= periph->periph_openings) { + error = EAGAIN; + goto out; + } /* - * Check if the device has room for another command + * there is excess capacity, but a special waits + * It'll need the adapter as soon as we clear out of the + * way and let it run (user level wait). */ - while (periph->periph_active < periph->periph_openings) { - /* - * there is excess capacity, but a special waits - * It'll need the adapter as soon as we clear out of the - * way and let it run (user level wait). - */ - if (periph->periph_flags & PERIPH_WAITING) { - periph->periph_flags &= ~PERIPH_WAITING; - cv_broadcast(periph_cv_periph(periph)); - return; - } - - /* - * If the device has become invalid, abort all the - * reads and writes until all files have been closed and - * re-opened - */ - if (__predict_false( - (periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) { - if ((bp = bufq_get(sd->buf_queue)) != NULL) { - bp->b_error = EIO; - bp->b_resid = bp->b_bcount; - biodone(bp); - continue; - } else { - return; - } - } - - /* - * See if there is a buf with work for us to do.. - */ - if ((bp = bufq_peek(sd->buf_queue)) == NULL) - return; - - /* - * We have a buf, now we should make a command. - */ - - if (lp->d_secsize == DEV_BSIZE) - nblks = bp->b_bcount >> DEV_BSHIFT; - else - nblks = howmany(bp->b_bcount, lp->d_secsize); - - /* - * Fill out the scsi command. Use the smallest CDB possible - * (6-byte, 10-byte, or 16-byte). - */ - if (((bp->b_rawblkno & 0x1fffff) == bp->b_rawblkno) && - ((nblks & 0xff) == nblks) && - !(periph->periph_quirks & PQUIRK_ONLYBIG)) { - /* 6-byte CDB */ - memset(&cmd_small, 0, sizeof(cmd_small)); - cmd_small.opcode = (bp->b_flags & B_READ) ? - SCSI_READ_6_COMMAND : SCSI_WRITE_6_COMMAND; - _lto3b(bp->b_rawblkno, cmd_small.addr); - cmd_small.length = nblks & 0xff; - cmdlen = sizeof(cmd_small); - cmdp = (struct scsipi_generic *)&cmd_small; - } else if ((bp->b_rawblkno & 0xffffffff) == bp->b_rawblkno) { - /* 10-byte CDB */ - memset(&cmd_big, 0, sizeof(cmd_big)); - cmd_big.opcode = (bp->b_flags & B_READ) ? - READ_10 : WRITE_10; - _lto4b(bp->b_rawblkno, cmd_big.addr); - _lto2b(nblks, cmd_big.length); - cmdlen = sizeof(cmd_big); - cmdp = (struct scsipi_generic *)&cmd_big; - } else { - /* 16-byte CDB */ - memset(&cmd16, 0, sizeof(cmd16)); - cmd16.opcode = (bp->b_flags & B_READ) ? - READ_16 : WRITE_16; - _lto8b(bp->b_rawblkno, cmd16.addr); - _lto4b(nblks, cmd16.length); - cmdlen = sizeof(cmd16); - cmdp = (struct scsipi_generic *)&cmd16; - } - - /* Instrumentation. */ - disk_busy(&sd->sc_dk); - - /* - * Mark the disk dirty so that the cache will be - * flushed on close. - */ - if ((bp->b_flags & B_READ) == 0) - sd->flags |= SDF_DIRTY; - - /* - * Figure out what flags to use. - */ - flags = XS_CTL_NOSLEEP|XS_CTL_ASYNC|XS_CTL_SIMPLE_TAG; - if (bp->b_flags & B_READ) - flags |= XS_CTL_DATA_IN; - else - flags |= XS_CTL_DATA_OUT; - - /* - * Call the routine that chats with the adapter. - * Note: we cannot sleep as we may be an interrupt - */ - xs = scsipi_make_xs_locked(periph, cmdp, cmdlen, - (u_char *)bp->b_data, bp->b_bcount, - SDRETRIES, SD_IO_TIMEOUT, bp, flags); - if (__predict_false(xs == NULL)) { - /* - * out of memory. Keep this buffer in the queue, and - * retry later. - */ - callout_reset(&sd->sc_callout, hz / 2, sdrestart, - periph); - return; - } - /* - * need to dequeue the buffer before queuing the command, - * because cdstart may be called recursively from the - * HBA driver - */ -#ifdef DIAGNOSTIC - if (bufq_get(sd->buf_queue) != bp) - panic("sdstart(): dequeued wrong buf"); -#else - bufq_get(sd->buf_queue); -#endif - error = scsipi_execute_xs(xs); - /* with a scsipi_xfer preallocated, scsipi_command can't fail */ - KASSERT(error == 0); + if (periph->periph_flags & PERIPH_WAITING) { + periph->periph_flags &= ~PERIPH_WAITING; + cv_broadcast(periph_cv_periph(periph)); + error = EAGAIN; + goto out; } + + /* + * If the device has become invalid, abort all the + * reads and writes until all files have been closed and + * re-opened + */ + if (__predict_false( + (periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) { + error = EIO; + goto out; + } + + /* + * Mark the disk dirty so that the cache will be + * flushed on close. + */ + if ((bp->b_flags & B_READ) == 0) + sd->flags |= SDF_DIRTY; + + if (sd->params.blksize == DEV_BSIZE) + nblks = bp->b_bcount >> DEV_BSHIFT; + else + nblks = howmany(bp->b_bcount, sd->params.blksize); + + /* + * Fill out the scsi command. Use the smallest CDB possible + * (6-byte, 10-byte, or 16-byte). + */ + if (((bp->b_rawblkno & 0x1fffff) == bp->b_rawblkno) && + ((nblks & 0xff) == nblks) && + !(periph->periph_quirks & PQUIRK_ONLYBIG)) { + /* 6-byte CDB */ + memset(&cmd_small, 0, sizeof(cmd_small)); + cmd_small.opcode = (bp->b_flags & B_READ) ? + SCSI_READ_6_COMMAND : SCSI_WRITE_6_COMMAND; + _lto3b(bp->b_rawblkno, cmd_small.addr); + cmd_small.length = nblks & 0xff; + cmdlen = sizeof(cmd_small); + cmdp = (struct scsipi_generic *)&cmd_small; + } else if ((bp->b_rawblkno & 0xffffffff) == bp->b_rawblkno) { + /* 10-byte CDB */ + memset(&cmd_big, 0, sizeof(cmd_big)); + cmd_big.opcode = (bp->b_flags & B_READ) ? + READ_10 : WRITE_10; + _lto4b(bp->b_rawblkno, cmd_big.addr); + _lto2b(nblks, cmd_big.length); + cmdlen = sizeof(cmd_big); + cmdp = (struct scsipi_generic *)&cmd_big; + } else { + /* 16-byte CDB */ + memset(&cmd16, 0, sizeof(cmd16)); + cmd16.opcode = (bp->b_flags & B_READ) ? + READ_16 : WRITE_16; + _lto8b(bp->b_rawblkno, cmd16.addr); + _lto4b(nblks, cmd16.length); + cmdlen = sizeof(cmd16); + cmdp = (struct scsipi_generic *)&cmd16; + } + + /* + * Figure out what flags to use. + */ + flags = XS_CTL_NOSLEEP|XS_CTL_ASYNC|XS_CTL_SIMPLE_TAG; + if (bp->b_flags & B_READ) + flags |= XS_CTL_DATA_IN; + else + flags |= XS_CTL_DATA_OUT; + + /* + * Call the routine that chats with the adapter. + * Note: we cannot sleep as we may be an interrupt + */ + xs = scsipi_make_xs_locked(periph, cmdp, cmdlen, + (u_char *)bp->b_data, bp->b_bcount, + SDRETRIES, SD_IO_TIMEOUT, bp, flags); + if (__predict_false(xs == NULL)) { + /* + * out of memory. Keep this buffer in the queue, and + * retry later. + */ + callout_reset(&sd->sc_callout, hz / 2, sdrestart, sd); + error = 0; + goto out; + } + + error = scsipi_execute_xs(xs); + /* with a scsipi_xfer preallocated, scsipi_command can't fail */ + KASSERT(error == 0); + +out: + mutex_exit(chan_mtx(chan)); + + return error; } +/* + * Recover I/O request after memory shortage + * + * Called from callout + */ static void sdrestart(void *v) { - struct scsipi_periph *periph = v; + struct sd_softc *sd = v; + struct dk_softc *dksc = &sd->sc_dksc; + + dk_start(dksc, NULL); +} + +/* + * Recover I/O request after memory shortage + * + * Called from scsipi midlayer when resources have been freed + * with channel lock held + */ +static void +sdstart(struct scsipi_periph *periph) +{ + struct sd_softc *sd = device_private(periph->periph_dev); + struct dk_softc *dksc = &sd->sc_dksc; struct scsipi_channel *chan = periph->periph_channel; - mutex_enter(chan_mtx(chan)); - sdstart((struct scsipi_periph *)v); + /* + * release channel lock as dk_start may need to acquire + * other locks + * + * sdstart is called from scsipi_put_xs and all its callers + * release the lock afterwards. So releasing it here + * doesn't matter. + */ mutex_exit(chan_mtx(chan)); + + dk_start(dksc, NULL); + + mutex_enter(chan_mtx(chan)); } static void sddone(struct scsipi_xfer *xs, int error) { struct sd_softc *sd = device_private(xs->xs_periph->periph_dev); + struct dk_softc *dksc = &sd->sc_dksc; struct buf *bp = xs->bp; if (sd->flags & SDF_FLUSHING) { @@ -966,11 +830,7 @@ sddone(struct scsipi_xfer *xs, int error) bp->b_resid = bp->b_bcount; } - disk_unbusy(&sd->sc_dk, bp->b_bcount - bp->b_resid, - (bp->b_flags & B_READ)); - rnd_add_uint32(&sd->rnd_source, bp->b_rawblkno); - - biodone(bp); + dk_done(dksc, bp); } } @@ -978,6 +838,7 @@ static void sdminphys(struct buf *bp) { struct sd_softc *sd = device_lookup_private(&sd_cd, SDUNIT(bp->b_dev)); + struct dk_softc *dksc = &sd->sc_dksc; long xmax; /* @@ -994,7 +855,7 @@ sdminphys(struct buf *bp) if ((sd->flags & SDF_ANCIENT) && ((sd->sc_periph->periph_flags & (PERIPH_REMOVABLE | PERIPH_MEDIA_LOADED)) != PERIPH_REMOVABLE)) { - xmax = sd->sc_dk.dk_label->d_secsize * 0xff; + xmax = dksc->sc_dkdev.dk_geom.dg_secsize * 0xff; if (bp->b_bcount > xmax) bp->b_bcount = xmax; @@ -1003,6 +864,21 @@ sdminphys(struct buf *bp) scsipi_adapter_minphys(sd->sc_periph->periph_channel, bp); } +static void +sd_iosize(device_t dev, int *count) +{ + struct buf B; + int bmaj; + + bmaj = bdevsw_lookup_major(&sd_bdevsw); + B.b_dev = MAKESDDEV(bmaj,device_unit(dev),RAW_PART); + B.b_bcount = *count; + + sdminphys(&B); + + *count = B.b_bcount; +} + static int sdread(dev_t dev, struct uio *uio, int ioflag) { @@ -1025,12 +901,11 @@ static int sdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) { struct sd_softc *sd = device_lookup_private(&sd_cd, SDUNIT(dev)); + struct dk_softc *dksc = &sd->sc_dksc; struct scsipi_periph *periph = sd->sc_periph; + int part = SDPART(dev); int error; -#ifdef __HAVE_OLD_DISKLABEL - struct disklabel *newlabel = NULL; -#endif SC_DEBUG(sd->sc_periph, SCSIPI_DB2, ("sdioctl 0x%lx ", cmd)); @@ -1038,110 +913,17 @@ sdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) * If the device is not valid, some IOCTLs can still be * handled on the raw partition. Check this here. */ - if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) { - switch (cmd) { - case DIOCKLABEL: - case DIOCWLABEL: - case DIOCLOCK: - case DIOCEJECT: - case ODIOCEJECT: - case DIOCGCACHE: - case DIOCSCACHE: - case DIOCGSTRATEGY: - case DIOCSSTRATEGY: - case SCIOCIDENTIFY: - case OSCIOCIDENTIFY: - case SCIOCCOMMAND: - case SCIOCDEBUG: - if (part == RAW_PART) - break; - /* FALLTHROUGH */ - default: - if ((periph->periph_flags & PERIPH_OPEN) == 0) - return (ENODEV); - else - return (EIO); - } - } + if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 && + part != RAW_PART) + return (EIO); - error = disk_ioctl(&sd->sc_dk, dev, cmd, addr, flag, l); - if (error != EPASSTHROUGH) - return (error); - - error = 0; switch (cmd) { - case DIOCWDINFO: - case DIOCSDINFO: -#ifdef __HAVE_OLD_DISKLABEL - case ODIOCWDINFO: - case ODIOCSDINFO: -#endif - { - struct disklabel *lp; - - if ((flag & FWRITE) == 0) - return (EBADF); - -#ifdef __HAVE_OLD_DISKLABEL - if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { - newlabel = malloc(sizeof *newlabel, M_TEMP, - M_WAITOK | M_ZERO); - if (newlabel == NULL) - return EIO; - memcpy(newlabel, addr, sizeof (struct olddisklabel)); - lp = newlabel; - } else -#endif - lp = (struct disklabel *)addr; - - mutex_enter(&sd->sc_dk.dk_openlock); - sd->flags |= SDF_LABELLING; - - error = setdisklabel(sd->sc_dk.dk_label, - lp, /*sd->sc_dk.dk_openmask : */0, - sd->sc_dk.dk_cpulabel); - if (error == 0) { - if (cmd == DIOCWDINFO -#ifdef __HAVE_OLD_DISKLABEL - || cmd == ODIOCWDINFO -#endif - ) - error = writedisklabel(SDLABELDEV(dev), - sdstrategy, sd->sc_dk.dk_label, - sd->sc_dk.dk_cpulabel); - } - - sd->flags &= ~SDF_LABELLING; - mutex_exit(&sd->sc_dk.dk_openlock); -#ifdef __HAVE_OLD_DISKLABEL - if (newlabel != NULL) - free(newlabel, M_TEMP); -#endif - return (error); - } - - case DIOCKLABEL: - if (*(int *)addr) - periph->periph_flags |= PERIPH_KEEP_LABEL; - else - periph->periph_flags &= ~PERIPH_KEEP_LABEL; - return (0); - - case DIOCWLABEL: - if ((flag & FWRITE) == 0) - return (EBADF); - if (*(int *)addr) - sd->flags |= SDF_WLABEL; - else - sd->flags &= ~SDF_WLABEL; - return (0); - case DIOCLOCK: if (periph->periph_flags & PERIPH_REMOVABLE) return (scsipi_prevent(periph, (*(int *)addr) ? SPAMR_PREVENT_DT : SPAMR_ALLOW, 0)); - else + else return (ENOTTY); case DIOCEJECT: @@ -1152,9 +934,7 @@ sdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) * Don't force eject: check that we are the only * partition open. If so, unlock it. */ - if ((sd->sc_dk.dk_openmask & ~(1 << part)) == 0 && - sd->sc_dk.dk_bopenmask + sd->sc_dk.dk_copenmask == - sd->sc_dk.dk_openmask) { + if (DK_BUSY(dksc, part) == 0) { error = scsipi_prevent(periph, SPAMR_ALLOW, XS_CTL_IGNORE_NOT_READY); if (error) @@ -1168,24 +948,6 @@ sdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) return ((periph->periph_flags & PERIPH_REMOVABLE) == 0 ? ENOTTY : scsipi_start(periph, SSS_STOP|SSS_LOEJ, 0)); - case DIOCGDEFLABEL: - sdgetdefaultlabel(sd, (struct disklabel *)addr); - return (0); - -#ifdef __HAVE_OLD_DISKLABEL - case ODIOCGDEFLABEL: - newlabel = malloc(sizeof *newlabel, M_TEMP, M_WAITOK); - if (newlabel == NULL) - return EIO; - sdgetdefaultlabel(sd, newlabel); - if (newlabel->d_npartitions <= OLDMAXPARTITIONS) - memcpy(addr, newlabel, sizeof (struct olddisklabel)); - else - error = ENOTTY; - free(newlabel, M_TEMP); - return error; -#endif - case DIOCGCACHE: return (sd_getcache(sd, (int *) addr)); @@ -1203,61 +965,19 @@ sdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) return (EBADF); if (((sd->flags & SDF_DIRTY) != 0 || *(int *)addr != 0)) { error = sd_flush(sd, 0); - if (error) + if (error) { sd->flags &= ~SDF_FLUSHING; - else - sd->flags &= ~(SDF_FLUSHING|SDF_DIRTY); + return (error); + } + sd->flags &= ~(SDF_FLUSHING|SDF_DIRTY); } - return (error); - - case DIOCGSTRATEGY: - { - struct disk_strategy *dks = addr; - int s; - - s = splbio(); - strlcpy(dks->dks_name, bufq_getstrategyname(sd->buf_queue), - sizeof(dks->dks_name)); - splx(s); - dks->dks_paramlen = 0; - - return 0; - } - - case DIOCSSTRATEGY: - { - struct disk_strategy *dks = addr; - struct bufq_state *new_bufq; - struct bufq_state *old_bufq; - int s; - - if ((flag & FWRITE) == 0) { - return EBADF; - } - - if (dks->dks_param != NULL) { - return EINVAL; - } - dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */ - error = bufq_alloc(&new_bufq, dks->dks_name, - BUFQ_EXACT|BUFQ_SORT_RAWBLOCK); - if (error) { - return error; - } - s = splbio(); - old_bufq = sd->buf_queue; - bufq_move(new_bufq, old_bufq); - sd->buf_queue = new_bufq; - splx(s); - bufq_free(old_bufq); - - return 0; - } + return (0); default: - if (part != RAW_PART) - return (ENOTTY); - return (scsipi_do_ioctl(periph, dev, cmd, addr, flag, l)); + error = dk_ioctl(dksc, dev, cmd, addr, flag, l); + if (error == ENOTTY) + error = scsipi_do_ioctl(periph, dev, cmd, addr, flag, l); + return (error); } #ifdef DIAGNOSTIC @@ -1266,86 +986,21 @@ sdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) } static void -sdgetdefaultlabel(struct sd_softc *sd, struct disklabel *lp) -{ +sd_label(device_t self, struct disklabel *lp) +{ + struct sd_softc *sd = device_private(self); - memset(lp, 0, sizeof(struct disklabel)); - - lp->d_secsize = sd->params.blksize; - lp->d_ntracks = sd->params.heads; - lp->d_nsectors = sd->params.sectors; - lp->d_ncylinders = sd->params.cyls; - lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; - - switch (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sd->sc_periph))) { - case SCSIPI_BUSTYPE_SCSI: - lp->d_type = DKTYPE_SCSI; - break; - case SCSIPI_BUSTYPE_ATAPI: - lp->d_type = DKTYPE_ATAPI; - break; - } - /* - * XXX - * We could probe the mode pages to figure out what kind of disc it is. - * Is this worthwhile? - */ strncpy(lp->d_typename, sd->name, 16); - strncpy(lp->d_packname, "fictitious", 16); - if (sd->params.disksize > UINT32_MAX) - lp->d_secperunit = UINT32_MAX; - else - lp->d_secperunit = sd->params.disksize; lp->d_rpm = sd->params.rot_rate; - lp->d_interleave = 1; - lp->d_flags = sd->sc_periph->periph_flags & PERIPH_REMOVABLE ? - D_REMOVABLE : 0; - - lp->d_partitions[RAW_PART].p_offset = 0; - lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; - lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; - lp->d_npartitions = RAW_PART + 1; - - lp->d_magic = DISKMAGIC; - lp->d_magic2 = DISKMAGIC; - lp->d_checksum = dkcksum(lp); -} - - -/* - * Load the label information on the named device - */ -static int -sdgetdisklabel(struct sd_softc *sd) -{ - struct disklabel *lp = sd->sc_dk.dk_label; - const char *errstring; - - memset(sd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel)); - - sdgetdefaultlabel(sd, lp); - - if (lp->d_secpercyl == 0) { - lp->d_secpercyl = 100; - /* as long as it's not 0 - readdisklabel divides by it (?) */ - } - - /* - * Call the generic disklabel extraction routine - */ - errstring = readdisklabel(MAKESDDEV(0, device_unit(sd->sc_dev), - RAW_PART), sdstrategy, lp, sd->sc_dk.dk_cpulabel); - if (errstring) { - aprint_error_dev(sd->sc_dev, "%s\n", errstring); - return EIO; - } - return 0; + if (sd->sc_periph->periph_flags & PERIPH_REMOVABLE) + lp->d_flags |= D_REMOVABLE; } static bool sd_shutdown(device_t self, int how) { struct sd_softc *sd = device_private(self); + struct dk_softc *dksc = &sd->sc_dksc; /* * If the disk cache needs to be flushed, and the disk supports @@ -1354,7 +1009,7 @@ sd_shutdown(device_t self, int how) */ if ((sd->flags & SDF_DIRTY) != 0) { if (sd_flush(sd, XS_CTL_NOSLEEP|XS_CTL_POLL)) { - aprint_error_dev(sd->sc_dev, + aprint_error_dev(dksc->sc_dev, "cache synchronization failed\n"); sd->flags &= ~SDF_FLUSHING; } else @@ -1379,6 +1034,7 @@ sd_interpret_sense(struct scsipi_xfer *xs) struct scsipi_channel *chan = periph->periph_channel; struct scsi_sense_data *sense = &xs->sense.scsi_sense; struct sd_softc *sd = device_private(periph->periph_dev); + struct dk_softc *dksc = &sd->sc_dksc; int error, retval = EJUSTRETURN; /* @@ -1428,7 +1084,7 @@ sd_interpret_sense(struct scsipi_xfer *xs) * Unit In The Process Of Becoming Ready. */ printf("%s: waiting for pack to spin up...\n", - device_xname(sd->sc_dev)); + dksc->sc_xname); if (!callout_pending(&periph->periph_callout)) scsipi_periph_freeze(periph, 1); callout_reset(&periph->periph_callout, @@ -1436,7 +1092,7 @@ sd_interpret_sense(struct scsipi_xfer *xs) retval = ERESTART; } else if (sense->ascq == 0x02) { printf("%s: pack is stopped, restarting...\n", - device_xname(sd->sc_dev)); + dksc->sc_xname); mutex_enter(chan_mtx(chan)); periph->periph_flags |= PERIPH_RECOVERING; mutex_exit(chan_mtx(chan)); @@ -1444,7 +1100,7 @@ sd_interpret_sense(struct scsipi_xfer *xs) XS_CTL_URGENT|XS_CTL_HEAD_TAG| XS_CTL_THAW_PERIPH|XS_CTL_FREEZE_PERIPH); if (error) { - aprint_error_dev(sd->sc_dev, + aprint_error_dev(dksc->sc_dev, "unable to restart pack\n"); retval = error; } else @@ -1468,37 +1124,23 @@ static int sdsize(dev_t dev) { struct sd_softc *sd; - int part, unit, omask; - int size; + struct dk_softc *dksc; + int unit; unit = SDUNIT(dev); sd = device_lookup_private(&sd_cd, unit); if (sd == NULL) return (-1); + dksc = &sd->sc_dksc; - if (!device_is_active(sd->sc_dev)) + if (!device_is_active(dksc->sc_dev)) return (-1); - part = SDPART(dev); - omask = sd->sc_dk.dk_openmask & (1 << part); - - if (omask == 0 && sdopen(dev, 0, S_IFBLK, NULL) != 0) - return (-1); - if ((sd->sc_periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) - size = -1; - else if (sd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) - size = -1; - else - size = sd->sc_dk.dk_label->d_partitions[part].p_size * - (sd->sc_dk.dk_label->d_secsize / DEV_BSIZE); - if (omask == 0 && sdclose(dev, 0, S_IFBLK, NULL) != 0) - return (-1); - return (size); + return dk_size(dksc, dev); } /* #define SD_DUMP_NOT_TRUSTED if you just want to watch */ static struct scsipi_xfer sx; -static int sddoingadump; /* * dump all of physical memory into the partition specified, starting @@ -1507,115 +1149,90 @@ static int sddoingadump; static int sddump(dev_t dev, daddr_t blkno, void *va, size_t size) { - struct sd_softc *sd; /* disk unit to do the I/O */ - struct disklabel *lp; /* disk's disklabel */ - int unit, part; - int sectorsize; /* size of a disk sector */ - int nsects; /* number of sectors in partition */ - int sectoff; /* sector offset of partition */ - int totwrt; /* total number of sectors left to write */ - int nwrt; /* current number of sectors to write */ - struct scsipi_rw_10 cmd; /* write command */ - struct scsipi_xfer *xs; /* ... convenience */ + struct sd_softc *sd; + struct dk_softc *dksc; struct scsipi_periph *periph; - struct scsipi_channel *chan; + int unit; - /* Check if recursive dump; if so, punt. */ - if (sddoingadump) - return (EFAULT); - - /* Mark as active early. */ - sddoingadump = 1; - - unit = SDUNIT(dev); /* Decompose unit & partition. */ - part = SDPART(dev); - - /* Check for acceptable drive number. */ - sd = device_lookup_private(&sd_cd, unit); - if (sd == NULL) + unit = SDUNIT(dev); + if ((sd = device_lookup_private(&sd_cd, unit)) == NULL) return (ENXIO); + dksc = &sd->sc_dksc; - if (!device_is_active(sd->sc_dev)) + if (!device_is_active(dksc->sc_dev)) return (ENODEV); periph = sd->sc_periph; - chan = periph->periph_channel; /* Make sure it was initialized. */ if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) return (ENXIO); - /* Convert to disk sectors. Request must be a multiple of size. */ - lp = sd->sc_dk.dk_label; - sectorsize = lp->d_secsize; - if ((size % sectorsize) != 0) - return (EFAULT); - totwrt = size / sectorsize; - blkno = dbtob(blkno) / sectorsize; /* blkno in DEV_BSIZE units */ + return dk_dump(dksc, dev, blkno, va, size); +} - nsects = lp->d_partitions[part].p_size; - sectoff = lp->d_partitions[part].p_offset; +static int +sd_dumpblocks(device_t dev, void *va, daddr_t blkno, int nblk) +{ + struct sd_softc *sd = device_private(dev); + struct dk_softc *dksc = &sd->sc_dksc; + struct disk_geom *dg = &dksc->sc_dkdev.dk_geom; + struct scsipi_rw_10 cmd; /* write command */ + struct scsipi_xfer *xs; /* ... convenience */ + struct scsipi_periph *periph; + struct scsipi_channel *chan; + size_t sectorsize; - /* Check transfer bounds against partition size. */ - if ((blkno < 0) || ((blkno + totwrt) > nsects)) - return (EINVAL); + periph = sd->sc_periph; + chan = periph->periph_channel; - /* Offset block number to start of partition. */ - blkno += sectoff; + sectorsize = dg->dg_secsize; xs = &sx; - while (totwrt > 0) { - nwrt = totwrt; /* XXX */ #ifndef SD_DUMP_NOT_TRUSTED - /* - * Fill out the scsi command - */ - memset(&cmd, 0, sizeof(cmd)); - cmd.opcode = WRITE_10; - _lto4b(blkno, cmd.addr); - _lto2b(nwrt, cmd.length); - /* - * Fill out the scsipi_xfer structure - * Note: we cannot sleep as we may be an interrupt - * don't use scsipi_command() as it may want to wait - * for an xs. - */ - memset(xs, 0, sizeof(sx)); - xs->xs_control |= XS_CTL_NOSLEEP | XS_CTL_POLL | - XS_CTL_DATA_OUT; - xs->xs_status = 0; - xs->xs_periph = periph; - xs->xs_retries = SDRETRIES; - xs->timeout = 10000; /* 10000 millisecs for a disk ! */ - xs->cmd = (struct scsipi_generic *)&cmd; - xs->cmdlen = sizeof(cmd); - xs->resid = nwrt * sectorsize; - xs->error = XS_NOERROR; - xs->bp = 0; - xs->data = va; - xs->datalen = nwrt * sectorsize; - callout_init(&xs->xs_callout, 0); + /* + * Fill out the scsi command + */ + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = WRITE_10; + _lto4b(blkno, cmd.addr); + _lto2b(nblk, cmd.length); + /* + * Fill out the scsipi_xfer structure + * Note: we cannot sleep as we may be an interrupt + * don't use scsipi_command() as it may want to wait + * for an xs. + */ + memset(xs, 0, sizeof(sx)); + xs->xs_control |= XS_CTL_NOSLEEP | XS_CTL_POLL | + XS_CTL_DATA_OUT; + xs->xs_status = 0; + xs->xs_periph = periph; + xs->xs_retries = SDRETRIES; + xs->timeout = 10000; /* 10000 millisecs for a disk ! */ + xs->cmd = (struct scsipi_generic *)&cmd; + xs->cmdlen = sizeof(cmd); + xs->resid = nblk * sectorsize; + xs->error = XS_NOERROR; + xs->bp = 0; + xs->data = va; + xs->datalen = nblk * sectorsize; + callout_init(&xs->xs_callout, 0); - /* - * Pass all this info to the scsi driver. - */ - scsipi_adapter_request(chan, ADAPTER_REQ_RUN_XFER, xs); - if ((xs->xs_status & XS_STS_DONE) == 0 || - xs->error != XS_NOERROR) - return (EIO); + /* + * Pass all this info to the scsi driver. + */ + scsipi_adapter_request(chan, ADAPTER_REQ_RUN_XFER, xs); + if ((xs->xs_status & XS_STS_DONE) == 0 || + xs->error != XS_NOERROR) + return (EIO); #else /* SD_DUMP_NOT_TRUSTED */ - /* Let's just talk about this first... */ - printf("sd%d: dump addr 0x%x, blk %d\n", unit, va, blkno); - delay(500 * 1000); /* half a second */ + /* Let's just talk about this first... */ + printf("sd%d: dump addr 0x%x, blk %d\n", unit, va, blkno); + delay(500 * 1000); /* half a second */ #endif /* SD_DUMP_NOT_TRUSTED */ - /* update block count */ - totwrt -= nwrt; - blkno += nwrt; - va = (char *)va + sectorsize * nwrt; - } - sddoingadump = 0; return (0); } @@ -2084,6 +1701,7 @@ printf("page 5 ok\n"); static int sd_get_parms(struct sd_softc *sd, struct disk_parms *dp, int flags) { + struct dk_softc *dksc = &sd->sc_dksc; int error; /* @@ -2115,7 +1733,7 @@ sd_get_parms(struct sd_softc *sd, struct disk_parms *dp, int flags) } page0: - printf("%s: fabricating a geometry\n", device_xname(sd->sc_dev)); + printf("%s: fabricating a geometry\n", dksc->sc_xname); /* Try calling driver's method for figuring out geometry. */ if (!sd->sc_periph->periph_channel->chan_adapter->adapt_getgeom || !(*sd->sc_periph->periph_channel->chan_adapter->adapt_getgeom) @@ -2272,7 +1890,8 @@ sd_setcache(struct sd_softc *sd, int bits) static void sd_set_geometry(struct sd_softc *sd) { - struct disk_geom *dg = &sd->sc_dk.dk_geom; + struct dk_softc *dksc = &sd->sc_dksc; + struct disk_geom *dg = &dksc->sc_dkdev.dk_geom; memset(dg, 0, sizeof(*dg)); @@ -2282,5 +1901,5 @@ sd_set_geometry(struct sd_softc *sd) dg->dg_ntracks = sd->params.heads; dg->dg_ncylinders = sd->params.cyls; - disk_set_info(sd->sc_dev, &sd->sc_dk, NULL); + disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL); } diff --git a/sys/dev/scsipi/sdvar.h b/sys/dev/scsipi/sdvar.h index aa28c8ad2df4..8eb087722f4a 100644 --- a/sys/dev/scsipi/sdvar.h +++ b/sys/dev/scsipi/sdvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: sdvar.h,v 1.37 2015/08/24 23:13:15 pooka Exp $ */ +/* $NetBSD: sdvar.h,v 1.38 2016/12/10 10:26:38 mlelstv Exp $ */ /*- * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. @@ -53,7 +53,7 @@ #include "opt_scsi.h" #endif -#include +#include #ifndef SDRETRIES #define SDRETRIES 4 @@ -74,12 +74,9 @@ struct disk_parms { }; struct sd_softc { - device_t sc_dev; - struct disk sc_dk; + struct dk_softc sc_dksc; int flags; -#define SDF_WLABEL 0x04 /* label is writable */ -#define SDF_LABELLING 0x08 /* writing label */ #define SDF_ANCIENT 0x10 /* disk is ancient; for minphys */ #define SDF_DIRTY 0x20 /* disk is dirty; needs cache flush */ #define SDF_FLUSHING 0x40 /* flushing, for sddone() */ @@ -88,12 +85,9 @@ struct sd_softc { struct disk_parms params; - struct bufq_state *buf_queue; callout_t sc_callout; u_int8_t type; char name[16]; /* product name, for default disklabel */ - - krndsource_t rnd_source; }; #define SDGP_RESULT_OK 0 /* parameters obtained */