From 5b51ec5cc85d425cb3e7b076d1f1d3ae58efa964 Mon Sep 17 00:00:00 2001 From: thorpej Date: Thu, 11 Jan 1996 03:36:34 +0000 Subject: [PATCH] Honor cache request and implement erase command, and add the SCSI tape device configuration page. Fixes PRs 807, 1201, and 1705. From John Kohl . --- sys/dev/scsipi/scsi_tape.h | 47 ++++++++++++++++++++++++++- sys/dev/scsipi/st.c | 66 +++++++++++++++++++++++++++++++------- sys/scsi/scsi_tape.h | 47 ++++++++++++++++++++++++++- sys/scsi/st.c | 66 +++++++++++++++++++++++++++++++------- 4 files changed, 200 insertions(+), 26 deletions(-) diff --git a/sys/dev/scsipi/scsi_tape.h b/sys/dev/scsipi/scsi_tape.h index 4ff8042e75bd..654b02ac7ec1 100644 --- a/sys/dev/scsipi/scsi_tape.h +++ b/sys/dev/scsipi/scsi_tape.h @@ -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 diff --git a/sys/dev/scsipi/st.c b/sys/dev/scsipi/st.c index 9e537181a4ee..d0a6e4fb0324 100644 --- a/sys/dev/scsipi/st.c +++ b/sys/dev/scsipi/st.c @@ -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 */ diff --git a/sys/scsi/scsi_tape.h b/sys/scsi/scsi_tape.h index 4ff8042e75bd..654b02ac7ec1 100644 --- a/sys/scsi/scsi_tape.h +++ b/sys/scsi/scsi_tape.h @@ -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 diff --git a/sys/scsi/st.c b/sys/scsi/st.c index 9e537181a4ee..d0a6e4fb0324 100644 --- a/sys/scsi/st.c +++ b/sys/scsi/st.c @@ -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 */