Honor cache request and implement erase command, and add the SCSI tape

device configuration page.  Fixes PRs 807, 1201, and 1705.
From John Kohl <jtk@kolvir.blrc.ma.us>.
This commit is contained in:
thorpej 1996-01-11 03:36:34 +00:00
parent 94bb8db5ad
commit 5b51ec5cc8
4 changed files with 200 additions and 26 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: scsi_tape.h,v 1.6 1994/12/28 19:43:08 mycroft Exp $ */
/* $NetBSD: scsi_tape.h,v 1.7 1996/01/11 03:36:34 thorpej Exp $ */
/*
* Copyright (c) 1994 Charles Hannum. All rights reserved.
@ -110,6 +110,16 @@ struct scsi_load {
u_char control;
};
#define ERASE 0x19
struct scsi_erase {
u_char opcode;
u_char byte2;
#define SE_LONG 0x01
#define SE_IMMED 0x02
u_char unused[3];
u_char control;
};
#define READ_BLOCK_LIMITS 0x05
struct scsi_block_limits {
u_char opcode;
@ -127,6 +137,41 @@ struct scsi_block_limits_data {
u_char min_length_0; /* Least significant */
};
/* See SCSI-II spec 9.3.3.1 */
struct scsi_tape_dev_conf_page {
u_char pagecode; /* 0x10 */
u_char pagelength; /* 0x0e */
u_char byte2;
#define SMT_CAP 0x40 /* change active partition */
#define SMT_CAF 0x20 /* change active format */
#define SMT_AFMASK 0x1f /* active format mask */
u_char active_partition;
u_char wb_full_ratio;
u_char rb_empty_ratio;
u_char wrdelay_time_1; /* MSB */
u_char wrdelay_time_0; /* LSB */
u_char byte8;
#define SMT_DBR 0x80 /* data buffer recovery */
#define SMT_BIS 0x40 /* block identifiers supported */
#define SMT_RSMK 0x20 /* report setmarks */
#define SMT_AVC 0x10 /* automatic velocity control */
#define SMT_SOCF_MASK 0xc0 /* stop on consecutive formats */
#define SMT_RBO 0x20 /* recover buffer order */
#define SMT_REW 0x10 /* report early warning */
u_char gap_size;
u_char byte10;
#define SMT_EODDEFINED 0xe0 /* EOD defined */
#define SMT_EEG 0x10 /* enable EOD generation */
#define SMT_SEW 0x80 /* synchronize at early warning */
u_char ew_bufsize_2; /* MSB */
u_char ew_bufsize_1; /* ... */
u_char ew_bufsize_0; /* LSB */
u_char sel_comp_alg;
#define SMT_COMP_NONE 0x00
#define SMT_COMP_DEFAULT 0x01
u_char reserved;
};
/* defines for the device specific byte in the mode select/sense header */
#define SMH_DSP_SPEED 0x0F
#define SMH_DSP_BUFF_MODE 0x70

View File

@ -1,4 +1,4 @@
/* $NetBSD: st.c,v 1.56 1996/01/05 16:03:35 pk Exp $ */
/* $NetBSD: st.c,v 1.57 1996/01/11 03:36:38 thorpej Exp $ */
/*
* Copyright (c) 1994 Charles Hannum. All rights reserved.
@ -266,14 +266,14 @@ int st_touch_tape __P((struct st_softc *));
int st_write_filemarks __P((struct st_softc *, int number, int flags));
int st_load __P((struct st_softc *, u_int type, int flags));
int st_mode_select __P((struct st_softc *, int flags));
void ststrategy();
int st_check_eod();
void ststart();
void st_unmount();
int st_mount_tape();
void st_loadquirks();
void st_identify_drive();
int st_interpret_sense();
void ststrategy __P((struct buf *));
int st_check_eod __P((struct st_softc *, boolean, int *, int));
void ststart __P((struct st_softc *));
void st_unmount __P((struct st_softc *, boolean));
int st_mount_tape __P((dev_t, int));
void st_loadquirks __P((struct st_softc *));
void st_identify_drive __P((struct st_softc *, struct scsi_inquiry_data *));
int st_interpret_sense __P((struct scsi_xfer *));
struct scsi_device st_switch = {
st_interpret_sense,
@ -298,6 +298,7 @@ struct scsi_device st_switch = {
#define ST_BLANK_READ 0x0200 /* BLANK CHECK encountered already */
#define ST_2FM_AT_EOD 0x0400 /* write 2 file marks at EOD */
#define ST_MOUNTED 0x0800 /* Device is presently mounted */
#define ST_DONTBUFFER 0x1000 /* Disable buffering/caching */
#define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ)
#define ST_PER_MOUNT (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
@ -1121,7 +1122,13 @@ stioctl(dev, cmd, arg, flag, p)
error = st_space(st, 1, SP_EOM, flags);
break;
case MTCACHE: /* enable controller cache */
st->flags &= ~ST_DONTBUFFER;
goto try_new_value;
case MTNOCACHE: /* disable controller cache */
st->flags |= ST_DONTBUFFER;
goto try_new_value;
case MTERASE: /* erase volume */
error = st_erase(st, number, flags);
break;
case MTSETBSIZ: /* Set block size for device */
#ifdef NOTYET
@ -1147,9 +1154,10 @@ stioctl(dev, cmd, arg, flag, p)
goto try_new_value;
case MTSETDNSTY: /* Set density for device and mode */
if (number > SCSI_2_MAX_DENSITY_CODE)
if (number > SCSI_2_MAX_DENSITY_CODE) {
error = EINVAL;
else
break;
} else
st->density = number;
goto try_new_value;
@ -1378,8 +1386,12 @@ st_mode_select(st, flags)
bzero(&scsi_select, scsi_select_len);
scsi_select.header.blk_desc_len = sizeof(struct scsi_blk_desc);
scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
scsi_select.header.dev_spec &= ~SMH_DSP_BUFF_MODE;
scsi_select.blk_desc.density = st->density;
if (st->flags & ST_DONTBUFFER)
scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_OFF;
else
scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
if (st->flags & ST_FIXEDBLOCKS)
lto3b(st->blksize, scsi_select.blk_desc.blklen);
if (st->page_0_size)
@ -1393,6 +1405,36 @@ st_mode_select(st, flags)
ST_RETRIES, 5000, NULL, flags | SCSI_DATA_OUT);
}
/*
* issue an erase command
*/
int
st_erase(st, full, flags)
struct st_softc *st;
int full, flags;
{
struct scsi_erase cmd;
/*
* Full erase means set LONG bit in erase command, which asks
* the drive to erase the entire unit. Without this bit, we're
* asking the drive to write an erase gap.
*/
bzero(&cmd, sizeof(cmd));
cmd.opcode = ERASE;
if (full)
cmd.byte2 = SE_IMMED|SE_LONG;
else
cmd.byte2 = SE_IMMED;
/*
* XXX We always do this asynchronously, for now. How long should
* we wait if we want to (eventually) to it synchronously?
*/
return (scsi_scsi_cmd(st->sc_link, (struct scsi_generic *)&cmd,
sizeof(cmd), 0, 0, ST_RETRIES, 5000, NULL, flags));
}
/*
* skip N blocks/filemarks/seq filemarks/eom
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: scsi_tape.h,v 1.6 1994/12/28 19:43:08 mycroft Exp $ */
/* $NetBSD: scsi_tape.h,v 1.7 1996/01/11 03:36:34 thorpej Exp $ */
/*
* Copyright (c) 1994 Charles Hannum. All rights reserved.
@ -110,6 +110,16 @@ struct scsi_load {
u_char control;
};
#define ERASE 0x19
struct scsi_erase {
u_char opcode;
u_char byte2;
#define SE_LONG 0x01
#define SE_IMMED 0x02
u_char unused[3];
u_char control;
};
#define READ_BLOCK_LIMITS 0x05
struct scsi_block_limits {
u_char opcode;
@ -127,6 +137,41 @@ struct scsi_block_limits_data {
u_char min_length_0; /* Least significant */
};
/* See SCSI-II spec 9.3.3.1 */
struct scsi_tape_dev_conf_page {
u_char pagecode; /* 0x10 */
u_char pagelength; /* 0x0e */
u_char byte2;
#define SMT_CAP 0x40 /* change active partition */
#define SMT_CAF 0x20 /* change active format */
#define SMT_AFMASK 0x1f /* active format mask */
u_char active_partition;
u_char wb_full_ratio;
u_char rb_empty_ratio;
u_char wrdelay_time_1; /* MSB */
u_char wrdelay_time_0; /* LSB */
u_char byte8;
#define SMT_DBR 0x80 /* data buffer recovery */
#define SMT_BIS 0x40 /* block identifiers supported */
#define SMT_RSMK 0x20 /* report setmarks */
#define SMT_AVC 0x10 /* automatic velocity control */
#define SMT_SOCF_MASK 0xc0 /* stop on consecutive formats */
#define SMT_RBO 0x20 /* recover buffer order */
#define SMT_REW 0x10 /* report early warning */
u_char gap_size;
u_char byte10;
#define SMT_EODDEFINED 0xe0 /* EOD defined */
#define SMT_EEG 0x10 /* enable EOD generation */
#define SMT_SEW 0x80 /* synchronize at early warning */
u_char ew_bufsize_2; /* MSB */
u_char ew_bufsize_1; /* ... */
u_char ew_bufsize_0; /* LSB */
u_char sel_comp_alg;
#define SMT_COMP_NONE 0x00
#define SMT_COMP_DEFAULT 0x01
u_char reserved;
};
/* defines for the device specific byte in the mode select/sense header */
#define SMH_DSP_SPEED 0x0F
#define SMH_DSP_BUFF_MODE 0x70

View File

@ -1,4 +1,4 @@
/* $NetBSD: st.c,v 1.56 1996/01/05 16:03:35 pk Exp $ */
/* $NetBSD: st.c,v 1.57 1996/01/11 03:36:38 thorpej Exp $ */
/*
* Copyright (c) 1994 Charles Hannum. All rights reserved.
@ -266,14 +266,14 @@ int st_touch_tape __P((struct st_softc *));
int st_write_filemarks __P((struct st_softc *, int number, int flags));
int st_load __P((struct st_softc *, u_int type, int flags));
int st_mode_select __P((struct st_softc *, int flags));
void ststrategy();
int st_check_eod();
void ststart();
void st_unmount();
int st_mount_tape();
void st_loadquirks();
void st_identify_drive();
int st_interpret_sense();
void ststrategy __P((struct buf *));
int st_check_eod __P((struct st_softc *, boolean, int *, int));
void ststart __P((struct st_softc *));
void st_unmount __P((struct st_softc *, boolean));
int st_mount_tape __P((dev_t, int));
void st_loadquirks __P((struct st_softc *));
void st_identify_drive __P((struct st_softc *, struct scsi_inquiry_data *));
int st_interpret_sense __P((struct scsi_xfer *));
struct scsi_device st_switch = {
st_interpret_sense,
@ -298,6 +298,7 @@ struct scsi_device st_switch = {
#define ST_BLANK_READ 0x0200 /* BLANK CHECK encountered already */
#define ST_2FM_AT_EOD 0x0400 /* write 2 file marks at EOD */
#define ST_MOUNTED 0x0800 /* Device is presently mounted */
#define ST_DONTBUFFER 0x1000 /* Disable buffering/caching */
#define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ)
#define ST_PER_MOUNT (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
@ -1121,7 +1122,13 @@ stioctl(dev, cmd, arg, flag, p)
error = st_space(st, 1, SP_EOM, flags);
break;
case MTCACHE: /* enable controller cache */
st->flags &= ~ST_DONTBUFFER;
goto try_new_value;
case MTNOCACHE: /* disable controller cache */
st->flags |= ST_DONTBUFFER;
goto try_new_value;
case MTERASE: /* erase volume */
error = st_erase(st, number, flags);
break;
case MTSETBSIZ: /* Set block size for device */
#ifdef NOTYET
@ -1147,9 +1154,10 @@ stioctl(dev, cmd, arg, flag, p)
goto try_new_value;
case MTSETDNSTY: /* Set density for device and mode */
if (number > SCSI_2_MAX_DENSITY_CODE)
if (number > SCSI_2_MAX_DENSITY_CODE) {
error = EINVAL;
else
break;
} else
st->density = number;
goto try_new_value;
@ -1378,8 +1386,12 @@ st_mode_select(st, flags)
bzero(&scsi_select, scsi_select_len);
scsi_select.header.blk_desc_len = sizeof(struct scsi_blk_desc);
scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
scsi_select.header.dev_spec &= ~SMH_DSP_BUFF_MODE;
scsi_select.blk_desc.density = st->density;
if (st->flags & ST_DONTBUFFER)
scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_OFF;
else
scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
if (st->flags & ST_FIXEDBLOCKS)
lto3b(st->blksize, scsi_select.blk_desc.blklen);
if (st->page_0_size)
@ -1393,6 +1405,36 @@ st_mode_select(st, flags)
ST_RETRIES, 5000, NULL, flags | SCSI_DATA_OUT);
}
/*
* issue an erase command
*/
int
st_erase(st, full, flags)
struct st_softc *st;
int full, flags;
{
struct scsi_erase cmd;
/*
* Full erase means set LONG bit in erase command, which asks
* the drive to erase the entire unit. Without this bit, we're
* asking the drive to write an erase gap.
*/
bzero(&cmd, sizeof(cmd));
cmd.opcode = ERASE;
if (full)
cmd.byte2 = SE_IMMED|SE_LONG;
else
cmd.byte2 = SE_IMMED;
/*
* XXX We always do this asynchronously, for now. How long should
* we wait if we want to (eventually) to it synchronously?
*/
return (scsi_scsi_cmd(st->sc_link, (struct scsi_generic *)&cmd,
sizeof(cmd), 0, 0, ST_RETRIES, 5000, NULL, flags));
}
/*
* skip N blocks/filemarks/seq filemarks/eom
*/