1. Move the mode_select functionality into common code (in st.c) and

invoke the common routine for both scsi and atapi tapes.

2. Replace a numeric constant with some sizeof's when calculating the
   size of the mode_select command buffer, clear the entire buffer, and
   KASSERT to ensure the page_0_size loaded from quirk table is valid.

3. Add a quirk for my Seagate Travan-40 tape drive.

As discussed on tech-kern@

Addresses my PR kern/34832
This commit is contained in:
pgoyette 2009-08-15 12:44:55 +00:00
parent 89669ce394
commit 345b8f1066
4 changed files with 75 additions and 71 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: st.c,v 1.211 2009/05/12 14:44:31 cegger Exp $ */
/* $NetBSD: st.c,v 1.212 2009/08/15 12:44:55 pgoyette Exp $ */
/*-
* Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
@ -50,7 +50,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: st.c,v 1.211 2009/05/12 14:44:31 cegger Exp $");
__KERNEL_RCSID(0, "$NetBSD: st.c,v 1.212 2009/08/15 12:44:55 pgoyette Exp $");
#include "opt_scsi.h"
@ -306,6 +306,13 @@ static const struct st_quirk_inquiry_pattern st_quirk_patterns[] = {
{0, 0, 0}, /* minor 8-11 */
{0, 0, 0} /* minor 12-15 */
}}},
{{T_SEQUENTIAL, T_REMOV,
"Seagate STT3401A", "hp0atxa", ""}, {0, 0, {
{ST_Q_FORCE_BLKSIZE, 512, 0}, /* minor 0-3 */
{ST_Q_FORCE_BLKSIZE, 1024, 0}, /* minor 4-7 */
{ST_Q_FORCE_BLKSIZE, 512, 0}, /* minor 8-11 */
{ST_Q_FORCE_BLKSIZE, 512, 0} /* minor 12-15 */
}}},
};
#define NOEJECT 0
@ -488,6 +495,7 @@ st_identify_drive(struct st_softc *st, struct scsipi_inquiry_pattern *inqbuf)
st->drive_quirks = finger->quirkdata.quirks;
st->quirks = finger->quirkdata.quirks; /* start value */
st->page_0_size = finger->quirkdata.page_0_size;
KASSERT(st->page_0_size <= MAX_PAGE_0_SIZE);
st_loadquirks(st);
}
}
@ -2401,3 +2409,57 @@ stdump(dev_t dev, daddr_t blkno, void *va,
/* Not implemented. */
return (ENXIO);
}
/*
* Send a filled out parameter structure to the drive to
* set it into the desire modes etc.
*/
int
st_mode_select(struct st_softc *st, int flags)
{
u_int select_len;
struct select {
struct scsi_mode_parameter_header_6 header;
struct scsi_general_block_descriptor blk_desc;
u_char sense_data[MAX_PAGE_0_SIZE];
} select;
struct scsipi_periph *periph = st->sc_periph;
select_len = sizeof(select.header) + sizeof(select.blk_desc) +
st->page_0_size;
/*
* This quirk deals with drives that have only one valid mode
* and think this gives them license to reject all mode selects,
* even if the selected mode is the one that is supported.
*/
if (st->quirks & ST_Q_UNIMODAL) {
SC_DEBUG(periph, SCSIPI_DB3,
("not setting density 0x%x blksize 0x%x\n",
st->density, st->blksize));
return (0);
}
/*
* Set up for a mode select
*/
memset(&select, 0, sizeof(select));
select.header.blk_desc_len = sizeof(struct scsi_general_block_descriptor);
select.header.dev_spec &= ~SMH_DSP_BUFF_MODE;
select.blk_desc.density = st->density;
if (st->flags & ST_DONTBUFFER)
select.header.dev_spec |= SMH_DSP_BUFF_MODE_OFF;
else
select.header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
if (st->flags & ST_FIXEDBLOCKS)
_lto3b(st->blksize, select.blk_desc.blklen);
if (st->page_0_size)
memcpy(select.sense_data, st->sense_data, st->page_0_size);
/*
* do the command
*/
return scsipi_mode_select(periph, 0, &select.header, select_len,
flags | XS_CTL_DATA_ONSTACK, ST_RETRIES,
ST_CTL_TIME);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: st_atapi.c,v 1.22 2009/05/12 14:44:31 cegger Exp $ */
/* $NetBSD: st_atapi.c,v 1.23 2009/08/15 12:44:55 pgoyette Exp $ */
/*
* Copyright (c) 2001 Manuel Bouyer.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: st_atapi.c,v 1.22 2009/05/12 14:44:31 cegger Exp $");
__KERNEL_RCSID(0, "$NetBSD: st_atapi.c,v 1.23 2009/08/15 12:44:55 pgoyette Exp $");
#include "opt_scsi.h"
#include "rnd.h"
@ -51,7 +51,6 @@ static int st_atapibus_match(device_t, cfdata_t, void *);
static void st_atapibus_attach(device_t, device_t, void *);
static int st_atapibus_ops(struct st_softc *, int, int);
static int st_atapibus_mode_sense(struct st_softc *, int);
static int st_atapibus_mode_select(struct st_softc *, int);
CFATTACH_DECL(st_atapibus, sizeof(struct st_softc),
st_atapibus_match, st_atapibus_attach, stdetach, stactivate);
@ -122,7 +121,7 @@ st_atapibus_ops(struct st_softc *st, int op, int flags)
case ST_OPS_MODESENSE:
return st_atapibus_mode_sense(st, flags);
case ST_OPS_MODESELECT:
return st_atapibus_mode_select(st, flags);
return st_mode_select(st, flags);
case ST_OPS_CMPRSS_ON:
case ST_OPS_CMPRSS_OFF:
return ENODEV;
@ -176,9 +175,3 @@ st_atapibus_mode_sense(struct st_softc *st, int flags)
}
return error;
}
static int
st_atapibus_mode_select(struct st_softc *st, int flags)
{
return ENODEV; /* for now ... */
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: st_scsi.c,v 1.29 2009/05/12 14:44:31 cegger Exp $ */
/* $NetBSD: st_scsi.c,v 1.30 2009/08/15 12:44:55 pgoyette Exp $ */
/*-
* Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
@ -50,7 +50,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: st_scsi.c,v 1.29 2009/05/12 14:44:31 cegger Exp $");
__KERNEL_RCSID(0, "$NetBSD: st_scsi.c,v 1.30 2009/08/15 12:44:55 pgoyette Exp $");
#include "opt_scsi.h"
#include "rnd.h"
@ -72,7 +72,6 @@ static void st_scsibus_attach(device_t, device_t, void *);
static int st_scsibus_ops(struct st_softc *, int, int);
static int st_scsibus_read_block_limits(struct st_softc *, int);
static int st_scsibus_mode_sense(struct st_softc *, int);
static int st_scsibus_mode_select(struct st_softc *, int);
static int st_scsibus_cmprss(struct st_softc *, int, int);
CFATTACH_DECL(st_scsibus, sizeof(struct st_softc),
@ -118,7 +117,7 @@ st_scsibus_ops(struct st_softc *st, int op, int flags)
case ST_OPS_MODESENSE:
return st_scsibus_mode_sense(st, flags);
case ST_OPS_MODESELECT:
return st_scsibus_mode_select(st, flags);
return st_mode_select(st, flags);
case ST_OPS_CMPRSS_ON:
case ST_OPS_CMPRSS_OFF:
return st_scsibus_cmprss(st, flags,
@ -187,7 +186,9 @@ st_scsibus_mode_sense(struct st_softc *st, int flags)
} scsipi_sense;
struct scsipi_periph *periph = st->sc_periph;
scsipi_sense_len = 12 + st->page_0_size;
scsipi_sense_len = sizeof(scsipi_sense.header) +
sizeof(scsipi_sense.blk_desc) +
st->page_0_size;
/*
* Set up a mode sense
@ -222,59 +223,6 @@ st_scsibus_mode_sense(struct st_softc *st, int flags)
return (0);
}
/*
* Send a filled out parameter structure to the drive to
* set it into the desire modes etc.
*/
static int
st_scsibus_mode_select(struct st_softc *st, int flags)
{
u_int scsi_select_len;
struct scsi_select {
struct scsi_mode_parameter_header_6 header;
struct scsi_general_block_descriptor blk_desc;
u_char sense_data[MAX_PAGE_0_SIZE];
} scsi_select;
struct scsipi_periph *periph = st->sc_periph;
scsi_select_len = 12 + st->page_0_size;
/*
* This quirk deals with drives that have only one valid mode
* and think this gives them license to reject all mode selects,
* even if the selected mode is the one that is supported.
*/
if (st->quirks & ST_Q_UNIMODAL) {
SC_DEBUG(periph, SCSIPI_DB3,
("not setting density 0x%x blksize 0x%x\n",
st->density, st->blksize));
return (0);
}
/*
* Set up for a mode select
*/
memset(&scsi_select, 0, scsi_select_len);
scsi_select.header.blk_desc_len = sizeof(struct scsi_general_block_descriptor);
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)
memcpy(scsi_select.sense_data, st->sense_data, st->page_0_size);
/*
* do the command
*/
return scsipi_mode_select(periph, 0, &scsi_select.header,
scsi_select_len, flags | XS_CTL_DATA_ONSTACK,
ST_RETRIES, ST_CTL_TIME);
}
static int
st_scsibus_cmprss(struct st_softc *st, int flags, int onoff)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: stvar.h,v 1.19 2009/05/12 14:44:31 cegger Exp $ */
/* $NetBSD: stvar.h,v 1.20 2009/08/15 12:44:55 pgoyette Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -181,5 +181,6 @@ struct st_softc {
void stattach(device_t, struct st_softc *, void *);
int stactivate(device_t, enum devact);
int stdetach(device_t, int);
int st_mode_select(struct st_softc *, int);
extern struct cfdriver st_cd;