|
@@ -96,6 +96,10 @@ static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
|
|
static void mptfc_target_destroy(struct scsi_target *starget);
|
|
static void mptfc_target_destroy(struct scsi_target *starget);
|
|
static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
|
|
static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
|
|
static void __devexit mptfc_remove(struct pci_dev *pdev);
|
|
static void __devexit mptfc_remove(struct pci_dev *pdev);
|
|
|
|
+static int mptfc_abort(struct scsi_cmnd *SCpnt);
|
|
|
|
+static int mptfc_dev_reset(struct scsi_cmnd *SCpnt);
|
|
|
|
+static int mptfc_bus_reset(struct scsi_cmnd *SCpnt);
|
|
|
|
+static int mptfc_host_reset(struct scsi_cmnd *SCpnt);
|
|
|
|
|
|
static struct scsi_host_template mptfc_driver_template = {
|
|
static struct scsi_host_template mptfc_driver_template = {
|
|
.module = THIS_MODULE,
|
|
.module = THIS_MODULE,
|
|
@@ -110,10 +114,10 @@ static struct scsi_host_template mptfc_driver_template = {
|
|
.target_destroy = mptfc_target_destroy,
|
|
.target_destroy = mptfc_target_destroy,
|
|
.slave_destroy = mptscsih_slave_destroy,
|
|
.slave_destroy = mptscsih_slave_destroy,
|
|
.change_queue_depth = mptscsih_change_queue_depth,
|
|
.change_queue_depth = mptscsih_change_queue_depth,
|
|
- .eh_abort_handler = mptscsih_abort,
|
|
|
|
- .eh_device_reset_handler = mptscsih_dev_reset,
|
|
|
|
- .eh_bus_reset_handler = mptscsih_bus_reset,
|
|
|
|
- .eh_host_reset_handler = mptscsih_host_reset,
|
|
|
|
|
|
+ .eh_abort_handler = mptfc_abort,
|
|
|
|
+ .eh_device_reset_handler = mptfc_dev_reset,
|
|
|
|
+ .eh_bus_reset_handler = mptfc_bus_reset,
|
|
|
|
+ .eh_host_reset_handler = mptfc_host_reset,
|
|
.bios_param = mptscsih_bios_param,
|
|
.bios_param = mptscsih_bios_param,
|
|
.can_queue = MPT_FC_CAN_QUEUE,
|
|
.can_queue = MPT_FC_CAN_QUEUE,
|
|
.this_id = -1,
|
|
.this_id = -1,
|
|
@@ -171,6 +175,77 @@ static struct fc_function_template mptfc_transport_functions = {
|
|
.show_host_symbolic_name = 1,
|
|
.show_host_symbolic_name = 1,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static int
|
|
|
|
+mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
|
|
|
|
+ int (*func)(struct scsi_cmnd *SCpnt),
|
|
|
|
+ const char *caller)
|
|
|
|
+{
|
|
|
|
+ struct scsi_device *sdev = SCpnt->device;
|
|
|
|
+ struct Scsi_Host *shost = sdev->host;
|
|
|
|
+ struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ int ready;
|
|
|
|
+
|
|
|
|
+ spin_lock_irqsave(shost->host_lock, flags);
|
|
|
|
+ while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
|
|
|
|
+ spin_unlock_irqrestore(shost->host_lock, flags);
|
|
|
|
+ dfcprintk ((MYIOC_s_INFO_FMT
|
|
|
|
+ "mptfc_block_error_handler.%d: %d:%d, port status is "
|
|
|
|
+ "DID_IMM_RETRY, deferring %s recovery.\n",
|
|
|
|
+ ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
|
|
|
|
+ ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
|
|
|
|
+ SCpnt->device->id,SCpnt->device->lun,caller));
|
|
|
|
+ msleep(1000);
|
|
|
|
+ spin_lock_irqsave(shost->host_lock, flags);
|
|
|
|
+ }
|
|
|
|
+ spin_unlock_irqrestore(shost->host_lock, flags);
|
|
|
|
+
|
|
|
|
+ if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
|
|
|
|
+ dfcprintk ((MYIOC_s_INFO_FMT
|
|
|
|
+ "%s.%d: %d:%d, failing recovery, "
|
|
|
|
+ "port state %d, vdev %p.\n", caller,
|
|
|
|
+ ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
|
|
|
|
+ ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
|
|
|
|
+ SCpnt->device->id,SCpnt->device->lun,ready,
|
|
|
|
+ SCpnt->device->hostdata));
|
|
|
|
+ return FAILED;
|
|
|
|
+ }
|
|
|
|
+ dfcprintk ((MYIOC_s_INFO_FMT
|
|
|
|
+ "%s.%d: %d:%d, executing recovery.\n", caller,
|
|
|
|
+ ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
|
|
|
|
+ ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
|
|
|
|
+ SCpnt->device->id,SCpnt->device->lun));
|
|
|
|
+ return (*func)(SCpnt);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+mptfc_abort(struct scsi_cmnd *SCpnt)
|
|
|
|
+{
|
|
|
|
+ return
|
|
|
|
+ mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+mptfc_dev_reset(struct scsi_cmnd *SCpnt)
|
|
|
|
+{
|
|
|
|
+ return
|
|
|
|
+ mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+mptfc_bus_reset(struct scsi_cmnd *SCpnt)
|
|
|
|
+{
|
|
|
|
+ return
|
|
|
|
+ mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+mptfc_host_reset(struct scsi_cmnd *SCpnt)
|
|
|
|
+{
|
|
|
|
+ return
|
|
|
|
+ mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__);
|
|
|
|
+}
|
|
|
|
+
|
|
static void
|
|
static void
|
|
mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
|
|
mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
|
|
{
|
|
{
|
|
@@ -562,6 +637,12 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (!SCpnt->device->hostdata) { /* vdev */
|
|
|
|
+ SCpnt->result = DID_NO_CONNECT << 16;
|
|
|
|
+ done(SCpnt);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
/* dd_data is null until finished adding target */
|
|
/* dd_data is null until finished adding target */
|
|
ri = *((struct mptfc_rport_info **)rport->dd_data);
|
|
ri = *((struct mptfc_rport_info **)rport->dd_data);
|
|
if (unlikely(!ri)) {
|
|
if (unlikely(!ri)) {
|