summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJustin T. Gibbs <gibbs@overdrive.btc.adaptec.com>2002-12-30 04:57:48 -0700
committerJustin T. Gibbs <gibbs@overdrive.btc.adaptec.com>2002-12-30 04:57:48 -0700
commit079d056fe7d8a81bc9cb94dc4e704bda7d5b40a4 (patch)
treecb23ff17e12d8aee94a3026a202e2341d3d6d4a3 /drivers
parente409b3d04874b0cad2a6aa1e305050f49cb6a9e6 (diff)
Add a failsafe mechanism to configure devices that have inquiry data
but somehow are not handled by the DV state machine. This ensures that the behavior seen before DV is restored in the event of a DV state machine failure.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c46
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h9
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c46
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h9
4 files changed, 82 insertions, 28 deletions
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 636de9ab9c32..02a7612a7efd 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -1,7 +1,7 @@
/*
* Adaptec AIC79xx device driver for Linux.
*
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#102 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#103 $
*
* --------------------------------------------------------------------------
* Copyright (c) 1994-2000 Justin T. Gibbs.
@@ -2640,6 +2640,7 @@ ahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset)
AHD_TRANS_GOAL, /*paused*/FALSE);
ahd_unlock(ahd, &s);
timeout = 10 * HZ;
+ targ->flags &= ~AHD_INQ_VALID;
/* FALLTHROUGH */
case AHD_DV_STATE_INQ_VERIFY:
{
@@ -2721,6 +2722,25 @@ ahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset)
}
out:
+ if ((targ->flags & AHD_INQ_VALID) != 0
+ && ahd_linux_get_device(ahd, devinfo.channel - 'A',
+ devinfo.target, devinfo.lun,
+ /*alloc*/FALSE) == NULL) {
+ /*
+ * The DV state machine failed to configure this device.
+ * This is normal if DV is disabled. Since we have inquiry
+ * data, filter it and use the "optimistic" negotiation
+ * parameters found in the inquiry string.
+ */
+ ahd_linux_filter_inquiry(ahd, &devinfo);
+ if ((targ->flags & (AHD_BASIC_DV|AHD_ENHANCED_DV)) != 0) {
+ ahd_print_devinfo(ahd, &devinfo);
+ printf("DV failed to configure device. "
+ "Please file a bug report against "
+ "this driver.\n");
+ }
+ }
+
if (cmd != NULL)
free(cmd, M_DEVBUF);
@@ -2806,24 +2826,21 @@ ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
break;
}
- if (ahd_linux_user_dv_setting(ahd) == 0) {
- ahd_linux_filter_inquiry(ahd, devinfo);
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+ AHD_SET_DV_STATE(ahd, targ, targ->dv_state+1);
+ targ->flags |= AHD_INQ_VALID;
+ if (ahd_linux_user_dv_setting(ahd) == 0)
break;
- }
spi3data = targ->inq_data->spi3data;
switch (spi3data & SID_SPI_CLOCK_DT_ST) {
default:
case SID_SPI_CLOCK_ST:
/* Assume only basic DV is supported. */
- ahd_linux_filter_inquiry(ahd, devinfo);
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_INQ_VERIFY);
+ targ->flags |= AHD_BASIC_DV;
break;
case SID_SPI_CLOCK_DT:
case SID_SPI_CLOCK_DT_ST:
- AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REBD);
+ targ->flags |= AHD_ENHANCED_DV;
break;
}
break;
@@ -2919,8 +2936,15 @@ ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
case AHD_DV_STATE_TUR:
switch (status & SS_MASK) {
case SS_NOP:
- AHD_SET_DV_STATE(ahd, targ,
- AHD_DV_STATE_INQ_ASYNC);
+ if ((targ->flags & AHD_BASIC_DV) != 0) {
+ ahd_linux_filter_inquiry(ahd, devinfo);
+ AHD_SET_DV_STATE(ahd, targ,
+ AHD_DV_STATE_INQ_VERIFY);
+ } else if ((targ->flags & AHD_ENHANCED_DV) != 0) {
+ AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REBD);
+ } else {
+ AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+ }
break;
case SS_RETRY:
case SS_TUR:
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 2aed30d80a24..5b632e68dd38 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -36,7 +36,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#97 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#98 $
*
*/
#ifndef _AIC79XX_LINUX_H_
@@ -425,16 +425,19 @@ struct ahd_linux_device {
};
typedef enum {
- AHD_DV_REQUIRED = 0x01
+ AHD_DV_REQUIRED = 0x01,
+ AHD_INQ_VALID = 0x02,
+ AHD_BASIC_DV = 0x04,
+ AHD_ENHANCED_DV = 0x08
} ahd_linux_targ_flags;
/* DV States */
typedef enum {
AHD_DV_STATE_EXIT = 0,
AHD_DV_STATE_INQ_SHORT_ASYNC,
- AHD_DV_STATE_TUR,
AHD_DV_STATE_INQ_ASYNC,
AHD_DV_STATE_INQ_ASYNC_VERIFY,
+ AHD_DV_STATE_TUR,
AHD_DV_STATE_REBD,
AHD_DV_STATE_INQ_VERIFY,
AHD_DV_STATE_WEB,
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 11a830ea8cc6..bc59c7c76123 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -1,7 +1,7 @@
/*
* Adaptec AIC7xxx device driver for Linux.
*
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#165 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#166 $
*
* Copyright (c) 1994 John Aycock
* The University of Calgary Department of Computer Science.
@@ -2492,6 +2492,7 @@ ahc_linux_dv_target(struct ahc_softc *ahc, u_int target_offset)
AHC_TRANS_GOAL, /*paused*/FALSE);
ahc_unlock(ahc, &s);
timeout = 10 * HZ;
+ targ->flags &= ~AHC_INQ_VALID;
/* FALLTHROUGH */
case AHC_DV_STATE_INQ_VERIFY:
{
@@ -2573,6 +2574,25 @@ ahc_linux_dv_target(struct ahc_softc *ahc, u_int target_offset)
}
out:
+ if ((targ->flags & AHC_INQ_VALID) != 0
+ && ahc_linux_get_device(ahc, devinfo.channel - 'A',
+ devinfo.target, devinfo.lun,
+ /*alloc*/FALSE) == NULL) {
+ /*
+ * The DV state machine failed to configure this device.
+ * This is normal if DV is disabled. Since we have inquiry
+ * data, filter it and use the "optimistic" negotiation
+ * parameters found in the inquiry string.
+ */
+ ahc_linux_filter_inquiry(ahc, &devinfo);
+ if ((targ->flags & (AHC_BASIC_DV|AHC_ENHANCED_DV)) != 0) {
+ ahc_print_devinfo(ahc, &devinfo);
+ printf("DV failed to configure device. "
+ "Please file a bug report against "
+ "this driver.\n");
+ }
+ }
+
if (cmd != NULL)
free(cmd, M_DEVBUF);
@@ -2658,24 +2678,21 @@ ahc_linux_dv_transition(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
break;
}
- if (ahc_linux_user_dv_setting(ahc) == 0) {
- ahc_linux_filter_inquiry(ahc, devinfo);
- AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+ AHC_SET_DV_STATE(ahc, targ, targ->dv_state+1);
+ targ->flags |= AHC_INQ_VALID;
+ if (ahc_linux_user_dv_setting(ahc) == 0)
break;
- }
spi3data = targ->inq_data->spi3data;
switch (spi3data & SID_SPI_CLOCK_DT_ST) {
default:
case SID_SPI_CLOCK_ST:
/* Assume only basic DV is supported. */
- ahc_linux_filter_inquiry(ahc, devinfo);
- AHC_SET_DV_STATE(ahc, targ,
- AHC_DV_STATE_INQ_VERIFY);
+ targ->flags |= AHC_BASIC_DV;
break;
case SID_SPI_CLOCK_DT:
case SID_SPI_CLOCK_DT_ST:
- AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_REBD);
+ targ->flags |= AHC_ENHANCED_DV;
break;
}
break;
@@ -2771,8 +2788,15 @@ ahc_linux_dv_transition(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
case AHC_DV_STATE_TUR:
switch (status & SS_MASK) {
case SS_NOP:
- AHC_SET_DV_STATE(ahc, targ,
- AHC_DV_STATE_INQ_ASYNC);
+ if ((targ->flags & AHC_BASIC_DV) != 0) {
+ ahc_linux_filter_inquiry(ahc, devinfo);
+ AHC_SET_DV_STATE(ahc, targ,
+ AHC_DV_STATE_INQ_VERIFY);
+ } else if ((targ->flags & AHC_ENHANCED_DV) != 0) {
+ AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_REBD);
+ } else {
+ AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+ }
break;
case SS_RETRY:
case SS_TUR:
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index 7c549176292d..5edbdda8bfee 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -53,7 +53,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#112 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#113 $
*
*/
#ifndef _AIC7XXX_LINUX_H_
@@ -438,16 +438,19 @@ struct ahc_linux_device {
};
typedef enum {
- AHC_DV_REQUIRED = 0x01
+ AHC_DV_REQUIRED = 0x01,
+ AHC_INQ_VALID = 0x02,
+ AHC_BASIC_DV = 0x04,
+ AHC_ENHANCED_DV = 0x08
} ahc_linux_targ_flags;
/* DV States */
typedef enum {
AHC_DV_STATE_EXIT = 0,
AHC_DV_STATE_INQ_SHORT_ASYNC,
- AHC_DV_STATE_TUR,
AHC_DV_STATE_INQ_ASYNC,
AHC_DV_STATE_INQ_ASYNC_VERIFY,
+ AHC_DV_STATE_TUR,
AHC_DV_STATE_REBD,
AHC_DV_STATE_INQ_VERIFY,
AHC_DV_STATE_WEB,