Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102602026
D33883.id101426.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
30 KB
Referenced Files
None
Subscribers
None
D33883.id101426.diff
View Options
Index: share/man/man4/sa.4
===================================================================
--- share/man/man4/sa.4
+++ share/man/man4/sa.4
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 5, 2017
+.Dd September 14, 2021
.Dt SA 4
.Os
.Sh NAME
@@ -323,6 +323,97 @@
driver does not currently use the
RECOVER BUFFERED DATA command.
.El
+.Sh TIMEOUTS
+The
+.Nm
+driver has a set of default timeouts for SCSI commands (READ, WRITE, TEST UNIT
+READY, etc.) that will likely work in most cases for many tape drives.
+.Pp
+For newer tape drives that claim to support the SPC-4
+standard (SCSI Primary Commands 4) or later standards, the
+.Nm
+driver will attempt to use the REPORT SUPPORTED OPERATION CODES command to
+fetch timeout descriptors from the drive.
+If the drive does report timeout descriptors, the
+.Nm
+driver will use the drive's recommended timeouts for commands.
+.Pp
+The timeouts in use are reported in units of THOUSANDTHS of a second via
+the
+.Va kern.cam.sa.%d.timeout.*
+.Xr sysctl 8
+variables.
+.Pp
+To override either the default timeouts, or the timeouts recommended by the
+drive, you can set one of two sets of loader tunable values.
+If you have a drive that supports the REPORT SUPPORTED OPERATION CODES
+timeout descriptors (see the
+.Xr camcontrol 8
+.Va opcodes
+subcommand) it is generally best to use those values.
+The global
+.Va kern.cam.sa.timeout.*
+values will override the timeouts for all
+.Nm
+driver instances.
+If there are 5 tape drives in the system, they'll all get the same timeouts.
+The
+.Va kern.cam.sa.%d.timeout.*
+values (where %d is the numeric
+.Nm
+instance number) will override the global timeouts as well as either the
+default timeouts or the timeouts recommended by the drive.
+.Pp
+To set timeouts after boot, the per-instance timeout values, for example:
+.Va kern.cam.sa.0.timeout.read ,
+are available as sysctl variables.
+.Pp
+Loader tunables:
+.Pp
+.Bl -tag -compact
+.It kern.cam.sa.timeout.erase
+.It kern.cam.sa.timeout.load
+.It kern.cam.sa.timeout.locate
+.It kern.cam.sa.timeout.mode_select
+.It kern.cam.sa.timeout.mode_sense
+.It kern.cam.sa.timeout.prevent
+.It kern.cam.sa.timeout.read
+.It kern.cam.sa.timeout.read_position
+.It kern.cam.sa.timeout.read_block_limits
+.It kern.cam.sa.timeout.report_density
+.It kern.cam.sa.timeout.reserve
+.It kern.cam.sa.timeout.rewind
+.It kern.cam.sa.timeout.space
+.It kern.cam.sa.timeout.tur
+.It kern.cam.sa.timeout.write
+.It kern.cam.sa.timeout.write_filemarks
+.El
+.Pp
+Loader tunable values and
+.Xr sysctl 8
+values:
+.Pp
+.Bl -tag -compact
+.It kern.cam.sa.%d.timeout.erase
+.It kern.cam.sa.%d.timeout.load
+.It kern.cam.sa.%d.timeout.locate
+.It kern.cam.sa.%d.timeout.mode_select
+.It kern.cam.sa.%d.timeout.mode_sense
+.It kern.cam.sa.%d.timeout.prevent
+.It kern.cam.sa.%d.timeout.read
+.It kern.cam.sa.%d.timeout.read_position
+.It kern.cam.sa.%d.timeout.read_block_limits
+.It kern.cam.sa.%d.timeout.report_density
+.It kern.cam.sa.%d.timeout.reserve
+.It kern.cam.sa.%d.timeout.rewind
+.It kern.cam.sa.%d.timeout.space
+.It kern.cam.sa.%d.timeout.tur
+.It kern.cam.sa.%d.timeout.write
+.It kern.cam.sa.%d.timeout.write_filemarks
+.El
+.Pp
+As mentioned above, the timeouts are set and reported in THOUSANDTHS of a
+second, so be sure to account for that when setting them.
.Sh IOCTLS
The
.Nm
Index: sys/cam/scsi/scsi_sa.c
===================================================================
--- sys/cam/scsi/scsi_sa.c
+++ sys/cam/scsi/scsi_sa.c
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 1999, 2000 Matthew Jacob
- * Copyright (c) 2013, 2014, 2015 Spectra Logic Corporation
+ * Copyright (c) 2013, 2014, 2015, 2021 Spectra Logic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -85,7 +85,7 @@
#define SA_ERASE_TIMEOUT 4 * 60
#endif
#ifndef SA_REP_DENSITY_TIMEOUT
-#define SA_REP_DENSITY_TIMEOUT 90
+#define SA_REP_DENSITY_TIMEOUT 1
#endif
#define SCSIOP_TIMEOUT (60 * 1000) /* not an option */
@@ -115,7 +115,7 @@
static MALLOC_DEFINE(M_SCSISA, "SCSI sa", "SCSI sequential access buffers");
typedef enum {
- SA_STATE_NORMAL, SA_STATE_ABNORMAL
+ SA_STATE_NORMAL, SA_STATE_PROBE, SA_STATE_ABNORMAL
} sa_state;
#define ccb_pflags ppriv_field0
@@ -125,27 +125,28 @@
#define SA_POSITION_UPDATED 0x1
typedef enum {
- SA_FLAG_OPEN = 0x0001,
- SA_FLAG_FIXED = 0x0002,
- SA_FLAG_TAPE_LOCKED = 0x0004,
- SA_FLAG_TAPE_MOUNTED = 0x0008,
- SA_FLAG_TAPE_WP = 0x0010,
- SA_FLAG_TAPE_WRITTEN = 0x0020,
- SA_FLAG_EOM_PENDING = 0x0040,
- SA_FLAG_EIO_PENDING = 0x0080,
- SA_FLAG_EOF_PENDING = 0x0100,
+ SA_FLAG_OPEN = 0x00001,
+ SA_FLAG_FIXED = 0x00002,
+ SA_FLAG_TAPE_LOCKED = 0x00004,
+ SA_FLAG_TAPE_MOUNTED = 0x00008,
+ SA_FLAG_TAPE_WP = 0x00010,
+ SA_FLAG_TAPE_WRITTEN = 0x00020,
+ SA_FLAG_EOM_PENDING = 0x00040,
+ SA_FLAG_EIO_PENDING = 0x00080,
+ SA_FLAG_EOF_PENDING = 0x00100,
SA_FLAG_ERR_PENDING = (SA_FLAG_EOM_PENDING|SA_FLAG_EIO_PENDING|
SA_FLAG_EOF_PENDING),
- SA_FLAG_INVALID = 0x0200,
- SA_FLAG_COMP_ENABLED = 0x0400,
- SA_FLAG_COMP_SUPP = 0x0800,
- SA_FLAG_COMP_UNSUPP = 0x1000,
- SA_FLAG_TAPE_FROZEN = 0x2000,
- SA_FLAG_PROTECT_SUPP = 0x4000,
+ SA_FLAG_INVALID = 0x00200,
+ SA_FLAG_COMP_ENABLED = 0x00400,
+ SA_FLAG_COMP_SUPP = 0x00800,
+ SA_FLAG_COMP_UNSUPP = 0x01000,
+ SA_FLAG_TAPE_FROZEN = 0x02000,
+ SA_FLAG_PROTECT_SUPP = 0x04000,
SA_FLAG_COMPRESSION = (SA_FLAG_COMP_SUPP|SA_FLAG_COMP_ENABLED|
SA_FLAG_COMP_UNSUPP),
- SA_FLAG_SCTX_INIT = 0x8000
+ SA_FLAG_SCTX_INIT = 0x08000,
+ SA_FLAG_RSOC_TO_TRY = 0x10000,
} sa_flags;
typedef enum {
@@ -154,6 +155,48 @@
SA_MODE_OFFLINE = 0x02
} sa_mode;
+typedef enum {
+ SA_TIMEOUT_ERASE,
+ SA_TIMEOUT_LOAD,
+ SA_TIMEOUT_LOCATE,
+ SA_TIMEOUT_MODE_SELECT,
+ SA_TIMEOUT_MODE_SENSE,
+ SA_TIMEOUT_PREVENT,
+ SA_TIMEOUT_READ,
+ SA_TIMEOUT_READ_BLOCK_LIMITS,
+ SA_TIMEOUT_READ_POSITION,
+ SA_TIMEOUT_REP_DENSITY,
+ SA_TIMEOUT_RESERVE,
+ SA_TIMEOUT_REWIND,
+ SA_TIMEOUT_SPACE,
+ SA_TIMEOUT_TUR,
+ SA_TIMEOUT_WRITE,
+ SA_TIMEOUT_WRITE_FILEMARKS,
+ SA_TIMEOUT_TYPE_MAX
+} sa_timeout_types;
+
+static struct sa_timeout_desc {
+ const char *desc;
+ int value;
+} sa_default_timeouts[SA_TIMEOUT_TYPE_MAX] = {
+ {"erase", ERASE_TIMEOUT},
+ {"load", REWIND_TIMEOUT},
+ {"locate", SPACE_TIMEOUT},
+ {"mode_select", SCSIOP_TIMEOUT},
+ {"mode_sense", SCSIOP_TIMEOUT},
+ {"prevent", SCSIOP_TIMEOUT},
+ {"read", IO_TIMEOUT},
+ {"read_block_limits", SCSIOP_TIMEOUT},
+ {"read_position", SCSIOP_TIMEOUT},
+ {"report_density", REP_DENSITY_TIMEOUT},
+ {"reserve", SCSIOP_TIMEOUT},
+ {"rewind", REWIND_TIMEOUT},
+ {"space", SPACE_TIMEOUT},
+ {"tur", SCSIOP_TIMEOUT},
+ {"write", IO_TIMEOUT},
+ {"write_filemarks", IO_TIMEOUT},
+};
+
typedef enum {
SA_PARAM_NONE = 0x000,
SA_PARAM_BLOCKSIZE = 0x001,
@@ -355,6 +398,7 @@
uint8_t density_type_bits[SA_DENSITY_TYPES];
int density_info_valid[SA_DENSITY_TYPES];
uint8_t density_info[SA_DENSITY_TYPES][SRDS_MAX_LENGTH];
+ int timeout_info[SA_TIMEOUT_TYPE_MAX];
struct sa_prot_info prot_info;
@@ -413,6 +457,8 @@
struct task sysctl_task;
struct sysctl_ctx_list sysctl_ctx;
struct sysctl_oid *sysctl_tree;
+ struct sysctl_ctx_list sysctl_timeout_ctx;
+ struct sysctl_oid *sysctl_timeout_tree;
};
struct sa_quirk_entry {
@@ -585,6 +631,8 @@
scsi_space_code code);
static void sadevgonecb(void *arg);
static void sasetupdev(struct sa_softc *softc, struct cdev *dev);
+static void saloadtotunables(struct sa_softc *softc);
+static void sasysctlinit(void *context, int pending);
static int samount(struct cam_periph *, int, struct cdev *);
static int saretension(struct cam_periph *periph);
static int sareservereleaseunit(struct cam_periph *periph,
@@ -602,6 +650,7 @@
int is_density);
static void safilldensitysb(struct sa_softc *softc, int *indent,
struct sbuf *sb);
+static void saloadtimeouts(struct sa_softc *softc, union ccb *ccb);
#ifndef SA_DEFAULT_IO_SPLIT
#define SA_DEFAULT_IO_SPLIT 0
@@ -2211,7 +2260,9 @@
cam_periph_unlock(periph);
if ((softc->flags & SA_FLAG_SCTX_INIT) != 0
- && sysctl_ctx_free(&softc->sysctl_ctx) != 0)
+ && (((softc->sysctl_timeout_tree != NULL)
+ && (sysctl_ctx_free(&softc->sysctl_timeout_ctx) != 0))
+ || sysctl_ctx_free(&softc->sysctl_ctx) != 0))
xpt_print(periph->path, "can't remove sysctl context\n");
cam_periph_lock(periph);
@@ -2282,12 +2333,36 @@
softc->num_devs_to_destroy++;
}
+static void
+saloadtotunables(struct sa_softc *softc)
+{
+ int i;
+ char tmpstr[80];
+
+ for (i = 0; i < SA_TIMEOUT_TYPE_MAX; i++) {
+ int tmpval, retval;
+
+ snprintf(tmpstr, sizeof(tmpstr), "kern.cam.sa.timeout.%s",
+ sa_default_timeouts[i].desc);
+ retval = TUNABLE_INT_FETCH(tmpstr, &tmpval);
+ if (retval != 0)
+ softc->timeout_info[i] = tmpval;
+
+ snprintf(tmpstr, sizeof(tmpstr), "kern.cam.sa.%u.timeout.%s",
+ softc->periph->unit_number, sa_default_timeouts[i].desc);
+ retval = TUNABLE_INT_FETCH(tmpstr, &tmpval);
+ if (retval != 0)
+ softc->timeout_info[i] = tmpval;
+ }
+}
+
static void
sasysctlinit(void *context, int pending)
{
struct cam_periph *periph;
struct sa_softc *softc;
- char tmpstr[32], tmpstr2[16];
+ char tmpstr[64], tmpstr2[16];
+ int i;
periph = (struct cam_periph *)context;
/*
@@ -2322,6 +2397,23 @@
OID_AUTO, "inject_eom", CTLFLAG_RW,
&softc->inject_eom, 0, "Queue EOM for the next write/read");
+ sysctl_ctx_init(&softc->sysctl_timeout_ctx);
+ softc->sysctl_timeout_tree = SYSCTL_ADD_NODE(&softc->sysctl_timeout_ctx,
+ SYSCTL_CHILDREN(softc->sysctl_tree), OID_AUTO, "timeout",
+ CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Timeouts");
+ if (softc->sysctl_timeout_tree == NULL)
+ goto bailout;
+
+ for (i = 0; i < SA_TIMEOUT_TYPE_MAX; i++) {
+ snprintf(tmpstr, sizeof(tmpstr), "%s timeout",
+ sa_default_timeouts[i].desc);
+
+ SYSCTL_ADD_INT(&softc->sysctl_timeout_ctx,
+ SYSCTL_CHILDREN(softc->sysctl_timeout_tree),
+ OID_AUTO, sa_default_timeouts[i].desc, CTLFLAG_RW,
+ &softc->timeout_info[i], 0, tmpstr);
+ }
+
bailout:
/*
* Release the reference that was held when this task was enqueued.
@@ -2339,6 +2431,7 @@
caddr_t match;
char tmpstr[80];
int error;
+ int i;
cgd = (struct ccb_getdev *)arg;
if (cgd == NULL) {
@@ -2383,6 +2476,15 @@
} else
softc->quirks = SA_QUIRK_NONE;
+
+ /*
+ * Initialize the default timeouts. If this drive supports
+ * timeout descriptors we'll overwrite these values with the
+ * recommended timeouts from the drive.
+ */
+ for (i = 0; i < SA_TIMEOUT_TYPE_MAX; i++)
+ softc->timeout_info[i] = sa_default_timeouts[i].value;
+
/*
* Long format data for READ POSITION was introduced in SSC, which
* was after SCSI-2. (Roughly equivalent to SCSI-3.) If the drive
@@ -2396,6 +2498,19 @@
if (cgd->inq_data.version <= SCSI_REV_CCS)
softc->quirks |= SA_QUIRK_NO_LONG_POS;
+ /*
+ * The SCSI REPORT SUPPORTED OPERATION CODES command was added in
+ * SPC-4. That command optionally includes timeout data for
+ * different commands. Timeout values can vary wildly among
+ * different drives, so if the drive itself has recommended values,
+ * we will try to use them. Set this flag to indicate we're going
+ * to ask the drive for timeout data. This flag also tells us to
+ * wait on loading timeout tunables so we can properly override
+ * timeouts with any user-specified values.
+ */
+ if (SID_ANSI_REV(&cgd->inq_data) >= SCSI_REV_SPC4)
+ softc->flags |= SA_FLAG_RSOC_TO_TRY;
+
if (cgd->inq_data.spc3_flags & SPC3_SID_PROTECT) {
struct ccb_dev_advinfo cdai;
struct scsi_vpd_extended_inquiry_data ext_inq;
@@ -2556,8 +2671,28 @@
*/
xpt_register_async(AC_LOST_DEVICE, saasync, periph, periph->path);
- xpt_announce_periph(periph, NULL);
- xpt_announce_quirks(periph, softc->quirks, SA_QUIRK_BIT_STRING);
+ /*
+ * See comment above, try fetching timeout values for drives that
+ * might support it. Otherwise, use the defaults.
+ */
+ if (softc->flags & SA_FLAG_RSOC_TO_TRY) {
+ /*
+ * Bump the peripheral refcount while we are probing.
+ */
+ cam_periph_acquire(periph);
+ softc->state = SA_STATE_PROBE;
+ xpt_schedule(periph, CAM_PRIORITY_DEV);
+ } else {
+ /*
+ * This drive doesn't support Report Supported Operation
+ * Codes, so we load the tunables at this point to bring
+ * in any user preferences.
+ */
+ saloadtotunables(softc);
+
+ xpt_announce_periph(periph, NULL);
+ xpt_announce_quirks(periph, softc->quirks, SA_QUIRK_BIT_STRING);
+ }
return (CAM_REQ_CMP);
}
@@ -2752,7 +2887,9 @@
(softc->flags & SA_FLAG_FIXED) != 0, length,
(bp->bio_flags & BIO_UNMAPPED) != 0 ? (void *)bp :
bp->bio_data, bp->bio_bcount, SSD_FULL_SIZE,
- IO_TIMEOUT);
+ (bp->bio_cmd == BIO_READ) ?
+ softc->timeout_info[SA_TIMEOUT_READ] :
+ softc->timeout_info[SA_TIMEOUT_WRITE]);
start_ccb->ccb_h.ccb_pflags &= ~SA_POSITION_UPDATED;
start_ccb->ccb_h.ccb_bp = bp;
bp = bioq_first(&softc->bio_queue);
@@ -2765,6 +2902,59 @@
}
break;
}
+ case SA_STATE_PROBE: {
+ int num_opcodes;
+ size_t alloc_len;
+ uint8_t *params;
+
+ /*
+ * This is an arbitrary number. An IBM LTO-6 drive reports
+ * 67 entries, and an IBM LTO-9 drive reports 71 entries.
+ * There can theoretically be more than 256 because
+ * service actions of a particular opcode are reported
+ * separately, but we're far enough ahead of the practical
+ * number here that we don't need to implement logic to
+ * retry if we don't get all the timeout descriptors.
+ */
+ num_opcodes = 256;
+
+ alloc_len = num_opcodes *
+ (sizeof(struct scsi_report_supported_opcodes_descr) +
+ sizeof(struct scsi_report_supported_opcodes_timeout));
+
+ params = malloc(alloc_len, M_SCSISA, M_NOWAIT| M_ZERO);
+ if (params == NULL) {
+ /*
+ * If this happens, go with default
+ * timeouts and announce the drive.
+ */
+ saloadtotunables(softc);
+
+ softc->state = SA_STATE_NORMAL;
+
+ xpt_announce_periph(periph, NULL);
+ xpt_announce_quirks(periph, softc->quirks,
+ SA_QUIRK_BIT_STRING);
+ xpt_release_ccb(start_ccb);
+ cam_periph_release_locked(periph);
+ return;
+ }
+
+ scsi_report_supported_opcodes(&start_ccb->csio,
+ /*retries*/ 3,
+ /*cbfcnp*/ sadone,
+ /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*options*/ RSO_RCTD,
+ /*req_opcode*/ 0,
+ /*req_service_action*/ 0,
+ /*data_ptr*/ params,
+ /*dxfer_len*/ alloc_len,
+ /*sense_len*/ SSD_FULL_SIZE,
+ /*timeout*/ softc->timeout_info[SA_TIMEOUT_TUR]);
+
+ xpt_action(start_ccb);
+ break;
+ }
case SA_STATE_ABNORMAL:
default:
panic("state 0x%x in sastart", softc->state);
@@ -2782,17 +2972,79 @@
softc = (struct sa_softc *)periph->softc;
csio = &done_ccb->csio;
-
- softc->dsreg = MTIO_DSREG_REST;
- bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
error = 0;
- if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- if ((error = saerror(done_ccb, 0, 0)) == ERESTART) {
+
+ if (softc->state == SA_STATE_NORMAL) {
+ softc->dsreg = MTIO_DSREG_REST;
+ bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
+
+ if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ if ((error = saerror(done_ccb, 0, 0)) == ERESTART) {
+ /*
+ * A retry was scheduled, so just return.
+ */
+ return;
+ }
+ }
+ } else if (softc->state == SA_STATE_PROBE) {
+ bp = NULL;
+ if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
/*
- * A retry was scheduled, so just return.
+ * Note that on probe, we just run through
+ * cam_periph_error(), since saerror() has a lot of
+ * special handling for I/O errors. We don't need
+ * that to get the opcodes. We either succeed
+ * after a retry or two, or give up. We don't
+ * print sense, we don't need to worry the user if
+ * this drive doesn't support timeout descriptors.
*/
- return;
+ if ((error = cam_periph_error(done_ccb, 0,
+ SF_NO_PRINT)) == ERESTART) {
+ /*
+ * A retry was scheduled, so just return.
+ */
+ return;
+ } else if (error != 0) {
+ /* We failed to get opcodes. Give up. */
+
+ saloadtotunables(softc);
+
+ softc->state = SA_STATE_NORMAL;
+
+ xpt_release_ccb(done_ccb);
+
+ xpt_announce_periph(periph, NULL);
+ xpt_announce_quirks(periph, softc->quirks,
+ SA_QUIRK_BIT_STRING);
+ cam_periph_release_locked(periph);
+ return;
+ }
}
+ /*
+ * At this point, we have succeeded, so load the timeouts
+ * and go into the normal state.
+ */
+ softc->state = SA_STATE_NORMAL;
+
+ /*
+ * First, load the timeouts we got from the drive.
+ */
+ saloadtimeouts(softc, done_ccb);
+
+ /*
+ * Next, overwrite the timeouts from the drive with any
+ * loader tunables that the user set.
+ */
+ saloadtotunables(softc);
+
+ xpt_release_ccb(done_ccb);
+ xpt_announce_periph(periph, NULL);
+ xpt_announce_quirks(periph, softc->quirks,
+ SA_QUIRK_BIT_STRING);
+ cam_periph_release_locked(periph);
+ return;
+ } else {
+ panic("state 0x%x in sadone", softc->state);
}
if (error == EIO) {
@@ -2890,13 +3142,15 @@
if (softc->flags & SA_FLAG_TAPE_MOUNTED) {
ccb = cam_periph_getccb(periph, 1);
scsi_test_unit_ready(&ccb->csio, 0, NULL,
- MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT);
+ MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE,
+ softc->timeout_info[SA_TIMEOUT_TUR]);
error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
softc->device_stats);
if (error == ENXIO) {
softc->flags &= ~SA_FLAG_TAPE_MOUNTED;
scsi_test_unit_ready(&ccb->csio, 0, NULL,
- MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT);
+ MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE,
+ softc->timeout_info[SA_TIMEOUT_TUR]);
error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
softc->device_stats);
} else if (error) {
@@ -2917,7 +3171,8 @@
}
ccb = cam_periph_getccb(periph, 1);
scsi_test_unit_ready(&ccb->csio, 0, NULL,
- MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT);
+ MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE,
+ softc->timeout_info[SA_TIMEOUT_TUR]);
error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
softc->device_stats);
}
@@ -2938,7 +3193,8 @@
* *Very* first off, make sure we're loaded to BOT.
*/
scsi_load_unload(&ccb->csio, 2, NULL, MSG_SIMPLE_Q_TAG, FALSE,
- FALSE, FALSE, 1, SSD_FULL_SIZE, REWIND_TIMEOUT);
+ FALSE, FALSE, 1, SSD_FULL_SIZE,
+ softc->timeout_info[SA_TIMEOUT_LOAD]);
error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
softc->device_stats);
@@ -2947,7 +3203,8 @@
*/
if (error) {
scsi_rewind(&ccb->csio, 2, NULL, MSG_SIMPLE_Q_TAG,
- FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT);
+ FALSE, SSD_FULL_SIZE,
+ softc->timeout_info[SA_TIMEOUT_REWIND]);
error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
softc->device_stats);
}
@@ -2976,11 +3233,12 @@
scsi_sa_read_write(&ccb->csio, 0, NULL,
MSG_SIMPLE_Q_TAG, 1, FALSE, 0, 8192,
(void *) rblim, 8192, SSD_FULL_SIZE,
- IO_TIMEOUT);
+ softc->timeout_info[SA_TIMEOUT_READ]);
(void) cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
softc->device_stats);
scsi_rewind(&ccb->csio, 1, NULL, MSG_SIMPLE_Q_TAG,
- FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT);
+ FALSE, SSD_FULL_SIZE,
+ softc->timeout_info[SA_TIMEOUT_REWIND]);
error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO,
SF_NO_PRINT | SF_RETRY_UA,
softc->device_stats);
@@ -2996,7 +3254,8 @@
* Next off, determine block limits.
*/
scsi_read_block_limits(&ccb->csio, 5, NULL, MSG_SIMPLE_Q_TAG,
- rblim, SSD_FULL_SIZE, SCSIOP_TIMEOUT);
+ rblim, SSD_FULL_SIZE,
+ softc->timeout_info[SA_TIMEOUT_READ_BLOCK_LIMITS]);
error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO,
SF_NO_PRINT | SF_RETRY_UA, softc->device_stats);
@@ -3610,7 +3869,7 @@
scsi_mode_sense(&ccb->csio, 5, NULL, MSG_SIMPLE_Q_TAG, FALSE,
SMS_PAGE_CTRL_CURRENT, (params_to_get & SA_PARAM_COMPRESSION) ?
cpage : SMS_VENDOR_SPECIFIC_PAGE, mode_buffer, mode_buffer_len,
- SSD_FULL_SIZE, SCSIOP_TIMEOUT);
+ SSD_FULL_SIZE, softc->timeout_info[SA_TIMEOUT_MODE_SENSE]);
error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
softc->device_stats);
@@ -3672,7 +3931,7 @@
scsi_mode_sense(&ccb->csio, 2, NULL, MSG_SIMPLE_Q_TAG, FALSE,
SMS_PAGE_CTRL_CURRENT, SMS_VENDOR_SPECIFIC_PAGE,
mode_buffer, mode_buffer_len, SSD_FULL_SIZE,
- SCSIOP_TIMEOUT);
+ softc->timeout_info[SA_TIMEOUT_MODE_SENSE]);
error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
softc->device_stats);
@@ -3739,7 +3998,8 @@
/*data_ptr*/ softc->density_info[i],
/*length*/ sizeof(softc->density_info[i]),
/*sense_len*/ SSD_FULL_SIZE,
- /*timeout*/ REP_DENSITY_TIMEOUT);
+ /*timeout*/
+ softc->timeout_info[SA_TIMEOUT_REP_DENSITY]);
error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
softc->device_stats);
status = ccb->ccb_h.status & CAM_STATUS_MASK;
@@ -3801,7 +4061,8 @@
/*param_len*/ dp_len,
/*minimum_cmd_size*/ 10,
/*sense_len*/ SSD_FULL_SIZE,
- /*timeout*/ SCSIOP_TIMEOUT);
+ /*timeout*/
+ softc->timeout_info[SA_TIMEOUT_MODE_SENSE]);
/*
* XXX KDM we need to be able to set the subpage in the
* fill function.
@@ -4029,7 +4290,8 @@
/*param_len*/ dp_len,
/*minimum_cmd_size*/ 10,
/*sense_len*/ SSD_FULL_SIZE,
- /*timeout*/ SCSIOP_TIMEOUT);
+ /*timeout*/
+ softc->timeout_info[SA_TIMEOUT_MODE_SELECT]);
error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
if (error != 0)
@@ -4299,7 +4561,8 @@
/* It is safe to retry this operation */
scsi_mode_select(&ccb->csio, 5, NULL, MSG_SIMPLE_Q_TAG,
(params_to_set & SA_PARAM_COMPRESSION)? TRUE : FALSE,
- FALSE, mode_buffer, mode_buffer_len, SSD_FULL_SIZE, SCSIOP_TIMEOUT);
+ FALSE, mode_buffer, mode_buffer_len, SSD_FULL_SIZE,
+ softc->timeout_info[SA_TIMEOUT_MODE_SELECT]);
error = cam_periph_runccb(ccb, saerror, 0,
sense_flags, softc->device_stats);
@@ -4616,7 +4879,7 @@
/* It is safe to retry this operation */
scsi_prevent(&ccb->csio, 5, NULL, MSG_SIMPLE_Q_TAG, action,
- SSD_FULL_SIZE, SCSIOP_TIMEOUT);
+ SSD_FULL_SIZE, softc->timeout_info[SA_TIMEOUT_PREVENT]);
error = cam_periph_runccb(ccb, saerror, 0, sf, softc->device_stats);
if (error == 0) {
@@ -4642,7 +4905,7 @@
/* It is safe to retry this operation */
scsi_rewind(&ccb->csio, 2, NULL, MSG_SIMPLE_Q_TAG, FALSE,
- SSD_FULL_SIZE, REWIND_TIMEOUT);
+ SSD_FULL_SIZE, softc->timeout_info[SA_TIMEOUT_REWIND]);
softc->dsreg = MTIO_DSREG_REW;
error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
@@ -4674,7 +4937,7 @@
/* This cannot be retried */
scsi_space(&ccb->csio, 0, NULL, MSG_SIMPLE_Q_TAG, code, count,
- SSD_FULL_SIZE, SPACE_TIMEOUT);
+ SSD_FULL_SIZE, softc->timeout_info[SA_TIMEOUT_SPACE]);
/*
* Clear residual because we will be using it.
@@ -4755,7 +5018,8 @@
softc->dsreg = MTIO_DSREG_FMK;
/* this *must* not be retried */
scsi_write_filemarks(&ccb->csio, 0, NULL, MSG_SIMPLE_Q_TAG,
- immed, setmarks, nmarks, SSD_FULL_SIZE, IO_TIMEOUT);
+ immed, setmarks, nmarks, SSD_FULL_SIZE,
+ softc->timeout_info[SA_TIMEOUT_WRITE_FILEMARKS]);
softc->dsreg = MTIO_DSREG_REST;
error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
@@ -4822,7 +5086,8 @@
/*data_ptr*/ (uint8_t *)&long_pos,
/*length*/ sizeof(long_pos),
/*sense_len*/ SSD_FULL_SIZE,
- /*timeout*/ SCSIOP_TIMEOUT);
+ /*timeout*/
+ softc->timeout_info[SA_TIMEOUT_READ_POSITION]);
softc->dsreg = MTIO_DSREG_RBSY;
error = cam_periph_runccb(ccb, saerror, 0, SF_QUIET_IR,
@@ -4918,7 +5183,8 @@
ccb = cam_periph_getccb(periph, 1);
scsi_read_position(&ccb->csio, 1, NULL, MSG_SIMPLE_Q_TAG,
- hard, &loc, SSD_FULL_SIZE, SCSIOP_TIMEOUT);
+ hard, &loc, SSD_FULL_SIZE,
+ softc->timeout_info[SA_TIMEOUT_READ_POSITION]);
softc->dsreg = MTIO_DSREG_RBSY;
error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
softc->dsreg = MTIO_DSREG_REST;
@@ -4986,7 +5252,8 @@
/*partition*/ locate_info->partition,
/*logical_id*/ locate_info->logical_id,
/*sense_len*/ SSD_FULL_SIZE,
- /*timeout*/ SPACE_TIMEOUT);
+ /*timeout*/
+ softc->timeout_info[SA_TIMEOUT_LOCATE]);
} else {
scsi_locate_10(&ccb->csio,
/*retries*/ 1,
@@ -4998,7 +5265,8 @@
/*partition*/ locate_info->partition,
/*block_address*/ locate_info->logical_id,
/*sense_len*/ SSD_FULL_SIZE,
- /*timeout*/ SPACE_TIMEOUT);
+ /*timeout*/
+ softc->timeout_info[SA_TIMEOUT_LOCATE]);
}
softc->dsreg = MTIO_DSREG_POS;
@@ -5061,7 +5329,8 @@
/* It is safe to retry this operation */
scsi_load_unload(&ccb->csio, 5, NULL, MSG_SIMPLE_Q_TAG, FALSE,
- FALSE, TRUE, TRUE, SSD_FULL_SIZE, ERASE_TIMEOUT);
+ FALSE, TRUE, TRUE, SSD_FULL_SIZE,
+ softc->timeout_info[SA_TIMEOUT_LOAD]);
softc->dsreg = MTIO_DSREG_TEN;
error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
@@ -5088,7 +5357,8 @@
/* It is safe to retry this operation */
scsi_reserve_release_unit(&ccb->csio, 2, NULL, MSG_SIMPLE_Q_TAG,
- FALSE, 0, SSD_FULL_SIZE, SCSIOP_TIMEOUT, reserve);
+ FALSE, 0, SSD_FULL_SIZE, softc->timeout_info[SA_TIMEOUT_RESERVE],
+ reserve);
softc->dsreg = MTIO_DSREG_RBSY;
error = cam_periph_runccb(ccb, saerror, 0,
SF_RETRY_UA | SF_NO_PRINT, softc->device_stats);
@@ -5119,7 +5389,8 @@
/* It is safe to retry this operation */
scsi_load_unload(&ccb->csio, 5, NULL, MSG_SIMPLE_Q_TAG, FALSE,
- FALSE, FALSE, load, SSD_FULL_SIZE, REWIND_TIMEOUT);
+ FALSE, FALSE, load, SSD_FULL_SIZE,
+ softc->timeout_info[SA_TIMEOUT_LOAD]);
softc->dsreg = (load)? MTIO_DSREG_LD : MTIO_DSREG_UNL;
error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
@@ -5151,7 +5422,7 @@
ccb = cam_periph_getccb(periph, 1);
scsi_erase(&ccb->csio, 1, NULL, MSG_SIMPLE_Q_TAG, FALSE, longerase,
- SSD_FULL_SIZE, ERASE_TIMEOUT);
+ SSD_FULL_SIZE, softc->timeout_info[SA_TIMEOUT_ERASE]);
softc->dsreg = MTIO_DSREG_ZER;
error = cam_periph_runccb(ccb, saerror, 0, 0, softc->device_stats);
@@ -5450,6 +5721,159 @@
SASBENDNODE(sb, *indent, mtdensity);
}
+/*
+ * Given a completed REPORT SUPPORTED OPERATION CODES command with timeout
+ * descriptors, go through the descriptors and set the sa(4) driver
+ * timeouts to the recommended values.
+ */
+static void
+saloadtimeouts(struct sa_softc *softc, union ccb *ccb)
+{
+ uint32_t valid_len, avail_len = 0, used_len = 0;
+ struct scsi_report_supported_opcodes_all *hdr;
+ struct scsi_report_supported_opcodes_descr *desc;
+ uint8_t *buf;
+
+ hdr = (struct scsi_report_supported_opcodes_all *)ccb->csio.data_ptr;
+ valid_len = ccb->csio.dxfer_len - ccb->csio.resid;
+
+ if (valid_len < sizeof(*hdr))
+ return;
+
+ avail_len = scsi_4btoul(hdr->length) + sizeof(hdr->length);
+ if ((avail_len != 0)
+ && (avail_len > valid_len)) {
+ xpt_print(softc->periph->path, "WARNING: available timeout "
+ "descriptor len %zu > valid len %u\n", avail_len,valid_len);
+ }
+
+ used_len = sizeof(hdr->length);
+ avail_len = MIN(avail_len, valid_len - sizeof(*hdr));
+ buf = ccb->csio.data_ptr;
+ while ((avail_len - used_len) > sizeof(*desc)) {
+ struct scsi_report_supported_opcodes_timeout *td;
+ uint32_t td_len;
+ uint32_t rec_time;
+ uint8_t *cur_ptr;
+
+ cur_ptr = &buf[used_len];
+ desc = (struct scsi_report_supported_opcodes_descr *)cur_ptr;
+
+ used_len += sizeof(*desc);
+ /* If there's no timeout descriptor, keep going */
+ if ((desc->flags & RSO_CTDP) == 0)
+ continue;
+
+ /*
+ * If we don't have enough space to fit a timeout
+ * descriptor then we're done.
+ */
+ if ((avail_len - used_len) < sizeof(*td)) {
+ used_len = avail_len;
+ continue;
+ }
+
+ cur_ptr = &buf[used_len];
+ td = (struct scsi_report_supported_opcodes_timeout *)cur_ptr;
+ td_len = scsi_2btoul(td->length);
+ td_len += sizeof(td->length);
+ used_len += td_len;
+
+ if (td_len < sizeof(*td))
+ continue;
+
+ /*
+ * Use the recommended timeout. The nominal time is the
+ * time to wait before querying for status.
+ */
+ rec_time = scsi_4btoul(td->recommended_time);
+
+ /*
+ * Our timeouts are set in thousandths of a seconds.
+ */
+ rec_time *= 1000;
+
+ switch(desc->opcode) {
+ case ERASE:
+ softc->timeout_info[SA_TIMEOUT_ERASE] = rec_time;
+ break;
+ case LOAD_UNLOAD:
+ softc->timeout_info[SA_TIMEOUT_LOAD] = rec_time;
+ break;
+ case LOCATE:
+ case LOCATE_16:
+ /*
+ * We are assuming these are the same timeout.
+ */
+ softc->timeout_info[SA_TIMEOUT_LOCATE] = rec_time;
+ break;
+ case MODE_SELECT_6:
+ case MODE_SELECT_10:
+ /*
+ * We are assuming these are the same timeout.
+ */
+ softc->timeout_info[SA_TIMEOUT_MODE_SELECT] = rec_time;
+ break;
+ case MODE_SENSE_6:
+ case MODE_SENSE_10:
+ /*
+ * We are assuming these are the same timeout.
+ */
+ softc->timeout_info[SA_TIMEOUT_MODE_SENSE] = rec_time;
+ break;
+ case PREVENT_ALLOW:
+ softc->timeout_info[SA_TIMEOUT_PREVENT] = rec_time;
+ break;
+ case SA_READ:
+ softc->timeout_info[SA_TIMEOUT_READ] = rec_time;
+ break;
+ case READ_BLOCK_LIMITS:
+ softc->timeout_info[SA_TIMEOUT_READ_BLOCK_LIMITS] =
+ rec_time;
+ break;
+ case READ_POSITION:
+ /*
+ * Note that this may show up multiple times for
+ * the short form, long form and extended form
+ * service actions. We're assuming they are all
+ * the same.
+ */
+ softc->timeout_info[SA_TIMEOUT_READ_POSITION] =rec_time;
+ break;
+ case REPORT_DENSITY_SUPPORT:
+ softc->timeout_info[SA_TIMEOUT_REP_DENSITY] = rec_time;
+ break;
+ case RESERVE_UNIT:
+ case RELEASE_UNIT:
+ /* We are assuming these are the same timeout.*/
+ softc->timeout_info[SA_TIMEOUT_RESERVE] = rec_time;
+ break;
+ case REWIND:
+ softc->timeout_info[SA_TIMEOUT_REWIND] = rec_time;
+ break;
+ case SPACE:
+ softc->timeout_info[SA_TIMEOUT_SPACE] = rec_time;
+ break;
+ case TEST_UNIT_READY:
+ softc->timeout_info[SA_TIMEOUT_TUR] = rec_time;
+ break;
+ case SA_WRITE:
+ softc->timeout_info[SA_TIMEOUT_WRITE] = rec_time;
+ break;
+ case WRITE_FILEMARKS:
+ softc->timeout_info[SA_TIMEOUT_WRITE_FILEMARKS] =
+ rec_time;
+ break;
+ default:
+ /*
+ * We have explicit cases for all of the timeouts
+ * we use.
+ */
+ break;
+ }
+ }
+}
+
#endif /* _KERNEL */
/*
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Nov 15, 3:49 PM (7 h, 3 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14644895
Default Alt Text
D33883.id101426.diff (30 KB)
Attached To
Mode
D33883: Switch to using drive-supplied timeouts for the sa(4) driver.
Attached
Detach File
Event Timeline
Log In to Comment