aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_os.c
diff options
context:
space:
mode:
authorAndrew Vasquez <andrew.vasquez@qlogic.com>2008-04-03 16:13:24 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-04-07 13:19:15 -0400
commit523ec773b8ffb1c607bc3a54c9526558e3b1eab1 (patch)
tree9cb3fc8a68af97a6359704e4341652aad9cc65d1 /drivers/scsi/qla2xxx/qla_os.c
parent3fe7cfb910ea138ae623d1320c71e2a7a0bdc527 (diff)
[SCSI] qla2xxx: Add midlayer target/device reset support.
Now that infrastructure is present within the midlayer and there is a clear distinction between what is expected from a device and target reset, convert the current device-reset codes to a target-reset, and add codes to perform a proper device-reset (LUN reset). In the process of adding reset support, collapse and consolidate large sections of mailbox-command (TMF issuance) codes, generalize the two 'wait-for-commands-to-complete' functions, and add a generic-reset routine for use by midlayer reset functions. Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_os.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c254
1 files changed, 101 insertions, 153 deletions
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index ba7d2ca3a0e8..5cddc503bd2b 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -100,6 +100,7 @@ static int qla24xx_queuecommand(struct scsi_cmnd *cmd,
100 void (*fn)(struct scsi_cmnd *)); 100 void (*fn)(struct scsi_cmnd *));
101static int qla2xxx_eh_abort(struct scsi_cmnd *); 101static int qla2xxx_eh_abort(struct scsi_cmnd *);
102static int qla2xxx_eh_device_reset(struct scsi_cmnd *); 102static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
103static int qla2xxx_eh_target_reset(struct scsi_cmnd *);
103static int qla2xxx_eh_bus_reset(struct scsi_cmnd *); 104static int qla2xxx_eh_bus_reset(struct scsi_cmnd *);
104static int qla2xxx_eh_host_reset(struct scsi_cmnd *); 105static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
105 106
@@ -113,6 +114,7 @@ static struct scsi_host_template qla2x00_driver_template = {
113 114
114 .eh_abort_handler = qla2xxx_eh_abort, 115 .eh_abort_handler = qla2xxx_eh_abort,
115 .eh_device_reset_handler = qla2xxx_eh_device_reset, 116 .eh_device_reset_handler = qla2xxx_eh_device_reset,
117 .eh_target_reset_handler = qla2xxx_eh_target_reset,
116 .eh_bus_reset_handler = qla2xxx_eh_bus_reset, 118 .eh_bus_reset_handler = qla2xxx_eh_bus_reset,
117 .eh_host_reset_handler = qla2xxx_eh_host_reset, 119 .eh_host_reset_handler = qla2xxx_eh_host_reset,
118 120
@@ -144,6 +146,7 @@ struct scsi_host_template qla24xx_driver_template = {
144 146
145 .eh_abort_handler = qla2xxx_eh_abort, 147 .eh_abort_handler = qla2xxx_eh_abort,
146 .eh_device_reset_handler = qla2xxx_eh_device_reset, 148 .eh_device_reset_handler = qla2xxx_eh_device_reset,
149 .eh_target_reset_handler = qla2xxx_eh_target_reset,
147 .eh_bus_reset_handler = qla2xxx_eh_bus_reset, 150 .eh_bus_reset_handler = qla2xxx_eh_bus_reset,
148 .eh_host_reset_handler = qla2xxx_eh_host_reset, 151 .eh_host_reset_handler = qla2xxx_eh_host_reset,
149 152
@@ -566,8 +569,6 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *ha)
566 else 569 else
567 return_status = QLA_FUNCTION_FAILED; 570 return_status = QLA_FUNCTION_FAILED;
568 571
569 DEBUG2(printk("%s return_status=%d\n",__func__,return_status));
570
571 return (return_status); 572 return (return_status);
572} 573}
573 574
@@ -714,181 +715,122 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
714 return ret; 715 return ret;
715} 716}
716 717
717/************************************************************************** 718enum nexus_wait_type {
718* qla2x00_eh_wait_for_pending_target_commands 719 WAIT_HOST = 0,
719* 720 WAIT_TARGET,
720* Description: 721 WAIT_LUN,
721* Waits for all the commands to come back from the specified target. 722};
722* 723
723* Input:
724* ha - pointer to scsi_qla_host structure.
725* t - target
726* Returns:
727* Either SUCCESS or FAILED.
728*
729* Note:
730**************************************************************************/
731static int 724static int
732qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t) 725qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha, unsigned int t,
726 unsigned int l, enum nexus_wait_type type)
733{ 727{
734 int cnt; 728 int cnt, match, status;
735 int status; 729 srb_t *sp;
736 srb_t *sp;
737 struct scsi_cmnd *cmd;
738 unsigned long flags; 730 unsigned long flags;
739 scsi_qla_host_t *pha = to_qla_parent(ha); 731 scsi_qla_host_t *pha = to_qla_parent(ha);
740 732
741 status = 0; 733 status = QLA_SUCCESS;
742 734 spin_lock_irqsave(&pha->hardware_lock, flags);
743 /* 735 for (cnt = 1; status == QLA_SUCCESS && cnt < MAX_OUTSTANDING_COMMANDS;
744 * Waiting for all commands for the designated target in the active 736 cnt++) {
745 * array
746 */
747 for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
748 spin_lock_irqsave(&pha->hardware_lock, flags);
749 sp = pha->outstanding_cmds[cnt]; 737 sp = pha->outstanding_cmds[cnt];
750 if (sp) { 738 if (!sp)
751 cmd = sp->cmd; 739 continue;
752 spin_unlock_irqrestore(&pha->hardware_lock, flags); 740 if (ha->vp_idx != sp->ha->vp_idx)
753 if (cmd->device->id == t && 741 continue;
754 ha->vp_idx == sp->ha->vp_idx) { 742 match = 0;
755 if (!qla2x00_eh_wait_on_command(ha, cmd)) { 743 switch (type) {
756 status = 1; 744 case WAIT_HOST:
757 break; 745 match = 1;
758 } 746 break;
759 } 747 case WAIT_TARGET:
760 } else { 748 match = sp->cmd->device->id == t;
761 spin_unlock_irqrestore(&pha->hardware_lock, flags); 749 break;
750 case WAIT_LUN:
751 match = (sp->cmd->device->id == t &&
752 sp->cmd->device->lun == l);
753 break;
762 } 754 }
755 if (!match)
756 continue;
757
758 spin_unlock_irqrestore(&pha->hardware_lock, flags);
759 status = qla2x00_eh_wait_on_command(ha, sp->cmd);
760 spin_lock_irqsave(&pha->hardware_lock, flags);
763 } 761 }
764 return (status); 762 spin_unlock_irqrestore(&pha->hardware_lock, flags);
763
764 return status;
765} 765}
766 766
767static char *reset_errors[] = {
768 "HBA not online",
769 "HBA not ready",
770 "Task management failed",
771 "Waiting for command completions",
772};
767 773
768/**************************************************************************
769* qla2xxx_eh_device_reset
770*
771* Description:
772* The device reset function will reset the target and abort any
773* executing commands.
774*
775* NOTE: The use of SP is undefined within this context. Do *NOT*
776* attempt to use this value, even if you determine it is
777* non-null.
778*
779* Input:
780* cmd = Linux SCSI command packet of the command that cause the
781* bus device reset.
782*
783* Returns:
784* SUCCESS/FAILURE (defined as macro in scsi.h).
785*
786**************************************************************************/
787static int 774static int
788qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) 775__qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
776 struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int))
789{ 777{
790 scsi_qla_host_t *ha = shost_priv(cmd->device->host); 778 scsi_qla_host_t *ha = shost_priv(cmd->device->host);
791 fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; 779 fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
792 int ret = FAILED; 780 int err;
793 unsigned int id, lun;
794 unsigned long serial;
795 781
796 qla2x00_block_error_handler(cmd); 782 qla2x00_block_error_handler(cmd);
797 783
798 id = cmd->device->id;
799 lun = cmd->device->lun;
800 serial = cmd->serial_number;
801
802 if (!fcport) 784 if (!fcport)
803 return ret; 785 return FAILED;
804 786
805 qla_printk(KERN_INFO, ha, 787 qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET ISSUED.\n",
806 "scsi(%ld:%d:%d): DEVICE RESET ISSUED.\n", ha->host_no, id, lun); 788 ha->host_no, cmd->device->id, cmd->device->lun, name);
807 789
790 err = 0;
808 if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) 791 if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
809 goto eh_dev_reset_done; 792 goto eh_reset_failed;
810 793 err = 1;
811 if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) { 794 if (qla2x00_wait_for_loop_ready(ha) != QLA_SUCCESS)
812 if (ha->isp_ops->abort_target(fcport) == 0) 795 goto eh_reset_failed;
813 ret = SUCCESS; 796 err = 2;
814 } else { 797 if (do_reset(fcport, cmd->device->lun) != QLA_SUCCESS)
815 DEBUG2(printk(KERN_INFO 798 goto eh_reset_failed;
816 "%s failed: loop not ready\n",__func__)); 799 err = 3;
817 } 800 if (qla2x00_eh_wait_for_pending_commands(ha, cmd->device->id,
818 801 cmd->device->lun, type) != QLA_SUCCESS)
819 if (ret == FAILED) { 802 goto eh_reset_failed;
820 DEBUG3(printk("%s(%ld): device reset failed\n", 803
821 __func__, ha->host_no)); 804 qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n",
822 qla_printk(KERN_INFO, ha, "%s: device reset failed\n", 805 ha->host_no, cmd->device->id, cmd->device->lun, name);
823 __func__); 806
807 return SUCCESS;
808
809 eh_reset_failed:
810 qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n",
811 ha->host_no, cmd->device->id, cmd->device->lun, name,
812 reset_errors[err]);
813 return FAILED;
814}
824 815
825 goto eh_dev_reset_done; 816static int
826 } 817qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
818{
819 scsi_qla_host_t *ha = shost_priv(cmd->device->host);
827 820
828 /* Flush outstanding commands. */ 821 return __qla2xxx_eh_generic_reset("DEVICE", WAIT_LUN, cmd,
829 if (qla2x00_eh_wait_for_pending_target_commands(ha, id)) 822 ha->isp_ops->lun_reset);
830 ret = FAILED;
831 if (ret == FAILED) {
832 DEBUG3(printk("%s(%ld): failed while waiting for commands\n",
833 __func__, ha->host_no));
834 qla_printk(KERN_INFO, ha,
835 "%s: failed while waiting for commands\n", __func__);
836 } else
837 qla_printk(KERN_INFO, ha,
838 "scsi(%ld:%d:%d): DEVICE RESET SUCCEEDED.\n", ha->host_no,
839 id, lun);
840 eh_dev_reset_done:
841 return ret;
842} 823}
843 824
844/**************************************************************************
845* qla2x00_eh_wait_for_pending_commands
846*
847* Description:
848* Waits for all the commands to come back from the specified host.
849*
850* Input:
851* ha - pointer to scsi_qla_host structure.
852*
853* Returns:
854* 1 : SUCCESS
855* 0 : FAILED
856*
857* Note:
858**************************************************************************/
859static int 825static int
860qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha) 826qla2xxx_eh_target_reset(struct scsi_cmnd *cmd)
861{ 827{
862 int cnt; 828 scsi_qla_host_t *ha = shost_priv(cmd->device->host);
863 int status;
864 srb_t *sp;
865 struct scsi_cmnd *cmd;
866 unsigned long flags;
867
868 status = 1;
869 829
870 /* 830 return __qla2xxx_eh_generic_reset("TARGET", WAIT_TARGET, cmd,
871 * Waiting for all commands for the designated target in the active 831 ha->isp_ops->target_reset);
872 * array
873 */
874 for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
875 spin_lock_irqsave(&ha->hardware_lock, flags);
876 sp = ha->outstanding_cmds[cnt];
877 if (sp) {
878 cmd = sp->cmd;
879 spin_unlock_irqrestore(&ha->hardware_lock, flags);
880 status = qla2x00_eh_wait_on_command(ha, cmd);
881 if (status == 0)
882 break;
883 }
884 else {
885 spin_unlock_irqrestore(&ha->hardware_lock, flags);
886 }
887 }
888 return (status);
889} 832}
890 833
891
892/************************************************************************** 834/**************************************************************************
893* qla2xxx_eh_bus_reset 835* qla2xxx_eh_bus_reset
894* 836*
@@ -939,7 +881,8 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
939 goto eh_bus_reset_done; 881 goto eh_bus_reset_done;
940 882
941 /* Flush outstanding commands. */ 883 /* Flush outstanding commands. */
942 if (!qla2x00_eh_wait_for_pending_commands(pha)) 884 if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) !=
885 QLA_SUCCESS)
943 ret = FAILED; 886 ret = FAILED;
944 887
945eh_bus_reset_done: 888eh_bus_reset_done:
@@ -1010,7 +953,8 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
1010 clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags); 953 clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
1011 954
1012 /* Waiting for our command in done_queue to be returned to OS.*/ 955 /* Waiting for our command in done_queue to be returned to OS.*/
1013 if (qla2x00_eh_wait_for_pending_commands(pha)) 956 if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) ==
957 QLA_SUCCESS)
1014 ret = SUCCESS; 958 ret = SUCCESS;
1015 959
1016 if (ha->parent) 960 if (ha->parent)
@@ -1066,7 +1010,7 @@ qla2x00_loop_reset(scsi_qla_host_t *ha)
1066 if (fcport->port_type != FCT_TARGET) 1010 if (fcport->port_type != FCT_TARGET)
1067 continue; 1011 continue;
1068 1012
1069 ret = ha->isp_ops->abort_target(fcport); 1013 ret = ha->isp_ops->target_reset(fcport, 0);
1070 if (ret != QLA_SUCCESS) { 1014 if (ret != QLA_SUCCESS) {
1071 DEBUG2_3(printk("%s(%ld): bus_reset failed: " 1015 DEBUG2_3(printk("%s(%ld): bus_reset failed: "
1072 "target_reset=%d d_id=%x.\n", __func__, 1016 "target_reset=%d d_id=%x.\n", __func__,
@@ -1258,7 +1202,8 @@ static struct isp_operations qla2100_isp_ops = {
1258 .enable_intrs = qla2x00_enable_intrs, 1202 .enable_intrs = qla2x00_enable_intrs,
1259 .disable_intrs = qla2x00_disable_intrs, 1203 .disable_intrs = qla2x00_disable_intrs,
1260 .abort_command = qla2x00_abort_command, 1204 .abort_command = qla2x00_abort_command,
1261 .abort_target = qla2x00_abort_target, 1205 .target_reset = qla2x00_abort_target,
1206 .lun_reset = qla2x00_lun_reset,
1262 .fabric_login = qla2x00_login_fabric, 1207 .fabric_login = qla2x00_login_fabric,
1263 .fabric_logout = qla2x00_fabric_logout, 1208 .fabric_logout = qla2x00_fabric_logout,
1264 .calc_req_entries = qla2x00_calc_iocbs_32, 1209 .calc_req_entries = qla2x00_calc_iocbs_32,
@@ -1291,7 +1236,8 @@ static struct isp_operations qla2300_isp_ops = {
1291 .enable_intrs = qla2x00_enable_intrs, 1236 .enable_intrs = qla2x00_enable_intrs,
1292 .disable_intrs = qla2x00_disable_intrs, 1237 .disable_intrs = qla2x00_disable_intrs,
1293 .abort_command = qla2x00_abort_command, 1238 .abort_command = qla2x00_abort_command,
1294 .abort_target = qla2x00_abort_target, 1239 .target_reset = qla2x00_abort_target,
1240 .lun_reset = qla2x00_lun_reset,
1295 .fabric_login = qla2x00_login_fabric, 1241 .fabric_login = qla2x00_login_fabric,
1296 .fabric_logout = qla2x00_fabric_logout, 1242 .fabric_logout = qla2x00_fabric_logout,
1297 .calc_req_entries = qla2x00_calc_iocbs_32, 1243 .calc_req_entries = qla2x00_calc_iocbs_32,
@@ -1324,7 +1270,8 @@ static struct isp_operations qla24xx_isp_ops = {
1324 .enable_intrs = qla24xx_enable_intrs, 1270 .enable_intrs = qla24xx_enable_intrs,
1325 .disable_intrs = qla24xx_disable_intrs, 1271 .disable_intrs = qla24xx_disable_intrs,
1326 .abort_command = qla24xx_abort_command, 1272 .abort_command = qla24xx_abort_command,
1327 .abort_target = qla24xx_abort_target, 1273 .target_reset = qla24xx_abort_target,
1274 .lun_reset = qla24xx_lun_reset,
1328 .fabric_login = qla24xx_login_fabric, 1275 .fabric_login = qla24xx_login_fabric,
1329 .fabric_logout = qla24xx_fabric_logout, 1276 .fabric_logout = qla24xx_fabric_logout,
1330 .calc_req_entries = NULL, 1277 .calc_req_entries = NULL,
@@ -1357,7 +1304,8 @@ static struct isp_operations qla25xx_isp_ops = {
1357 .enable_intrs = qla24xx_enable_intrs, 1304 .enable_intrs = qla24xx_enable_intrs,
1358 .disable_intrs = qla24xx_disable_intrs, 1305 .disable_intrs = qla24xx_disable_intrs,
1359 .abort_command = qla24xx_abort_command, 1306 .abort_command = qla24xx_abort_command,
1360 .abort_target = qla24xx_abort_target, 1307 .target_reset = qla24xx_abort_target,
1308 .lun_reset = qla24xx_lun_reset,
1361 .fabric_login = qla24xx_login_fabric, 1309 .fabric_login = qla24xx_login_fabric,
1362 .fabric_logout = qla24xx_fabric_logout, 1310 .fabric_logout = qla24xx_fabric_logout,
1363 .calc_req_entries = NULL, 1311 .calc_req_entries = NULL,