summaryrefslogtreecommitdiff
path: root/sys/cam
diff options
context:
space:
mode:
authorMatt Jacob <mjacob@FreeBSD.org>1998-12-17 18:56:23 +0000
committerMatt Jacob <mjacob@FreeBSD.org>1998-12-17 18:56:23 +0000
commit888bec0f0c2180e1bce5f2881d6d7cdbb2feea0a (patch)
tree445dd4742e740458a5df800aea2879a57a282351 /sys/cam
parentf9828cced4415aa04af3bbdc8eb332b9b16cc1f7 (diff)
Notes
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/scsi/scsi_sa.c319
1 files changed, 268 insertions, 51 deletions
diff --git a/sys/cam/scsi/scsi_sa.c b/sys/cam/scsi/scsi_sa.c
index 6ca32648f8c4..fedbdc25abda 100644
--- a/sys/cam/scsi/scsi_sa.c
+++ b/sys/cam/scsi/scsi_sa.c
@@ -25,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: scsi_sa.c,v 1.6 1998/11/26 10:47:52 joerg Exp $
+ * $Id: scsi_sa.c,v 1.7 1998/12/11 07:19:36 mjacob Exp $
*/
#include <sys/param.h>
@@ -76,6 +76,10 @@
#define SAUNIT(DEV) ((minor(DEV)&0xF0) >> 4) /* 4 bit unit. */
#define SASETUNIT(DEV, U) makedev(major(DEV), ((U) << 4))
+#ifndef UNUSED_PARAMETER
+#define UNUSED_PARAMETER(x) x = x
+#endif
+
typedef enum {
SA_STATE_NORMAL
} sa_state;
@@ -95,15 +99,14 @@ typedef enum {
SA_FLAG_TAPE_MOUNTED = 0x0008,
SA_FLAG_TAPE_WP = 0x0010,
SA_FLAG_TAPE_WRITTEN = 0x0020,
- SA_FLAG_2FM_AT_EOD = 0x0040,
- SA_FLAG_EOM_PENDING = 0x0080,
- SA_FLAG_EIO_PENDING = 0x0100,
- SA_FLAG_EOF_PENDING = 0x0200,
+ SA_FLAG_EOM_PENDING = 0x0040,
+ SA_FLAG_EIO_PENDING = 0x0080,
+ SA_FLAG_EOF_PENDING = 0x0100,
SA_FLAG_ERR_PENDING = (SA_FLAG_EOM_PENDING|SA_FLAG_EIO_PENDING|
SA_FLAG_EOF_PENDING),
- SA_FLAG_INVALID = 0x0400,
- SA_FLAG_COMP_ENABLED = 0x0800,
- SA_FLAG_COMP_UNSUPP = 0x1000
+ SA_FLAG_INVALID = 0x0200,
+ SA_FLAG_COMP_ENABLED = 0x0400,
+ SA_FLAG_COMP_UNSUPP = 0x0800
} sa_flags;
typedef enum {
@@ -126,7 +129,10 @@ typedef enum {
typedef enum {
SA_QUIRK_NONE = 0x00,
- SA_QUIRK_NOCOMP = 0x01
+ SA_QUIRK_NOCOMP = 0x01, /* can't deal with compression at all */
+ SA_QUIRK_FIXED = 0x02, /* force fixed mode */
+ SA_QUIRK_VARIABLE = 0x04, /* force variable mode */
+ SA_QUIRK_2FM = 0x05 /* Two File Marks at EOD */
} sa_quirks;
struct sa_softc {
@@ -143,6 +149,7 @@ struct sa_softc {
u_int32_t comp_algorithm;
u_int32_t saved_comp_algorithm;
u_int32_t media_blksize;
+ u_int32_t last_media_blksize;
u_int32_t media_numblks;
u_int8_t media_density;
u_int8_t speed;
@@ -161,11 +168,11 @@ static struct sa_quirk_entry sa_quirk_table[] =
{
{
{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
- "Python 25601*", "*"}, /*quirks*/SA_QUIRK_NOCOMP
+ "Python 25601*", "*"}, SA_QUIRK_NOCOMP
},
{
{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
- " TDC 3600", "U07:"}, /*quirks*/SA_QUIRK_NOCOMP
+ " TDC 3600", "U07:"}, SA_QUIRK_NOCOMP
}
};
@@ -203,7 +210,7 @@ static void saprevent(struct cam_periph *periph, int action);
static int sarewind(struct cam_periph *periph);
static int saspace(struct cam_periph *periph, int count,
scsi_space_code code);
-static int samount(struct cam_periph *periph);
+static int samount(struct cam_periph *, int, dev_t);
static int saretension(struct cam_periph *periph);
static int sareservereleaseunit(struct cam_periph *periph,
int reserve);
@@ -314,9 +321,8 @@ saopen(dev_t dev, int flags, int fmt, struct proc *p)
error = EBUSY;
}
- if (error == 0) {
- error = samount(periph);
- }
+ if (error == 0)
+ error = samount(periph, flags, dev);
/* Perform other checking... */
}
@@ -350,23 +356,66 @@ saclose(dev_t dev, int flag, int fmt, struct proc *p)
return (error); /* error code from tsleep */
}
- sacheckeod(periph);
+ /*
+ * See whether or not we need to write filemarks...
+ */
+ error = sacheckeod(periph);
+ if (error) {
+ xpt_print_path(periph->path);
+ printf("failure at writing filemarks - opting for safety\n");
+ mode = SA_MODE_OFFLINE;
+ }
+ /*
+ * Whatever we end up doing, allow users to eject tapes from here on.
+ */
saprevent(periph, PR_ALLOW);
+ /*
+ * Decide how to end...
+ */
switch (mode) {
- case SA_MODE_REWIND:
- sarewind(periph);
- break;
+ default:
+ xpt_print_path(periph->path);
+ printf("unknown close mode %x- opting for safety\n", mode);
+ /* FALLTHROUGH */
case SA_MODE_OFFLINE:
sarewind(periph);
saloadunload(periph, /*load*/FALSE);
break;
+ case SA_MODE_REWIND:
+ sarewind(periph);
+ break;
case SA_MODE_NOREWIND:
- default:
+ /*
+ * If we're not rewinding/unloading the tape, find out
+ * whether we need to back up over one of two filemarks
+ * we wrote (if we wrote two filemarks) so that appends
+ * from this point on will be sane.
+ */
+ if ((softc->quirks & SA_QUIRK_2FM) &&
+ (softc->flags & SA_FLAG_TAPE_WRITTEN)) {
+ error = saspace(periph, -1, SS_FILEMARKS);
+ if (error) {
+ xpt_print_path(periph->path);
+ printf("unable to backspace over one of double"
+ " filemarks at EOD- opting for safety\n");
+ sarewind(periph);
+ saloadunload(periph, FALSE);
+ }
+ }
break;
}
+ /*
+ * We wish to note here that there are no filemarks written.
+ */
+ softc->filemarks = 0;
+
+ /*
+ * And we are no longer open for business.
+ */
+
softc->flags &= ~SA_FLAG_OPEN;
/* release the device */
@@ -570,9 +619,8 @@ saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
count = mt->mt_count;
switch (mt->mt_op) {
- case MTWEOF: /* write an end-of-file record */
- error = sawritefilemarks(periph, count,
- /*setmarks*/FALSE);
+ case MTWEOF: /* write an end-of-file marker */
+ error = sawritefilemarks(periph, count, FALSE);
break;
case MTBSR: /* backward space record */
case MTFSR: /* forward space record */
@@ -585,8 +633,18 @@ saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
nmarks = softc->filemarks;
error = sacheckeod(periph);
+ if (error) {
+ xpt_print_path(periph->path);
+ printf("EOD check prior to spacing failed\n");
+ softc->flags |= SA_FLAG_EIO_PENDING;
+ break;
+ }
nmarks -= softc->filemarks;
-
+ /*
+ * XXX: This very interestingly treats filemarks as
+ * XXX: marks we can just BSR over if the op is indeed
+ * XXX: a MTBSR.
+ */
if ((mt->mt_op == MTBSR) || (mt->mt_op == MTBSF))
count = -count;
@@ -606,10 +664,25 @@ saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
if (error == 0)
error = saspace(periph, count - nmarks,
spaceop);
+ /*
+ * At this point, clear that we've written the tape
+ * and that we've written any filemarks. We really
+ * don't know what the applications wishes to do next-
+ * the sacheckeod's will make sure we terminated the
+ * tape correctly if we'd been writing, but the next
+ * action the user application takes will set again
+ * whether we need to write filemarks.
+ */
+ softc->flags &= ~SA_FLAG_TAPE_WRITTEN;
+ softc->filemarks = 0;
break;
}
case MTREW: /* rewind */
+ (void) sacheckeod(periph);
error = sarewind(periph);
+ /* see above */
+ softc->flags &= ~SA_FLAG_TAPE_WRITTEN;
+ softc->filemarks = 0;
break;
case MTERASE: /* erase */
error = saerase(periph, count);
@@ -618,6 +691,12 @@ saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
error = saretension(periph);
break;
case MTOFFL: /* rewind and put the drive offline */
+
+ (void) sacheckeod(periph);
+ /* see above */
+ softc->flags &= ~SA_FLAG_TAPE_WRITTEN;
+ softc->filemarks = 0;
+
/*
* Be sure to allow media removal before
* attempting the eject.
@@ -630,7 +709,6 @@ saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
else
break;
- /* XXX KDM */
softc->flags &= ~SA_FLAG_TAPE_LOCKED;
softc->flags &= ~SA_FLAG_TAPE_MOUNTED;
break;
@@ -644,6 +722,8 @@ saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
error = sasetparams(periph, SA_PARAM_BLOCKSIZE, count,
0, 0);
if (error == 0) {
+ softc->last_media_blksize =
+ softc->media_blksize;
softc->media_blksize = count;
if (count) {
softc->flags |= SA_FLAG_FIXED;
@@ -655,6 +735,11 @@ saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
softc->blk_mask = ~0;
softc->blk_shift = 0;
}
+ /*
+ * Make the user's desire 'persistent'.
+ */
+ softc->quirks &= ~SA_QUIRK_VARIABLE;
+ softc->quirks |= SA_QUIRK_FIXED;
} else {
softc->flags &= ~SA_FLAG_FIXED;
if (softc->max_blk == 0) {
@@ -667,6 +752,11 @@ saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
} else {
softc->blk_mask = 0;
}
+ /*
+ * Make the user's desire 'persistent'.
+ */
+ softc->quirks |= SA_QUIRK_VARIABLE;
+ softc->quirks &= ~SA_QUIRK_FIXED;
}
}
break;
@@ -1009,14 +1099,18 @@ sastart(struct cam_periph *periph, union ccb *start_ccb)
length =
bp->b_bcount / softc->media_blksize;
}
+ CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
+ ("Fixed Record Count is %d\n", length));
} else {
length = bp->b_bcount;
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO,
+ ("Variable Record Count is %d\n", length));
}
devstat_start_transaction(&softc->device_stats);
/*
- * XXX - Perhaps we should...
+ * Some people have theorized that we should
* suppress illegal length indication if we are
* running in variable block mode so that we don't
* have to request sense every time our requested
@@ -1027,6 +1121,13 @@ sastart(struct cam_periph *periph, union ccb *start_ccb)
* information about blocks that are larger than
* our read buffer unless we set the block size
* in the mode page to something other than 0.
+ *
+ * I believe that this is a non-issue. If user apps
+ * don't adjust their read size to match our record
+ * size, that's just life. Anyway, the typical usage
+ * would be to issue, e.g., 64KB reads and occasionally
+ * have to do deal with 512 byte or 1KB intermediate
+ * records.
*/
scsi_sa_read_write(&start_ccb->csio,
/*retries*/4,
@@ -1075,7 +1176,6 @@ sadone(struct cam_periph *periph, union ccb *done_ccb)
bp = (struct buf *)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) {
/*
* A retry was scheuled, so
@@ -1156,14 +1256,26 @@ sadone(struct cam_periph *periph, union ccb *done_ccb)
xpt_release_ccb(done_ccb);
}
+
+/*
+ * Mount the tape (make sure it's ready for I/O).
+ */
static int
-samount(struct cam_periph *periph)
+samount(struct cam_periph *periph, int oflags, dev_t dev)
{
struct sa_softc *softc;
union ccb *ccb;
struct ccb_scsiio *csio;
int error;
+ /*
+ * oflags can be checked for 'kind' of open (read-only check) - later
+ * dev can be checked for a control-mode or compression open - later
+ */
+ UNUSED_PARAMETER(oflags);
+ UNUSED_PARAMETER(dev);
+
+
softc = (struct sa_softc *)periph->softc;
ccb = cam_periph_getccb(periph, /* priority */1);
csio = &ccb->csio;
@@ -1196,7 +1308,7 @@ samount(struct cam_periph *periph)
if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) {
struct scsi_read_block_limits_data *rblim;
int comp_enabled, comp_supported;
- u_int8_t write_protect;
+ u_int8_t write_protect, guessing = 0;
/*
* Clear out old state.
@@ -1275,6 +1387,51 @@ samount(struct cam_periph *periph)
goto exit;
}
+ /*
+ * If no quirk has determined that this is a device that is
+ * preferred to be in fixed or variable mode, now is the time
+ * to find out.
+ */
+ if ((softc->quirks & (SA_QUIRK_FIXED|SA_QUIRK_VARIABLE)) == 0) {
+ guessing = 1;
+ switch (softc->media_density) {
+ case SCSI_DENSITY_QIC_11_4TRK:
+ case SCSI_DENSITY_QIC_11_9TRK:
+ case SCSI_DENSITY_QIC_24:
+ case SCSI_DENSITY_QIC_120:
+ case SCSI_DENSITY_QIC_150:
+ softc->quirks |= SA_QUIRK_FIXED;
+ softc->last_media_blksize = 512;
+ break;
+ default:
+ softc->last_media_blksize =
+ softc->media_blksize;
+ softc->quirks |= SA_QUIRK_VARIABLE;
+ break;
+ }
+ }
+ /*
+ * If no quirk has determined that this is a device that needs
+ * to have 2 Filemarks at EOD, now is the time to find out.
+ */
+ if ((softc->quirks & SA_QUIRK_2FM) != 0) {
+ switch (softc->media_density) {
+ case SCSI_DENSITY_HALFINCH_800:
+ case SCSI_DENSITY_HALFINCH_1600:
+ case SCSI_DENSITY_HALFINCH_6250:
+ case SCSI_DENSITY_HALFINCH_6250C:
+ case SCSI_DENSITY_HALFINCH_PE:
+ softc->quirks |= SA_QUIRK_2FM;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * Now validate that some info we got makes sense.
+ */
+
if ((softc->max_blk < softc->media_blksize) ||
(softc->min_blk > softc->media_blksize &&
softc->media_blksize)) {
@@ -1285,6 +1442,57 @@ samount(struct cam_periph *periph)
softc->max_blk = softc->min_blk =
softc->media_blksize;
}
+
+ /*
+ * Now put ourselves into the right frame of mind based
+ * upon quirks...
+ */
+tryagain:
+ if ((softc->quirks & SA_QUIRK_FIXED) &&
+ (softc->media_blksize == 0)) {
+ softc->media_blksize = softc->last_media_blksize;
+ if (softc->media_blksize == 0) {
+ softc->media_blksize = BLKDEV_IOSIZE;
+ if (softc->media_blksize < softc->min_blk) {
+ softc->media_blksize = softc->min_blk;
+ }
+ }
+ error = sasetparams(periph, SA_PARAM_BLOCKSIZE,
+ softc->media_blksize, 0, 0);
+ if (error) {
+ xpt_print_path(ccb->ccb_h.path);
+ printf("unable to set fixed blocksize to %d\n",
+ softc->media_blksize);
+ goto exit;
+ }
+ }
+
+ if ((softc->quirks & SA_QUIRK_VARIABLE) &&
+ (softc->media_blksize != 0)) {
+ softc->last_media_blksize = softc->media_blksize;
+ softc->media_blksize = 0;
+ error = sasetparams(periph, SA_PARAM_BLOCKSIZE,
+ 0, 0, 0);
+ if (error) {
+ /*
+ * If this fails and we were guessing, just
+ * assume that we got it wrong and go try
+ * fixed block mode...
+ */
+ xpt_print_path(ccb->ccb_h.path);
+ if (guessing && softc->media_density ==
+ SCSI_DEFAULT_DENSITY) {
+ softc->quirks &= ~SA_QUIRK_VARIABLE;
+ softc->quirks |= SA_QUIRK_FIXED;
+ if (softc->last_media_blksize == 0)
+ softc->last_media_blksize = 512;
+ goto tryagain;
+ }
+ printf("unable to set variable blocksize\n");
+ goto exit;
+ }
+ }
+
/*
* Now that we have the current block size,
* set up some parameters for sastart's usage.
@@ -1331,13 +1539,16 @@ samount(struct cam_periph *periph)
} else
softc->flags |= SA_FLAG_COMP_UNSUPP;
- if (softc->buffer_mode != SMH_SA_BUF_MODE_NOBUF)
- goto exit;
+ if (softc->buffer_mode == SMH_SA_BUF_MODE_NOBUF) {
+ error = sasetparams(periph, SA_PARAM_BUFF_MODE, 0,
+ 0, 0);
+ if (error == 0)
+ softc->buffer_mode = SMH_SA_BUF_MODE_SIBUF;
+ }
- error = sasetparams(periph, SA_PARAM_BUFF_MODE, 0, 0, 0);
if (error == 0)
- softc->buffer_mode = SMH_SA_BUF_MODE_SIBUF;
+ softc->flags |= SA_FLAG_TAPE_MOUNTED;
exit:
if (rblim != NULL)
free(rblim, M_TEMP);
@@ -1367,15 +1578,13 @@ sacheckeod(struct cam_periph *periph)
if ((softc->flags & SA_FLAG_TAPE_WRITTEN) != 0) {
markswanted++;
-
- if ((softc->flags & SA_FLAG_2FM_AT_EOD) != 0)
+ if ((softc->quirks & SA_QUIRK_2FM) != 0)
markswanted++;
}
if (softc->filemarks < markswanted) {
markswanted -= softc->filemarks;
- error = sawritefilemarks(periph, markswanted,
- /*setmarks*/FALSE);
+ error = sawritefilemarks(periph, markswanted, FALSE);
} else {
error = 0;
}
@@ -1405,7 +1614,7 @@ saerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
|| (sense_key == SSD_KEY_BLANK_CHECK))) {
u_int32_t info;
u_int32_t resid;
- int defer_action;
+ int defer_action;
/*
* Filter out some sense codes of interest.
@@ -1423,6 +1632,11 @@ saerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
info /= softc->media_blksize;
}
}
+ 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 ((resid > 0 && resid < csio->dxfer_len)
&& (softc->flags & SA_FLAG_FIXED) != 0)
defer_action = TRUE;
@@ -1643,6 +1857,15 @@ retry:
bcopy(ncomp_page, comp_page,sizeof(*comp_page));
}
+ if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) {
+ int idx;
+ char *xyz = mode_buffer;
+ xpt_print_path(periph->path);
+ printf("Mode Sense Data=");
+ for (idx = 0; idx < mode_buffer_len; idx++)
+ printf(" 0x%02x", xyz[idx]);
+ printf("\n");
+ }
} else if (status == CAM_SCSI_STATUS_ERROR) {
/* Tell the user about the fatal error. */
scsi_sense_print(&ccb->csio);
@@ -1859,11 +2082,12 @@ sasetparams(struct cam_periph *periph, sa_params params_to_set,
/*timeout*/ 5000);
if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) {
+ int idx;
char *xyz = mode_buffer;
xpt_print_path(periph->path);
printf("Mode Select Data=");
- for (error = 0; error < mode_buffer_len; error++)
- printf(" 0x%02x", xyz[error]);
+ for (idx = 0; idx < mode_buffer_len; idx++)
+ printf(" 0x%02x", xyz[idx]);
printf("\n");
}
@@ -2003,9 +2227,7 @@ sarewind(struct cam_periph *periph)
/*reduction*/0,
/*timeout*/0,
/*getcount_only*/0);
-
xpt_release_ccb(ccb);
-
return (error);
}
@@ -2037,9 +2259,7 @@ saspace(struct cam_periph *periph, int count, scsi_space_code code)
/*reduction*/0,
/*timeout*/0,
/*getcount_only*/0);
-
xpt_release_ccb(ccb);
-
return (error);
}
@@ -2074,6 +2294,10 @@ sawritefilemarks(struct cam_periph *periph, int nmarks, int setmarks)
/*timeout*/0,
/*getcount_only*/0);
+ /*
+ * XXXX: Actually, we need to get back the actual number of filemarks
+ * XXXX: written (there can be a residual).
+ */
if (error == 0) {
struct sa_softc *softc;
@@ -2082,7 +2306,6 @@ sawritefilemarks(struct cam_periph *periph, int nmarks, int setmarks)
}
xpt_release_ccb(ccb);
-
return (error);
}
@@ -2117,9 +2340,7 @@ saretension(struct cam_periph *periph)
/*reduction*/0,
/*timeout*/0,
/*getcount_only*/0);
-
xpt_release_ccb(ccb);
-
return(error);
}
@@ -2208,9 +2429,7 @@ saloadunload(struct cam_periph *periph, int load)
/*reduction*/0,
/*timeout*/0,
/*getcount_only*/0);
-
xpt_release_ccb(ccb);
-
return (error);
}
@@ -2244,9 +2463,7 @@ saerase(struct cam_periph *periph, int longerase)
/*reduction*/0,
/*timeout*/0,
/*getcount_only*/0);
-
xpt_release_ccb(ccb);
-
return (error);
}