summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authorken <ken@FreeBSD.org>1998-10-02 05:25:49 +0000
committerken <ken@FreeBSD.org>1998-10-02 05:25:49 +0000
commit555e3912745f812a59847721e00316f474707979 (patch)
tree38cf525c23efaa3da2ad851073076f6f6b69f64a /sys/cam
parentc19e09786ae641a353a484bb8ace2e97269c5b2b (diff)
downloadFreeBSD-src-555e3912745f812a59847721e00316f474707979.zip
FreeBSD-src-555e3912745f812a59847721e00316f474707979.tar.gz
Modify the changer driver so it can handle (hopefully!) changers that need
block descriptors enabled on mode sense commands. Basically, we try sending a mode sense with block descriptors disabled (the previous default), and if it fails, we try sending the mode sense with block descriptors enabled. If that works, we note that in a runtime quirk entry, so we don't bother disabling block descriptors again for the device. This problem was first reported by Chris Jones <cjones@honors.montana.edu> on one of the NetBSD lists, but I'd imagine that some FreeBSD users would have run into it eventually as well, since our changer driver is derived form the NetBSD changer driver. Also, change some of the probe logic so that we do the right thing in the case of a failure to attach. Fix a memory leak in chgetparams(). Add a couple of inline helper functions to scsi_all.h to correctly return the start of a mode page. NetBSD PR: kern/6214 Reviewed by: gibbs
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/scsi/scsi_all.h32
-rw-r--r--sys/cam/scsi/scsi_ch.c256
2 files changed, 218 insertions, 70 deletions
diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h
index 3a78840..adc16cf 100644
--- a/sys/cam/scsi/scsi_all.h
+++ b/sys/cam/scsi/scsi_all.h
@@ -14,7 +14,7 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
*
- * $Id: scsi_all.h,v 1.2 1998/09/18 22:33:59 ken Exp $
+ * $Id: scsi_all.h,v 1.3 1998/09/29 22:11:30 ken Exp $
*/
/*
@@ -796,7 +796,8 @@ static __inline u_int32_t scsi_2btoul(u_int8_t *bytes);
static __inline u_int32_t scsi_3btoul(u_int8_t *bytes);
static __inline int32_t scsi_3btol(u_int8_t *bytes);
static __inline u_int32_t scsi_4btoul(u_int8_t *bytes);
-
+static __inline void *find_mode_page_6(struct scsi_mode_header_6 *mode_header);
+static __inline void *find_mode_page_10(struct scsi_mode_header_10 *mode_header);
static __inline void scsi_extract_sense(struct scsi_sense_data *sense,
int *error_code, int *sense_key,
@@ -878,6 +879,33 @@ scsi_4btoul(u_int8_t *bytes)
bytes[3];
return (rv);
}
+
+/*
+ * Given the pointer to a returned mode sense buffer, return a pointer to
+ * the start of the first mode page.
+ */
+static __inline void *
+find_mode_page_6(struct scsi_mode_header_6 *mode_header)
+{
+ void *page_start;
+
+ page_start = (void *)((u_int8_t *)&mode_header[1] +
+ mode_header->blk_desc_len);
+
+ return(page_start);
+}
+
+static __inline void *
+find_mode_page_10(struct scsi_mode_header_10 *mode_header)
+{
+ void *page_start;
+
+ page_start = (void *)((u_int8_t *)&mode_header[1] +
+ scsi_2btoul(mode_header->blk_desc_len));
+
+ return(page_start);
+}
+
__END_DECLS
#endif /*_SCSI_SCSI_ALL_H*/
diff --git a/sys/cam/scsi/scsi_ch.c b/sys/cam/scsi/scsi_ch.c
index 0f5d9dc..e805c1d 100644
--- a/sys/cam/scsi/scsi_ch.c
+++ b/sys/cam/scsi/scsi_ch.c
@@ -24,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: scsi_ch.c,v 1.1 1998/05/17 13:08:49 hans Exp hans $
+ * $Id: scsi_ch.c,v 1.1 1998/09/15 06:36:34 gibbs Exp $
*/
/*
* Derived from the NetBSD SCSI changer driver.
@@ -124,11 +124,17 @@ typedef enum {
CH_CCB_WAITING
} ch_ccb_types;
+typedef enum {
+ CH_Q_NONE = 0x00,
+ CH_Q_NO_DBD = 0x01
+} ch_quirks;
+
#define ccb_state ppriv_field0
#define ccb_bp ppriv_ptr1
struct scsi_mode_sense_data {
struct scsi_mode_header_6 header;
+ struct scsi_mode_blk_desc blk_desc;
union {
struct page_element_address_assignment ea;
struct page_transport_geometry_parameters tg;
@@ -139,6 +145,7 @@ struct scsi_mode_sense_data {
struct ch_softc {
ch_flags flags;
ch_state state;
+ ch_quirks quirks;
union ccb saved_ccb;
struct devstat device_stats;
@@ -401,6 +408,7 @@ chregister(struct cam_periph *periph, void *arg)
softc->state = CH_STATE_PROBE;
periph->softc = softc;
cam_extend_set(chperiphs, periph->unit_number, periph);
+ softc->quirks = CH_Q_NONE;
/*
* Changers don't have a blocksize, and obviously don't support
@@ -527,17 +535,24 @@ chstart(struct cam_periph *periph, union ccb *start_ccb)
}
case CH_STATE_PROBE:
{
- struct scsi_mode_sense_data *sense_data;
+ int mode_buffer_len;
+ void *mode_buffer;
- sense_data = (struct scsi_mode_sense_data *)malloc(
- sizeof(*sense_data),
- M_TEMP, M_NOWAIT);
+ /*
+ * Include the block descriptor when calculating the mode
+ * buffer length,
+ */
+ mode_buffer_len = sizeof(struct scsi_mode_header_6) +
+ sizeof(struct scsi_mode_blk_desc) +
+ sizeof(struct page_element_address_assignment);
- if (sense_data == NULL) {
+ mode_buffer = malloc(mode_buffer_len, M_TEMP, M_NOWAIT);
+
+ if (mode_buffer == NULL) {
printf("chstart: couldn't malloc mode sense data\n");
break;
}
- bzero(sense_data, sizeof(*sense_data));
+ bzero(mode_buffer, mode_buffer_len);
/*
* Get the element address assignment page.
@@ -546,11 +561,12 @@ chstart(struct cam_periph *periph, union ccb *start_ccb)
/* retries */ 1,
/* cbfcnp */ chdone,
/* tag_action */ MSG_SIMPLE_Q_TAG,
- /* dbd */ TRUE,
+ /* dbd */ (softc->quirks & CH_Q_NO_DBD) ?
+ FALSE : TRUE,
/* page_code */ SMS_PAGE_CTRL_CURRENT,
/* page */ CH_ELEMENT_ADDR_ASSIGN_PAGE,
- /* param_buf */ (u_int8_t *)sense_data,
- /* param_len */ sizeof(*sense_data),
+ /* param_buf */ (u_int8_t *)mode_buffer,
+ /* param_len */ mode_buffer_len,
/* sense_len */ SSD_FULL_SIZE,
/* timeout */ CH_TIMEOUT_MODE_SENSE);
@@ -574,29 +590,26 @@ chdone(struct cam_periph *periph, union ccb *done_ccb)
switch(done_ccb->ccb_h.ccb_state) {
case CH_CCB_PROBE:
{
- struct scsi_mode_sense_data *sense_data;
+ struct scsi_mode_header_6 *mode_header;
+ struct page_element_address_assignment *ea;
char announce_buf[80];
- sense_data = (struct scsi_mode_sense_data *)csio->data_ptr;
+
+ mode_header = (struct scsi_mode_header_6 *)csio->data_ptr;
+
+ ea = (struct page_element_address_assignment *)
+ find_mode_page_6(mode_header);
if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP){
- softc->sc_firsts[CHET_MT] =
- scsi_2btoul(sense_data->pages.ea.mtea);
- softc->sc_counts[CHET_MT] =
- scsi_2btoul(sense_data->pages.ea.nmte);
- softc->sc_firsts[CHET_ST] =
- scsi_2btoul(sense_data->pages.ea.fsea);
- softc->sc_counts[CHET_ST] =
- scsi_2btoul(sense_data->pages.ea.nse);
- softc->sc_firsts[CHET_IE] =
- scsi_2btoul(sense_data->pages.ea.fieea);
- softc->sc_counts[CHET_IE] =
- scsi_2btoul(sense_data->pages.ea.niee);
- softc->sc_firsts[CHET_DT] =
- scsi_2btoul(sense_data->pages.ea.fdtea);
- softc->sc_counts[CHET_DT] =
- scsi_2btoul(sense_data->pages.ea.ndte);
+ softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea);
+ softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte);
+ softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea);
+ softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse);
+ softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea);
+ softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee);
+ softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea);
+ softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte);
softc->sc_picker = softc->sc_firsts[CHET_MT];
#define PLURAL(c) (c) == 1 ? "" : "s"
@@ -614,7 +627,7 @@ chdone(struct cam_periph *periph, union ccb *done_ccb)
} else {
int error;
- error = cherror(done_ccb, 0, SF_RETRY_UA);
+ error = cherror(done_ccb, 0, SF_RETRY_UA|SF_NO_PRINT);
/*
* Retry any UNIT ATTENTION type errors. They
* are expected at boot.
@@ -626,20 +639,60 @@ chdone(struct cam_periph *periph, union ccb *done_ccb)
*/
return;
} else if (error != 0) {
+ int retry_scheduled;
+ struct scsi_mode_sense_6 *sms;
+
+ sms = (struct scsi_mode_sense_6 *)
+ done_ccb->csio.cdb_io.cdb_bytes;
+
+ /*
+ * Check to see if block descriptors were
+ * disabled. Some devices don't like that.
+ * We're taking advantage of the fact that
+ * the first few bytes of the 6 and 10 byte
+ * mode sense commands are the same. If
+ * block descriptors were disabled, enable
+ * them and re-send the command.
+ */
+ if (sms->byte2 & SMS_DBD) {
+ sms->byte2 &= ~SMS_DBD;
+ xpt_action(done_ccb);
+ softc->quirks |= CH_Q_NO_DBD;
+ retry_scheduled = 1;
+ } else
+ retry_scheduled = 0;
+
/* Don't wedge this device's queue */
cam_release_devq(done_ccb->ccb_h.path,
/*relsim_flags*/0,
/*reduction*/0,
/*timeout*/0,
/*getcount_only*/0);
- sprintf(announce_buf,
- "Attempt to query device parameters"
- " failed");
+
+ if (retry_scheduled)
+ return;
+
+ if ((done_ccb->ccb_h.status & CAM_STATUS_MASK)
+ == CAM_SCSI_STATUS_ERROR)
+ scsi_sense_print(&done_ccb->csio);
+ else {
+ xpt_print_path(periph->path);
+ printf("got CAM status %#x\n",
+ done_ccb->ccb_h.status);
+ }
+ xpt_print_path(periph->path);
+ printf("fatal error, failed to attach to"
+ " device\n");
+
+ cam_periph_invalidate(periph);
+
+ announce_buf[0] = '\0';
}
}
- xpt_announce_periph(periph, announce_buf);
+ if (announce_buf[0] != '\0')
+ xpt_announce_periph(periph, announce_buf);
softc->state = CH_STATE_NORMAL;
- free(sense_data, M_TEMP);
+ free(mode_header, M_TEMP);
cam_periph_unlock(periph);
break;
}
@@ -1295,8 +1348,11 @@ chgetparams(struct cam_periph *periph)
{
union ccb *ccb;
struct ch_softc *softc;
- struct scsi_mode_sense_data *sense_data;
- int error, from;
+ void *mode_buffer;
+ int mode_buffer_len;
+ struct page_element_address_assignment *ea;
+ struct page_device_capabilities *cap;
+ int error, from, dbd;
u_int8_t *moves, *exchanges;
error = 0;
@@ -1305,14 +1361,26 @@ chgetparams(struct cam_periph *periph)
ccb = cam_periph_getccb(periph, /*priority*/ 1);
- sense_data = (struct scsi_mode_sense_data *)malloc(sizeof(*sense_data),
- M_TEMP, M_NOWAIT);
- if (sense_data == NULL) {
+ /*
+ * The scsi_mode_sense_data structure is just a convenience
+ * structure that allows us to easily calculate the worst-case
+ * storage size of the mode sense buffer.
+ */
+ mode_buffer_len = sizeof(struct scsi_mode_sense_data);
+
+ mode_buffer = malloc(mode_buffer_len, M_TEMP, M_NOWAIT);
+
+ if (mode_buffer == NULL) {
printf("chgetparams: couldn't malloc mode sense data\n");
return(ENOSPC);
}
- bzero(sense_data, sizeof(*sense_data));
+ bzero(mode_buffer, mode_buffer_len);
+
+ if (softc->quirks & CH_Q_NO_DBD)
+ dbd = FALSE;
+ else
+ dbd = TRUE;
/*
* Get the element address assignment page.
@@ -1321,35 +1389,60 @@ chgetparams(struct cam_periph *periph)
/* retries */ 1,
/* cbfcnp */ chdone,
/* tag_action */ MSG_SIMPLE_Q_TAG,
- /* dbd */ TRUE,
+ /* dbd */ dbd,
/* page_code */ SMS_PAGE_CTRL_CURRENT,
/* page */ CH_ELEMENT_ADDR_ASSIGN_PAGE,
- /* param_buf */ (u_int8_t *)sense_data,
- /* param_len */ sizeof(*sense_data),
+ /* param_buf */ (u_int8_t *)mode_buffer,
+ /* param_len */ mode_buffer_len,
/* sense_len */ SSD_FULL_SIZE,
/* timeout */ CH_TIMEOUT_MODE_SENSE);
error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0,
- /* sense_flags */ SF_RETRY_UA,
+ /* sense_flags */ SF_RETRY_UA |SF_NO_PRINT,
&softc->device_stats);
if (error) {
- xpt_print_path(periph->path);
- printf("chgetparams: error getting element address page\n");
- xpt_release_ccb(ccb);
- return(error);
+ if (dbd) {
+ struct scsi_mode_sense_6 *sms;
+
+ sms = (struct scsi_mode_sense_6 *)
+ ccb->csio.cdb_io.cdb_bytes;
+
+ sms->byte2 &= ~SMS_DBD;
+ error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0,
+ /* sense_flags */ SF_RETRY_UA,
+ &softc->device_stats);
+ } else {
+ /*
+ * Since we disabled sense printing above, print
+ * out the sense here since we got an error.
+ */
+ scsi_sense_print(&ccb->csio);
+ }
+
+ if (error) {
+ xpt_print_path(periph->path);
+ printf("chgetparams: error getting element "
+ "address page\n");
+ xpt_release_ccb(ccb);
+ free(mode_buffer, M_TEMP);
+ return(error);
+ }
}
- softc->sc_firsts[CHET_MT] = scsi_2btoul(sense_data->pages.ea.mtea);
- softc->sc_counts[CHET_MT] = scsi_2btoul(sense_data->pages.ea.nmte);
- softc->sc_firsts[CHET_ST] = scsi_2btoul(sense_data->pages.ea.fsea);
- softc->sc_counts[CHET_ST] = scsi_2btoul(sense_data->pages.ea.nse);
- softc->sc_firsts[CHET_IE] = scsi_2btoul(sense_data->pages.ea.fieea);
- softc->sc_counts[CHET_IE] = scsi_2btoul(sense_data->pages.ea.niee);
- softc->sc_firsts[CHET_DT] = scsi_2btoul(sense_data->pages.ea.fdtea);
- softc->sc_counts[CHET_DT] = scsi_2btoul(sense_data->pages.ea.ndte);
+ ea = (struct page_element_address_assignment *)
+ find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer);
+
+ softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea);
+ softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte);
+ softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea);
+ softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse);
+ softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea);
+ softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee);
+ softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea);
+ softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte);
- bzero(sense_data, sizeof(*sense_data));
+ bzero(mode_buffer, mode_buffer_len);
/*
* Now get the device capabilities page.
@@ -1358,36 +1451,63 @@ chgetparams(struct cam_periph *periph)
/* retries */ 1,
/* cbfcnp */ chdone,
/* tag_action */ MSG_SIMPLE_Q_TAG,
- /* dbd */ TRUE,
+ /* dbd */ dbd,
/* page_code */ SMS_PAGE_CTRL_CURRENT,
/* page */ CH_DEVICE_CAP_PAGE,
- /* param_buf */ (u_int8_t *)sense_data,
- /* param_len */ sizeof(*sense_data),
+ /* param_buf */ (u_int8_t *)mode_buffer,
+ /* param_len */ mode_buffer_len,
/* sense_len */ SSD_FULL_SIZE,
/* timeout */ CH_TIMEOUT_MODE_SENSE);
error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0,
- /* sense_flags */ SF_RETRY_UA,
+ /* sense_flags */ SF_RETRY_UA|SF_NO_PRINT,
&softc->device_stats);
- xpt_release_ccb(ccb);
-
if (error) {
- xpt_print_path(periph->path);
- printf("chgetparams: error getting device capabilities page\n");
- return(error);
+ if (dbd) {
+ struct scsi_mode_sense_6 *sms;
+
+ sms = (struct scsi_mode_sense_6 *)
+ ccb->csio.cdb_io.cdb_bytes;
+
+ sms->byte2 &= ~SMS_DBD;
+ error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ 0,
+ /* sense_flags */ SF_RETRY_UA,
+ &softc->device_stats);
+ } else {
+ /*
+ * Since we disabled sense printing above, print
+ * out the sense here since we got an error.
+ */
+ scsi_sense_print(&ccb->csio);
+ }
+
+ if (error) {
+ xpt_print_path(periph->path);
+ printf("chgetparams: error getting device "
+ "capabilities page\n");
+ xpt_release_ccb(ccb);
+ free(mode_buffer, M_TEMP);
+ return(error);
+ }
}
+ xpt_release_ccb(ccb);
+
+ cap = (struct page_device_capabilities *)
+ find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer);
bzero(softc->sc_movemask, sizeof(softc->sc_movemask));
bzero(softc->sc_exchangemask, sizeof(softc->sc_exchangemask));
- moves = &sense_data->pages.cap.move_from_mt;
- exchanges = &sense_data->pages.cap.exchange_with_mt;
+ moves = &cap->move_from_mt;
+ exchanges = &cap->exchange_with_mt;
for (from = CHET_MT; from <= CHET_DT; ++from) {
softc->sc_movemask[from] = moves[from];
softc->sc_exchangemask[from] = exchanges[from];
}
+ free(mode_buffer, M_TEMP);
+
return(error);
}
OpenPOWER on IntegriCloud