diff options
Diffstat (limited to 'drivers/message/fusion/mptfc.c')
| -rw-r--r-- | drivers/message/fusion/mptfc.c | 89 |
1 files changed, 85 insertions, 4 deletions
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index e57bb035a021..1dd491773150 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c | |||
| @@ -96,6 +96,10 @@ static int mptfc_qcmd(struct scsi_cmnd *SCpnt, | |||
| 96 | static void mptfc_target_destroy(struct scsi_target *starget); | 96 | static void mptfc_target_destroy(struct scsi_target *starget); |
| 97 | static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout); | 97 | static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout); |
| 98 | static void __devexit mptfc_remove(struct pci_dev *pdev); | 98 | static void __devexit mptfc_remove(struct pci_dev *pdev); |
| 99 | static int mptfc_abort(struct scsi_cmnd *SCpnt); | ||
| 100 | static int mptfc_dev_reset(struct scsi_cmnd *SCpnt); | ||
| 101 | static int mptfc_bus_reset(struct scsi_cmnd *SCpnt); | ||
| 102 | static int mptfc_host_reset(struct scsi_cmnd *SCpnt); | ||
| 99 | 103 | ||
| 100 | static struct scsi_host_template mptfc_driver_template = { | 104 | static struct scsi_host_template mptfc_driver_template = { |
| 101 | .module = THIS_MODULE, | 105 | .module = THIS_MODULE, |
| @@ -110,10 +114,10 @@ static struct scsi_host_template mptfc_driver_template = { | |||
| 110 | .target_destroy = mptfc_target_destroy, | 114 | .target_destroy = mptfc_target_destroy, |
| 111 | .slave_destroy = mptscsih_slave_destroy, | 115 | .slave_destroy = mptscsih_slave_destroy, |
| 112 | .change_queue_depth = mptscsih_change_queue_depth, | 116 | .change_queue_depth = mptscsih_change_queue_depth, |
| 113 | .eh_abort_handler = mptscsih_abort, | 117 | .eh_abort_handler = mptfc_abort, |
| 114 | .eh_device_reset_handler = mptscsih_dev_reset, | 118 | .eh_device_reset_handler = mptfc_dev_reset, |
| 115 | .eh_bus_reset_handler = mptscsih_bus_reset, | 119 | .eh_bus_reset_handler = mptfc_bus_reset, |
| 116 | .eh_host_reset_handler = mptscsih_host_reset, | 120 | .eh_host_reset_handler = mptfc_host_reset, |
| 117 | .bios_param = mptscsih_bios_param, | 121 | .bios_param = mptscsih_bios_param, |
| 118 | .can_queue = MPT_FC_CAN_QUEUE, | 122 | .can_queue = MPT_FC_CAN_QUEUE, |
| 119 | .this_id = -1, | 123 | .this_id = -1, |
| @@ -171,6 +175,77 @@ static struct fc_function_template mptfc_transport_functions = { | |||
| 171 | .show_host_symbolic_name = 1, | 175 | .show_host_symbolic_name = 1, |
| 172 | }; | 176 | }; |
| 173 | 177 | ||
| 178 | static int | ||
| 179 | mptfc_block_error_handler(struct scsi_cmnd *SCpnt, | ||
| 180 | int (*func)(struct scsi_cmnd *SCpnt), | ||
| 181 | const char *caller) | ||
| 182 | { | ||
| 183 | struct scsi_device *sdev = SCpnt->device; | ||
| 184 | struct Scsi_Host *shost = sdev->host; | ||
| 185 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | ||
| 186 | unsigned long flags; | ||
| 187 | int ready; | ||
| 188 | |||
| 189 | spin_lock_irqsave(shost->host_lock, flags); | ||
| 190 | while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) { | ||
| 191 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
| 192 | dfcprintk ((MYIOC_s_INFO_FMT | ||
| 193 | "mptfc_block_error_handler.%d: %d:%d, port status is " | ||
| 194 | "DID_IMM_RETRY, deferring %s recovery.\n", | ||
| 195 | ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, | ||
| 196 | ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, | ||
| 197 | SCpnt->device->id,SCpnt->device->lun,caller)); | ||
| 198 | msleep(1000); | ||
| 199 | spin_lock_irqsave(shost->host_lock, flags); | ||
| 200 | } | ||
| 201 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
| 202 | |||
| 203 | if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) { | ||
| 204 | dfcprintk ((MYIOC_s_INFO_FMT | ||
| 205 | "%s.%d: %d:%d, failing recovery, " | ||
| 206 | "port state %d, vdev %p.\n", caller, | ||
| 207 | ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, | ||
| 208 | ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, | ||
| 209 | SCpnt->device->id,SCpnt->device->lun,ready, | ||
| 210 | SCpnt->device->hostdata)); | ||
| 211 | return FAILED; | ||
| 212 | } | ||
| 213 | dfcprintk ((MYIOC_s_INFO_FMT | ||
| 214 | "%s.%d: %d:%d, executing recovery.\n", caller, | ||
| 215 | ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, | ||
| 216 | ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, | ||
| 217 | SCpnt->device->id,SCpnt->device->lun)); | ||
| 218 | return (*func)(SCpnt); | ||
| 219 | } | ||
| 220 | |||
| 221 | static int | ||
| 222 | mptfc_abort(struct scsi_cmnd *SCpnt) | ||
| 223 | { | ||
| 224 | return | ||
| 225 | mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__); | ||
| 226 | } | ||
| 227 | |||
| 228 | static int | ||
| 229 | mptfc_dev_reset(struct scsi_cmnd *SCpnt) | ||
| 230 | { | ||
| 231 | return | ||
| 232 | mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__); | ||
| 233 | } | ||
| 234 | |||
| 235 | static int | ||
| 236 | mptfc_bus_reset(struct scsi_cmnd *SCpnt) | ||
| 237 | { | ||
| 238 | return | ||
| 239 | mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__); | ||
| 240 | } | ||
| 241 | |||
| 242 | static int | ||
| 243 | mptfc_host_reset(struct scsi_cmnd *SCpnt) | ||
| 244 | { | ||
| 245 | return | ||
| 246 | mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__); | ||
| 247 | } | ||
| 248 | |||
| 174 | static void | 249 | static void |
| 175 | mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) | 250 | mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) |
| 176 | { | 251 | { |
| @@ -562,6 +637,12 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) | |||
| 562 | return 0; | 637 | return 0; |
| 563 | } | 638 | } |
| 564 | 639 | ||
| 640 | if (!SCpnt->device->hostdata) { /* vdev */ | ||
| 641 | SCpnt->result = DID_NO_CONNECT << 16; | ||
| 642 | done(SCpnt); | ||
| 643 | return 0; | ||
| 644 | } | ||
| 645 | |||
| 565 | /* dd_data is null until finished adding target */ | 646 | /* dd_data is null until finished adding target */ |
| 566 | ri = *((struct mptfc_rport_info **)rport->dd_data); | 647 | ri = *((struct mptfc_rport_info **)rport->dd_data); |
| 567 | if (unlikely(!ri)) { | 648 | if (unlikely(!ri)) { |
