diff options
Diffstat (limited to 'drivers/scsi/scsi_transport_fc.c')
-rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 46 |
1 files changed, 40 insertions, 6 deletions
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 13ea64119b73..8db656214b5c 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <scsi/scsi_host.h> | 31 | #include <scsi/scsi_host.h> |
32 | #include <scsi/scsi_transport.h> | 32 | #include <scsi/scsi_transport.h> |
33 | #include <scsi/scsi_transport_fc.h> | 33 | #include <scsi/scsi_transport_fc.h> |
34 | #include <scsi/scsi_cmnd.h> | ||
34 | #include "scsi_priv.h" | 35 | #include "scsi_priv.h" |
35 | 36 | ||
36 | /* | 37 | /* |
@@ -1090,6 +1091,40 @@ static int fc_rport_match(struct attribute_container *cont, | |||
1090 | } | 1091 | } |
1091 | 1092 | ||
1092 | 1093 | ||
1094 | /** | ||
1095 | * fc_timed_out - FC Transport I/O timeout intercept handler | ||
1096 | * | ||
1097 | * @scmd: The SCSI command which timed out | ||
1098 | * | ||
1099 | * This routine protects against error handlers getting invoked while a | ||
1100 | * rport is in a blocked state, typically due to a temporarily loss of | ||
1101 | * connectivity. If the error handlers are allowed to proceed, requests | ||
1102 | * to abort i/o, reset the target, etc will likely fail as there is no way | ||
1103 | * to communicate with the device to perform the requested function. These | ||
1104 | * failures may result in the midlayer taking the device offline, requiring | ||
1105 | * manual intervention to restore operation. | ||
1106 | * | ||
1107 | * This routine, called whenever an i/o times out, validates the state of | ||
1108 | * the underlying rport. If the rport is blocked, it returns | ||
1109 | * EH_RESET_TIMER, which will continue to reschedule the timeout. | ||
1110 | * Eventually, either the device will return, or devloss_tmo will fire, | ||
1111 | * and when the timeout then fires, it will be handled normally. | ||
1112 | * If the rport is not blocked, normal error handling continues. | ||
1113 | * | ||
1114 | * Notes: | ||
1115 | * This routine assumes no locks are held on entry. | ||
1116 | **/ | ||
1117 | static enum scsi_eh_timer_return | ||
1118 | fc_timed_out(struct scsi_cmnd *scmd) | ||
1119 | { | ||
1120 | struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device)); | ||
1121 | |||
1122 | if (rport->port_state == FC_PORTSTATE_BLOCKED) | ||
1123 | return EH_RESET_TIMER; | ||
1124 | |||
1125 | return EH_NOT_HANDLED; | ||
1126 | } | ||
1127 | |||
1093 | /* | 1128 | /* |
1094 | * Must be called with shost->host_lock held | 1129 | * Must be called with shost->host_lock held |
1095 | */ | 1130 | */ |
@@ -1115,15 +1150,13 @@ static int fc_user_scan(struct Scsi_Host *shost, uint channel, | |||
1115 | struct scsi_transport_template * | 1150 | struct scsi_transport_template * |
1116 | fc_attach_transport(struct fc_function_template *ft) | 1151 | fc_attach_transport(struct fc_function_template *ft) |
1117 | { | 1152 | { |
1118 | struct fc_internal *i = kmalloc(sizeof(struct fc_internal), | ||
1119 | GFP_KERNEL); | ||
1120 | int count; | 1153 | int count; |
1154 | struct fc_internal *i = kzalloc(sizeof(struct fc_internal), | ||
1155 | GFP_KERNEL); | ||
1121 | 1156 | ||
1122 | if (unlikely(!i)) | 1157 | if (unlikely(!i)) |
1123 | return NULL; | 1158 | return NULL; |
1124 | 1159 | ||
1125 | memset(i, 0, sizeof(struct fc_internal)); | ||
1126 | |||
1127 | i->t.target_attrs.ac.attrs = &i->starget_attrs[0]; | 1160 | i->t.target_attrs.ac.attrs = &i->starget_attrs[0]; |
1128 | i->t.target_attrs.ac.class = &fc_transport_class.class; | 1161 | i->t.target_attrs.ac.class = &fc_transport_class.class; |
1129 | i->t.target_attrs.ac.match = fc_target_match; | 1162 | i->t.target_attrs.ac.match = fc_target_match; |
@@ -1148,6 +1181,8 @@ fc_attach_transport(struct fc_function_template *ft) | |||
1148 | /* Transport uses the shost workq for scsi scanning */ | 1181 | /* Transport uses the shost workq for scsi scanning */ |
1149 | i->t.create_work_queue = 1; | 1182 | i->t.create_work_queue = 1; |
1150 | 1183 | ||
1184 | i->t.eh_timed_out = fc_timed_out; | ||
1185 | |||
1151 | i->t.user_scan = fc_user_scan; | 1186 | i->t.user_scan = fc_user_scan; |
1152 | 1187 | ||
1153 | /* | 1188 | /* |
@@ -1305,12 +1340,11 @@ fc_rport_create(struct Scsi_Host *shost, int channel, | |||
1305 | size_t size; | 1340 | size_t size; |
1306 | 1341 | ||
1307 | size = (sizeof(struct fc_rport) + fci->f->dd_fcrport_size); | 1342 | size = (sizeof(struct fc_rport) + fci->f->dd_fcrport_size); |
1308 | rport = kmalloc(size, GFP_KERNEL); | 1343 | rport = kzalloc(size, GFP_KERNEL); |
1309 | if (unlikely(!rport)) { | 1344 | if (unlikely(!rport)) { |
1310 | printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__); | 1345 | printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__); |
1311 | return NULL; | 1346 | return NULL; |
1312 | } | 1347 | } |
1313 | memset(rport, 0, size); | ||
1314 | 1348 | ||
1315 | rport->maxframe_size = -1; | 1349 | rport->maxframe_size = -1; |
1316 | rport->supported_classes = FC_COS_UNSPECIFIED; | 1350 | rport->supported_classes = FC_COS_UNSPECIFIED; |