diff options
Diffstat (limited to 'drivers/scsi/aic7xxx/aic79xx_osm.c')
-rw-r--r-- | drivers/scsi/aic7xxx/aic79xx_osm.c | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 2567e29960bd..7254ea535a16 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c | |||
@@ -314,6 +314,21 @@ static uint32_t aic79xx_seltime; | |||
314 | */ | 314 | */ |
315 | uint32_t aic79xx_periodic_otag; | 315 | uint32_t aic79xx_periodic_otag; |
316 | 316 | ||
317 | /* Some storage boxes are using an LSI chip which has a bug making it | ||
318 | * impossible to use aic79xx Rev B chip in 320 speeds. The following | ||
319 | * storage boxes have been reported to be buggy: | ||
320 | * EonStor 3U 16-Bay: U16U-G3A3 | ||
321 | * EonStor 2U 12-Bay: U12U-G3A3 | ||
322 | * SentinelRAID: 2500F R5 / R6 | ||
323 | * SentinelRAID: 2500F R1 | ||
324 | * SentinelRAID: 2500F/1500F | ||
325 | * SentinelRAID: 150F | ||
326 | * | ||
327 | * To get around this LSI bug, you can set your board to 160 mode | ||
328 | * or you can enable the SLOWCRC bit. | ||
329 | */ | ||
330 | uint32_t aic79xx_slowcrc; | ||
331 | |||
317 | /* | 332 | /* |
318 | * Module information and settable options. | 333 | * Module information and settable options. |
319 | */ | 334 | */ |
@@ -343,6 +358,7 @@ MODULE_PARM_DESC(aic79xx, | |||
343 | " amplitude:<int> Set the signal amplitude (0-7).\n" | 358 | " amplitude:<int> Set the signal amplitude (0-7).\n" |
344 | " seltime:<int> Selection Timeout:\n" | 359 | " seltime:<int> Selection Timeout:\n" |
345 | " (0/256ms,1/128ms,2/64ms,3/32ms)\n" | 360 | " (0/256ms,1/128ms,2/64ms,3/32ms)\n" |
361 | " slowcrc Turn on the SLOWCRC bit (Rev B only)\n" | ||
346 | "\n" | 362 | "\n" |
347 | " Sample /etc/modprobe.conf line:\n" | 363 | " Sample /etc/modprobe.conf line:\n" |
348 | " Enable verbose logging\n" | 364 | " Enable verbose logging\n" |
@@ -1003,6 +1019,7 @@ aic79xx_setup(char *s) | |||
1003 | { "slewrate", NULL }, | 1019 | { "slewrate", NULL }, |
1004 | { "precomp", NULL }, | 1020 | { "precomp", NULL }, |
1005 | { "amplitude", NULL }, | 1021 | { "amplitude", NULL }, |
1022 | { "slowcrc", &aic79xx_slowcrc }, | ||
1006 | }; | 1023 | }; |
1007 | 1024 | ||
1008 | end = strchr(s, '\0'); | 1025 | end = strchr(s, '\0'); |
@@ -1072,7 +1089,6 @@ ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *templa | |||
1072 | return (ENOMEM); | 1089 | return (ENOMEM); |
1073 | 1090 | ||
1074 | *((struct ahd_softc **)host->hostdata) = ahd; | 1091 | *((struct ahd_softc **)host->hostdata) = ahd; |
1075 | ahd_lock(ahd, &s); | ||
1076 | ahd->platform_data->host = host; | 1092 | ahd->platform_data->host = host; |
1077 | host->can_queue = AHD_MAX_QUEUE; | 1093 | host->can_queue = AHD_MAX_QUEUE; |
1078 | host->cmd_per_lun = 2; | 1094 | host->cmd_per_lun = 2; |
@@ -1083,7 +1099,9 @@ ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *templa | |||
1083 | host->max_lun = AHD_NUM_LUNS; | 1099 | host->max_lun = AHD_NUM_LUNS; |
1084 | host->max_channel = 0; | 1100 | host->max_channel = 0; |
1085 | host->sg_tablesize = AHD_NSEG; | 1101 | host->sg_tablesize = AHD_NSEG; |
1102 | ahd_lock(ahd, &s); | ||
1086 | ahd_set_unit(ahd, ahd_linux_unit++); | 1103 | ahd_set_unit(ahd, ahd_linux_unit++); |
1104 | ahd_unlock(ahd, &s); | ||
1087 | sprintf(buf, "scsi%d", host->host_no); | 1105 | sprintf(buf, "scsi%d", host->host_no); |
1088 | new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); | 1106 | new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); |
1089 | if (new_name != NULL) { | 1107 | if (new_name != NULL) { |
@@ -1093,7 +1111,6 @@ ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *templa | |||
1093 | host->unique_id = ahd->unit; | 1111 | host->unique_id = ahd->unit; |
1094 | ahd_linux_initialize_scsi_bus(ahd); | 1112 | ahd_linux_initialize_scsi_bus(ahd); |
1095 | ahd_intr_enable(ahd, TRUE); | 1113 | ahd_intr_enable(ahd, TRUE); |
1096 | ahd_unlock(ahd, &s); | ||
1097 | 1114 | ||
1098 | host->transportt = ahd_linux_transport_template; | 1115 | host->transportt = ahd_linux_transport_template; |
1099 | 1116 | ||
@@ -1127,6 +1144,7 @@ ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd) | |||
1127 | { | 1144 | { |
1128 | u_int target_id; | 1145 | u_int target_id; |
1129 | u_int numtarg; | 1146 | u_int numtarg; |
1147 | unsigned long s; | ||
1130 | 1148 | ||
1131 | target_id = 0; | 1149 | target_id = 0; |
1132 | numtarg = 0; | 1150 | numtarg = 0; |
@@ -1139,6 +1157,8 @@ ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd) | |||
1139 | else | 1157 | else |
1140 | numtarg = (ahd->features & AHD_WIDE) ? 16 : 8; | 1158 | numtarg = (ahd->features & AHD_WIDE) ? 16 : 8; |
1141 | 1159 | ||
1160 | ahd_lock(ahd, &s); | ||
1161 | |||
1142 | /* | 1162 | /* |
1143 | * Force negotiation to async for all targets that | 1163 | * Force negotiation to async for all targets that |
1144 | * will not see an initial bus reset. | 1164 | * will not see an initial bus reset. |
@@ -1155,16 +1175,12 @@ ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd) | |||
1155 | ahd_update_neg_request(ahd, &devinfo, tstate, | 1175 | ahd_update_neg_request(ahd, &devinfo, tstate, |
1156 | tinfo, AHD_NEG_ALWAYS); | 1176 | tinfo, AHD_NEG_ALWAYS); |
1157 | } | 1177 | } |
1178 | ahd_unlock(ahd, &s); | ||
1158 | /* Give the bus some time to recover */ | 1179 | /* Give the bus some time to recover */ |
1159 | if ((ahd->flags & AHD_RESET_BUS_A) != 0) { | 1180 | if ((ahd->flags & AHD_RESET_BUS_A) != 0) { |
1160 | ahd_freeze_simq(ahd); | 1181 | ahd_freeze_simq(ahd); |
1161 | init_timer(&ahd->platform_data->reset_timer); | 1182 | msleep(AIC79XX_RESET_DELAY); |
1162 | ahd->platform_data->reset_timer.data = (u_long)ahd; | 1183 | ahd_release_simq(ahd); |
1163 | ahd->platform_data->reset_timer.expires = | ||
1164 | jiffies + (AIC79XX_RESET_DELAY * HZ)/1000; | ||
1165 | ahd->platform_data->reset_timer.function = | ||
1166 | (ahd_linux_callback_t *)ahd_release_simq; | ||
1167 | add_timer(&ahd->platform_data->reset_timer); | ||
1168 | } | 1184 | } |
1169 | } | 1185 | } |
1170 | 1186 | ||
@@ -2033,6 +2049,9 @@ ahd_linux_sem_timeout(u_long arg) | |||
2033 | void | 2049 | void |
2034 | ahd_freeze_simq(struct ahd_softc *ahd) | 2050 | ahd_freeze_simq(struct ahd_softc *ahd) |
2035 | { | 2051 | { |
2052 | unsigned long s; | ||
2053 | |||
2054 | ahd_lock(ahd, &s); | ||
2036 | ahd->platform_data->qfrozen++; | 2055 | ahd->platform_data->qfrozen++; |
2037 | if (ahd->platform_data->qfrozen == 1) { | 2056 | if (ahd->platform_data->qfrozen == 1) { |
2038 | scsi_block_requests(ahd->platform_data->host); | 2057 | scsi_block_requests(ahd->platform_data->host); |
@@ -2040,6 +2059,7 @@ ahd_freeze_simq(struct ahd_softc *ahd) | |||
2040 | CAM_LUN_WILDCARD, SCB_LIST_NULL, | 2059 | CAM_LUN_WILDCARD, SCB_LIST_NULL, |
2041 | ROLE_INITIATOR, CAM_REQUEUE_REQ); | 2060 | ROLE_INITIATOR, CAM_REQUEUE_REQ); |
2042 | } | 2061 | } |
2062 | ahd_unlock(ahd, &s); | ||
2043 | } | 2063 | } |
2044 | 2064 | ||
2045 | void | 2065 | void |
@@ -2344,8 +2364,9 @@ done: | |||
2344 | ahd_name(ahd), dev->active); | 2364 | ahd_name(ahd), dev->active); |
2345 | retval = FAILED; | 2365 | retval = FAILED; |
2346 | } | 2366 | } |
2347 | } | 2367 | } else |
2348 | ahd_unlock(ahd, &flags); | 2368 | ahd_unlock(ahd, &flags); |
2369 | |||
2349 | return (retval); | 2370 | return (retval); |
2350 | } | 2371 | } |
2351 | 2372 | ||