summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authormjacob <mjacob@FreeBSD.org>1999-11-17 06:05:09 +0000
committermjacob <mjacob@FreeBSD.org>1999-11-17 06:05:09 +0000
commit4d7a907aa04fc0fbe3df7935f159d2e3ec94a7bc (patch)
tree23521cd3f8d8f264593c6268fe42b1e75ff128f9 /sys/cam
parentf491f5dd5845fe6d70d12f3e4078f19e7d0e0937 (diff)
downloadFreeBSD-src-4d7a907aa04fc0fbe3df7935f159d2e3ec94a7bc.zip
FreeBSD-src-4d7a907aa04fc0fbe3df7935f159d2e3ec94a7bc.tar.gz
Fix for 11815 (at mount time do a throwaway read of the front of the
tape to force the drive to do a media access so it knows what media may be inserted). Also Ken's make_dev patches- relatively untested.
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/scsi/scsi_sa.c452
1 files changed, 321 insertions, 131 deletions
diff --git a/sys/cam/scsi/scsi_sa.c b/sys/cam/scsi/scsi_sa.c
index 0d5326c..735da5e 100644
--- a/sys/cam/scsi/scsi_sa.c
+++ b/sys/cam/scsi/scsi_sa.c
@@ -78,13 +78,28 @@
#ifndef SA_ERASE_TIMEOUT
#define SA_ERASE_TIMEOUT 4 * 60
#endif
+
+#define REWIND_TIMEOUT (SA_REWIND_TIMEOUT * 60 * 10000)
+#define ERASE_TIMEOUT (SA_ERASE_TIMEOUT * 60 * 10000)
+#define SPACE_TIMEOUT (SA_SPACE_TIMEOUT * 60 * 10000)
+
/*
* Additional options that can be set for config: SA_1FM_AT_EOT
*/
+
#ifndef UNUSED_PARAMETER
#define UNUSED_PARAMETER(x) x = x
#endif
+#define QFRLS(ccb) \
+ if (((ccb)->ccb_h.status & CAM_DEV_QFRZN) != 0) \
+ cam_release_devq((ccb)->ccb_h.path, 0, 0, 0, FALSE)
+
+/*
+ * Driver states
+ */
+
+
typedef enum {
SA_STATE_NORMAL, SA_STATE_ABNORMAL
} sa_state;
@@ -143,6 +158,30 @@ typedef enum {
SA_QUIRK_1FM = 0x10 /* No more than 1 File Mark at EOD */
} sa_quirks;
+#define SA_NOT_CTLDEV 0
+#define SA_CTLDEV 1
+
+#define SA_ATYPE_R 0
+#define SA_ATYPE_NR 1
+#define SA_ATYPE_ER 2
+
+#define SAMINOR(ctl, unit, mode, access) \
+ ((ctl << 29) | ((unit & 0x3f0) << 16) | (unit & 0xf) | \
+ (mode << 2) | access)
+
+#define SA_NUM_MODES 4
+struct sa_devs {
+ dev_t ctl_dev;
+ struct sa_mode_devs {
+ dev_t r_dev;
+ dev_t nr_dev;
+ dev_t er_dev;
+ } mode_devs[SA_NUM_MODES];
+ dev_t r_dev;
+ dev_t nr_dev;
+ dev_t er_dev;
+};
+
struct sa_softc {
sa_state state;
sa_flags flags;
@@ -150,6 +189,7 @@ struct sa_softc {
struct buf_queue_head buf_queue;
int queue_count;
struct devstat device_stats;
+ struct sa_devs devs;
int blk_gran;
int blk_mask;
int blk_shift;
@@ -379,61 +419,51 @@ saopen(dev_t dev, int flags, int fmt, struct proc *p)
mode = SAMODE(dev);
density = SADENSITY(dev);
+ s = splsoftcam();
periph = cam_extend_get(saperiphs, unit);
- if (periph == NULL)
+ if (periph == NULL) {
+ (void) splx(s);
return (ENXIO);
-
+ }
softc = (struct sa_softc *)periph->softc;
+ if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
+ splx(s);
+ return (error);
+ }
+ splx(s);
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO,
("saopen(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags));
- s = splsoftcam();
-
+ if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+ cam_periph_unlock(periph);
+ return(ENXIO);
+ }
if (SA_IS_CTRL(dev)) {
softc->ctrl_mode = 1;
- (void) splx(s);
+ cam_periph_unlock(periph);
return (0);
}
- if (softc->flags & SA_FLAG_INVALID) {
- splx(s);
- return(ENXIO);
- }
- if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
- splx(s);
- return (error); /* error code from tsleep */
- }
-
- splx(s);
-
- if ((softc->flags & SA_FLAG_OPEN) == 0) {
- if (cam_periph_acquire(periph) != CAM_REQ_CMP)
- return(ENXIO);
-
- if ((error = sareservereleaseunit(periph, TRUE)) != 0) {
- cam_periph_unlock(periph);
- cam_periph_release(periph);
- return(error);
- }
- }
-
- if (error == 0) {
- if ((softc->flags & SA_FLAG_OPEN) != 0) {
- error = EBUSY;
- }
-
- if (error == 0)
- error = samount(periph, flags, dev);
- /* Perform other checking... */
+ if (softc->flags & SA_FLAG_OPEN) {
+ error = EBUSY;
+ } else if (softc->flags & SA_FLAG_INVALID) {
+ error = ENXIO;
+ } else {
+ /*
+ * The function samount ensures media is loaded and ready.
+ * It also does a device RESERVE if the tape isn't yet mounted.
+ */
+ error = samount(periph, flags, dev);
}
- if (error == 0) {
+ if (error) {
+ cam_periph_release(periph);
+ } else {
saprevent(periph, PR_PREVENT);
softc->flags |= SA_FLAG_OPEN;
}
-
cam_periph_unlock(periph);
return (error);
}
@@ -458,15 +488,17 @@ saclose(dev_t dev, int flag, int fmt, struct proc *p)
("saclose(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags));
+ if ((error = cam_periph_lock(periph, PRIBIO)) != 0) {
+ return (error);
+ }
+
if (SA_IS_CTRL(dev)) {
softc->ctrl_mode = 0;
+ cam_periph_release(periph);
+ cam_periph_unlock(periph);
return (0);
}
- if ((error = cam_periph_lock(periph, PRIBIO)) != 0) {
- return (error);
- }
-
/*
* Were we writing the tape?
*/
@@ -570,8 +602,9 @@ saclose(dev_t dev, int flag, int fmt, struct proc *p)
"command to clear this state.\n");
}
- /* release the device */
- sareservereleaseunit(periph, FALSE);
+ /* release the device if it is no longer mounted */
+ if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0)
+ sareservereleaseunit(periph, FALSE);
cam_periph_unlock(periph);
cam_periph_release(periph);
@@ -707,7 +740,7 @@ saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
int unit;
int mode;
int density;
- int error;
+ int error = 0;
unit = SAUNIT(dev);
mode = SAMODE(dev);
@@ -786,6 +819,36 @@ saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
{
struct mtget *g = (struct mtget *)arg;
+ /*
+ * If this isn't the control mode device, actually go out
+ * and ask the drive again what it's set to.
+ */
+ if (!SA_IS_CTRL(dev)) {
+ u_int8_t write_protect;
+ int comp_enabled, comp_supported;
+ error = sagetparams(periph, SA_PARAM_ALL,
+ &softc->media_blksize, &softc->media_density,
+ &softc->media_numblks, &softc->buffer_mode,
+ &write_protect, &softc->speed, &comp_supported,
+ &comp_enabled, &softc->comp_algorithm, NULL);
+ if (error)
+ break;
+ if (write_protect)
+ softc->flags |= SA_FLAG_TAPE_WP;
+ else
+ softc->flags &= ~SA_FLAG_TAPE_WP;
+ softc->flags &= ~(SA_FLAG_COMP_SUPP|
+ SA_FLAG_COMP_ENABLED|SA_FLAG_COMP_UNSUPP);
+ if (comp_supported) {
+ if (softc->saved_comp_algorithm == 0)
+ softc->saved_comp_algorithm =
+ softc->comp_algorithm;
+ softc->flags |= SA_FLAG_COMP_SUPP;
+ if (comp_enabled)
+ softc->flags |= SA_FLAG_COMP_ENABLED;
+ } else
+ softc->flags |= SA_FLAG_COMP_UNSUPP;
+ }
bzero(g, sizeof(struct mtget));
g->mt_type = MT_ISAR;
if (softc->flags & SA_FLAG_COMP_UNSUPP) {
@@ -969,17 +1032,15 @@ saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
/*
* Be sure to allow media removal before
- * attempting the eject.
+ * attempting the eject. And clear flags
+ * anyway.
*/
+ softc->flags &= ~(SA_FLAG_TAPE_LOCKED|
+ SA_FLAG_TAPE_FROZEN|SA_FLAG_TAPE_MOUNTED);
saprevent(periph, PR_ALLOW);
if (error == 0)
error = saloadunload(periph, FALSE);
- else
- break;
- softc->flags &= ~(SA_FLAG_TAPE_LOCKED|
- SA_FLAG_TAPE_WRITTEN| SA_FLAG_TAPE_WRITTEN|
- SA_FLAG_TAPE_FROZEN);
break;
case MTNOP: /* no operation, sets status only */
@@ -1149,9 +1210,6 @@ sainit(void)
if (status != CAM_REQ_CMP) {
printf("sa: Failed to attach master async callback "
"due to status 0x%x!\n", status);
- } else {
- /* If we were successfull, register our devsw */
- cdevsw_add(&sa_cdevsw);
}
}
@@ -1209,10 +1267,23 @@ static void
sacleanup(struct cam_periph *periph)
{
struct sa_softc *softc;
+ int i;
softc = (struct sa_softc *)periph->softc;
devstat_remove_entry(&softc->device_stats);
+
+ destroy_dev(softc->devs.ctl_dev);
+ destroy_dev(softc->devs.r_dev);
+ destroy_dev(softc->devs.nr_dev);
+ destroy_dev(softc->devs.er_dev);
+
+ for (i = 0; i < SA_NUM_MODES; i++) {
+ destroy_dev(softc->devs.mode_devs[i].r_dev);
+ destroy_dev(softc->devs.mode_devs[i].nr_dev);
+ destroy_dev(softc->devs.mode_devs[i].er_dev);
+ }
+
cam_extend_release(saperiphs, periph->unit_number);
xpt_print_path(periph->path);
printf("removing device entry\n");
@@ -1266,6 +1337,7 @@ saregister(struct cam_periph *periph, void *arg)
struct ccb_setasync csa;
struct ccb_getdev *cgd;
caddr_t match;
+ int i;
cgd = (struct ccb_getdev *)arg;
if (periph == NULL) {
@@ -1321,12 +1393,42 @@ saregister(struct cam_periph *periph, void *arg)
* blocksize until we media is inserted. So, set a flag to
* indicate that the blocksize is unavailable right now.
*/
- devstat_add_entry(&softc->device_stats, "sa",
- periph->unit_number, 0,
- DEVSTAT_BS_UNAVAILABLE,
- cgd->pd_type | DEVSTAT_TYPE_IF_SCSI,
- DEVSTAT_PRIORITY_SA);
-
+ devstat_add_entry(&softc->device_stats, "sa", periph->unit_number, 0,
+ DEVSTAT_BS_UNAVAILABLE, cgd->pd_type | DEVSTAT_TYPE_IF_SCSI,
+ DEVSTAT_PRIORITY_SA);
+
+ softc->devs.ctl_dev = make_dev(&sa_cdevsw, SAMINOR(SA_CTLDEV,
+ periph->unit_number, 0, SA_ATYPE_R), UID_ROOT, GID_OPERATOR,
+ 0660, "r%s%d.ctl", periph->periph_name, periph->unit_number);
+
+ softc->devs.r_dev = make_dev(&sa_cdevsw, SAMINOR(SA_NOT_CTLDEV,
+ periph->unit_number, 0, SA_ATYPE_R), UID_ROOT, GID_OPERATOR,
+ 0660, "r%s%d", periph->periph_name, periph->unit_number);
+
+ softc->devs.nr_dev = make_dev(&sa_cdevsw, SAMINOR(SA_NOT_CTLDEV,
+ periph->unit_number, 0, SA_ATYPE_NR), UID_ROOT, GID_OPERATOR,
+ 0660, "nr%s%d", periph->periph_name, periph->unit_number);
+
+ softc->devs.er_dev = make_dev(&sa_cdevsw, SAMINOR(SA_NOT_CTLDEV,
+ periph->unit_number, 0, SA_ATYPE_ER), UID_ROOT, GID_OPERATOR,
+ 0660, "er%s%d", periph->periph_name, periph->unit_number);
+
+ for (i = 0; i < SA_NUM_MODES; i++) {
+ softc->devs.mode_devs[i].r_dev = make_dev(&sa_cdevsw,
+ SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_R),
+ UID_ROOT, GID_OPERATOR, 0660, "r%s%d.%d",
+ periph->periph_name, periph->unit_number, i);
+ softc->devs.mode_devs[i].nr_dev = make_dev(&sa_cdevsw,
+ SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_NR),
+ UID_ROOT, GID_OPERATOR, 0660, "nr%s%d.%d",
+ periph->periph_name, periph->unit_number, i);
+
+ softc->devs.mode_devs[i].nr_dev = make_dev(&sa_cdevsw,
+ SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_ER),
+ UID_ROOT, GID_OPERATOR, 0660, "er%s%d.%d",
+ periph->periph_name, periph->unit_number, i);
+ }
+
/*
* Add an async callback so that we get
* notified if this device goes away.
@@ -1606,7 +1708,6 @@ samount(struct cam_periph *periph, int oflags, dev_t dev)
{
struct sa_softc *softc;
union ccb *ccb;
- struct ccb_scsiio *csio;
int error;
/*
@@ -1618,30 +1719,47 @@ samount(struct cam_periph *periph, int oflags, dev_t dev)
softc = (struct sa_softc *)periph->softc;
- ccb = cam_periph_getccb(periph, 1);
- csio = &ccb->csio;
- error = 0;
-
- /*
- * This *should* determine if something has happend since the last
- * open/mount that would invalidate the mount, but is currently
- * broken.
- *
- * This will also eat any pending UAs.
- */
- scsi_test_unit_ready(csio, 1, sadone,
- MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, 5 * 60 * 1000);
/*
- * Because we're not supplying a error routine, cam_periph_runccb
- * will unfreeze the queue if there was an error.
+ * This should determine if something has happend since the last
+ * open/mount that would invalidate the mount. We do *not* want
+ * to retry this command- we just want the status. But we only
+ * do this if we're mounted already- if we're not mounted,
+ * we don't care about the unit read state and can instead use
+ * this opportunity to attempt to reserve the tape unit.
*/
- cam_periph_runccb(ccb, NULL, 0, 0, &softc->device_stats);
-
+
+ if (softc->flags & SA_FLAG_TAPE_MOUNTED) {
+ ccb = cam_periph_getccb(periph, 1);
+ scsi_test_unit_ready(&ccb->csio, 0, sadone,
+ MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, 5 * 60 * 1000);
+ error = cam_periph_runccb(ccb, saerror, 0, 0,
+ &softc->device_stats);
+ QFRLS(ccb);
+ if (error == ENXIO) {
+ softc->flags &= ~SA_FLAG_TAPE_MOUNTED;
+ scsi_test_unit_ready(&ccb->csio, 0, sadone,
+ MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, 5 * 60 * 1000);
+ error = cam_periph_runccb(ccb, saerror, 0, 0,
+ &softc->device_stats);
+ QFRLS(ccb);
+ } else if (error) {
+ /* XXX: Should we freeze the tape? */
+ softc->flags &= ~SA_FLAG_TAPE_MOUNTED;
+ xpt_print_path(ccb->ccb_h.path);
+ printf("error %d on TUR in samount\n", error);
+ }
+ } else {
+ error = sareservereleaseunit(periph, TRUE);
+ if (error) {
+ return (error);
+ }
+ ccb = cam_periph_getccb(periph, 1);
+ }
if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) {
- struct scsi_read_block_limits_data *rblim = NULL;
- int comp_enabled, comp_supported;
+ struct scsi_read_block_limits_data *rblim = NULL;
+ int comp_enabled, comp_supported;
u_int8_t write_protect, guessing = 0;
/*
@@ -1659,17 +1777,17 @@ samount(struct cam_periph *periph, int oflags, dev_t dev)
FALSE, FALSE, 1, SSD_FULL_SIZE, 60000);
error = cam_periph_runccb(ccb, saerror, 0, SF_QUIET_IR,
&softc->device_stats);
- if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
- cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
+ QFRLS(ccb);
+
/*
* In case this doesn't work, do a REWIND instead
*/
if (error) {
- scsi_rewind(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG,
- FALSE, SSD_FULL_SIZE,
- (SA_REWIND_TIMEOUT) * 60 * 1000);
+ scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG,
+ FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT);
error = cam_periph_runccb(ccb, saerror, 0, 0,
&softc->device_stats);
+ QFRLS(ccb);
}
if (error) {
xpt_release_ccb(ccb);
@@ -1677,18 +1795,47 @@ samount(struct cam_periph *periph, int oflags, dev_t dev)
}
/*
- * Next off, determine block limits.
+ * Do a dummy test read to force access to the
+ * media so that the drive will really know what's
+ * there.
*/
rblim = (struct scsi_read_block_limits_data *)
- malloc(sizeof(*rblim), M_TEMP, M_WAITOK);
+ malloc(MAXPHYS, M_TEMP, M_WAITOK);
+ if (rblim == NULL) {
+ xpt_print_path(ccb->ccb_h.path);
+ printf("no memory for test read\n");
+ xpt_release_ccb(ccb);
+ error = ENOMEM;
+ goto exit;
+ }
+ scsi_sa_read_write(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, 1,
+ FALSE, 0, MAXPHYS, (void *) rblim, MAXPHYS, SSD_FULL_SIZE,
+ 120 * 60 * 1000);
+ (void) cam_periph_runccb(ccb, saerror, 0, SF_QUIET_IR,
+ &softc->device_stats);
+ QFRLS(ccb);
+ scsi_rewind(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG,
+ FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT);
+ error = cam_periph_runccb(ccb, saerror, 0, 0,
+ &softc->device_stats);
+ QFRLS(ccb);
+ if (error) {
+ xpt_print_path(ccb->ccb_h.path);
+ printf("unable to rewind after test read\n");
+ xpt_release_ccb(ccb);
+ goto exit;
+ }
- /* it is safe to retry this */
- scsi_read_block_limits(csio, 5, sadone, MSG_SIMPLE_Q_TAG,
+ /*
+ * Next off, determine block limits.
+ */
+ scsi_read_block_limits(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG,
rblim, SSD_FULL_SIZE, 5000);
error = cam_periph_runccb(ccb, saerror, 0,
SF_RETRY_UA | SF_RETRY_SELTO, &softc->device_stats);
+ QFRLS(ccb);
xpt_release_ccb(ccb);
if (error != 0) {
@@ -1965,7 +2112,6 @@ exit:
free(rblim, M_TEMP);
if (error != 0) {
- cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
softc->dsreg = MTIO_DSREG_NIL;
} else {
softc->fileno = softc->blkno = 0;
@@ -1981,7 +2127,14 @@ exit:
} else
xpt_release_ccb(ccb);
- return (error);
+ /*
+ * If we return an error, we're not mounted any more,
+ * so release any device reservation.
+ */
+ if (error != 0) {
+ (void) sareservereleaseunit(periph, FALSE);
+ }
+ return(error);
}
static int
@@ -2018,8 +2171,8 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
struct sa_softc *softc;
struct ccb_scsiio *csio;
struct scsi_sense_data *sense;
- u_int32_t resid;
- int32_t info;
+ u_int32_t resid = 0;
+ int32_t info = 0;
int error_code, sense_key, asc, ascq;
int error, defer_action;
@@ -2060,6 +2213,13 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
(int) csio->cdb_len);
softc->last_ctl_resid = resid;
}
+ CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Key 0x%x ASC/ASCQ
+ 0x%x 0x%x flags 0x%x resid %d dxfer_len %d\n", sense_key,
+ asc, ascq, sense->flags & ~SSD_KEY_RESERVED, resid,
+ csio->dxfer_len));
+ } else {
+ CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Cam Status 0x%x\n",
+ csio->ccb_h.status & CAM_STATUS_MASK));
}
/*
@@ -2088,10 +2248,6 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
* Handle writes && reads differently.
*/
- CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Key 0x%x ASC/ASCQ 0x%x "
- "0x%x flags 0x%x resid %d dxfer_len %d\n", sense_key, asc, ascq,
- sense->flags & ~SSD_KEY_RESERVED, resid, csio->dxfer_len));
-
if (csio->cdb_io.cdb_bytes[0] == SA_WRITE) {
if (sense->flags & SSD_FILEMARK) {
xpt_print_path(csio->ccb_h.path);
@@ -2430,8 +2586,16 @@ sasetparams(struct cam_periph *periph, sa_params params_to_set,
mode_hdr = (struct scsi_mode_header_6 *)mode_buffer;
mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1];
+ ccb = cam_periph_getccb(periph, 1);
+
+retry:
+
if (params_to_set & SA_PARAM_COMPRESSION) {
- cpage = (sa_comp_t *)&mode_blk[1];
+ if (mode_blk) {
+ cpage = (sa_comp_t *)&mode_blk[1];
+ } else {
+ cpage = (sa_comp_t *)&mode_hdr[1];
+ }
bcopy(ccomp, cpage, sizeof (sa_comp_t));
} else
cpage = NULL;
@@ -2441,22 +2605,24 @@ sasetparams(struct cam_periph *periph, sa_params params_to_set,
* pass in. Otherwise, use the blocksize we got back from the
* mode select above.
*/
- if (params_to_set & SA_PARAM_BLOCKSIZE)
- scsi_ulto3b(blocksize, mode_blk->blklen);
- else
- scsi_ulto3b(current_blocksize, mode_blk->blklen);
+ if (mode_blk) {
+ if (params_to_set & SA_PARAM_BLOCKSIZE)
+ scsi_ulto3b(blocksize, mode_blk->blklen);
+ else
+ scsi_ulto3b(current_blocksize, mode_blk->blklen);
- /*
- * Set density if requested, else preserve old density.
- * SCSI_SAME_DENSITY only applies to SCSI-2 or better
- * devices, else density we've latched up in our softc.
- */
- if (params_to_set & SA_PARAM_DENSITY) {
- mode_blk->density = density;
- } else if (softc->scsi_rev > SCSI_REV_CCS) {
- mode_blk->density = SCSI_SAME_DENSITY;
- } else {
- mode_blk->density = softc->media_density;
+ /*
+ * Set density if requested, else preserve old density.
+ * SCSI_SAME_DENSITY only applies to SCSI-2 or better
+ * devices, else density we've latched up in our softc.
+ */
+ if (params_to_set & SA_PARAM_DENSITY) {
+ mode_blk->density = density;
+ } else if (softc->scsi_rev > SCSI_REV_CCS) {
+ mode_blk->density = SCSI_SAME_DENSITY;
+ } else {
+ mode_blk->density = softc->media_density;
+ }
}
/*
@@ -2471,7 +2637,10 @@ sasetparams(struct cam_periph *periph, sa_params params_to_set,
/* set single-initiator buffering mode */
mode_hdr->dev_spec |= SMH_SA_BUF_MODE_SIBUF;
- mode_hdr->blk_desc_len = sizeof(struct scsi_mode_blk_desc);
+ if (mode_blk)
+ mode_hdr->blk_desc_len = sizeof(struct scsi_mode_blk_desc);
+ else
+ mode_hdr->blk_desc_len = 0;
/*
* First, if the user wants us to set the compression algorithm or
@@ -2496,24 +2665,34 @@ sasetparams(struct cam_periph *periph, sa_params params_to_set,
if (ccomp->dcomp.dce_and_dcc & SA_DCP_DCC) {
struct scsi_data_compression_page *dcp = &cpage->dcomp;
if (calg == 0) {
- /* disable compression */
- dcp->dce_and_dcc &= ~SA_DCP_DCE;
+ /* disable compression && decompression */
+ dcp->dce_and_dcc = 0;
+ dcp->dde_and_red = 0;
break;
}
- /* enable compression */
- dcp->dce_and_dcc |= SA_DCP_DCE;
- /* enable decompression */
- dcp->dde_and_red |= SA_DCP_DDE;
+ /* enable compression && decompression */
+ dcp->dce_and_dcc = SA_DCP_DCE;
+ dcp->dde_and_red = SA_DCP_DDE;
+ /*
+ * If there, use compression algorithm from caller.
+ * Otherwise, if there's a saved compression algorithm
+ * and there is no current algorithm, use the saved
+ * algorithm. Else parrot back what we got and hope
+ * for the best.
+ */
if (calg != MT_COMP_ENABLE) {
scsi_ulto4b(calg, dcp->comp_algorithm);
+ scsi_ulto4b(calg, dcp->decomp_algorithm);
} else if (scsi_4btoul(dcp->comp_algorithm) == 0 &&
softc->saved_comp_algorithm != 0) {
scsi_ulto4b(softc->saved_comp_algorithm,
dcp->comp_algorithm);
+ scsi_ulto4b(softc->saved_comp_algorithm,
+ dcp->decomp_algorithm);
}
break;
}
- case SA_DEVICE_CONFIGURATION_PAGE: /* NOT YET */
+ case SA_DEVICE_CONFIGURATION_PAGE:
{
struct scsi_dev_conf_page *dcp = &cpage->dconf;
if (calg == 0) {
@@ -2555,8 +2734,6 @@ sasetparams(struct cam_periph *periph, sa_params params_to_set,
}
}
- ccb = cam_periph_getccb(periph, 1);
-
/* It is safe to retry this operation */
scsi_mode_select(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG,
(params_to_set & SA_PARAM_COMPRESSION)? TRUE : FALSE,
@@ -2576,13 +2753,25 @@ sasetparams(struct cam_periph *periph, sa_params params_to_set,
}
- if (error == 0) {
- xpt_release_ccb(ccb);
- } else {
+ if (error) {
if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
/*
+ * If we can, try without setting density/blocksize.
+ */
+ if (mode_blk) {
+ if ((params_to_set &
+ (SA_PARAM_DENSITY|SA_PARAM_BLOCKSIZE)) == 0) {
+ mode_blk = NULL;
+ goto retry;
+ }
+ } else {
+ mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1];
+ cpage = (sa_comp_t *)&mode_blk[1];
+ }
+
+ /*
* If we were setting the blocksize, and that failed, we
* want to set it to its original value. If we weren't
* setting the blocksize, we don't want to change it.
@@ -2615,9 +2804,10 @@ sasetparams(struct cam_periph *periph, sa_params params_to_set,
if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
- xpt_release_ccb(ccb);
}
+ xpt_release_ccb(ccb);
+
if (ccomp != NULL)
free(ccomp, M_TEMP);
@@ -2665,7 +2855,7 @@ saprevent(struct cam_periph *periph, int action)
/* It is safe to retry this operation */
scsi_prevent(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, action,
- SSD_FULL_SIZE, 60000);
+ SSD_FULL_SIZE, 100000);
/*
* We can be quiet about illegal requests.
@@ -2698,7 +2888,7 @@ sarewind(struct cam_periph *periph)
/* It is safe to retry this operation */
scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE,
- SSD_FULL_SIZE, (SA_REWIND_TIMEOUT) * 60 * 1000);
+ SSD_FULL_SIZE, REWIND_TIMEOUT);
softc->dsreg = MTIO_DSREG_REW;
error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
@@ -2729,7 +2919,7 @@ saspace(struct cam_periph *periph, int count, scsi_space_code code)
/* This cannot be retried */
scsi_space(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, code, count,
- SSD_FULL_SIZE, (SA_SPACE_TIMEOUT) * 60 * 1000);
+ SSD_FULL_SIZE, SPACE_TIMEOUT);
softc->dsreg = (count < 0)? MTIO_DSREG_REV : MTIO_DSREG_FWD;
error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
@@ -2915,7 +3105,7 @@ saretension(struct cam_periph *periph)
/* It is safe to retry this operation */
scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE,
- FALSE, TRUE, TRUE, SSD_FULL_SIZE, (SA_ERASE_TIMEOUT) * 60 * 1000);
+ FALSE, TRUE, TRUE, SSD_FULL_SIZE, ERASE_TIMEOUT);
softc->dsreg = MTIO_DSREG_TEN;
error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
@@ -3021,7 +3211,7 @@ saerase(struct cam_periph *periph, int longerase)
ccb = cam_periph_getccb(periph, 1);
scsi_erase(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, FALSE, longerase,
- SSD_FULL_SIZE, (SA_ERASE_TIMEOUT) * 60 * 1000);
+ SSD_FULL_SIZE, ERASE_TIMEOUT);
softc->dsreg = MTIO_DSREG_ZER;
error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
OpenPOWER on IntegriCloud