aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla4xxx
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2008-02-29 19:25:20 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-04-07 13:15:43 -0400
commitce5450392fa3ab54f0a84aa3b7589f8d6f2a58af (patch)
tree17b051094ab95842b41d9ef3bdb5b2a1ef20370a /drivers/scsi/qla4xxx
parent30bd7df8ced23eefec87a5cda96dc99b002ed9da (diff)
[SCSI] qla4xxx: Add target reset functionality
This patch adds target reset functionalty. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Acked-by: David Somayajulu <david.somayajulu@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/qla4xxx')
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h1
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c39
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c82
4 files changed, 105 insertions, 19 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index fe415ec85655..ed8ee66a7da5 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -216,6 +216,7 @@ union external_hw_config_reg {
216#define MBOX_CMD_ABOUT_FW 0x0009 216#define MBOX_CMD_ABOUT_FW 0x0009
217#define MBOX_CMD_PING 0x000B 217#define MBOX_CMD_PING 0x000B
218#define MBOX_CMD_LUN_RESET 0x0016 218#define MBOX_CMD_LUN_RESET 0x0016
219#define MBOX_CMD_TARGET_WARM_RESET 0x0017
219#define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E 220#define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E
220#define MBOX_CMD_GET_FW_STATUS 0x001F 221#define MBOX_CMD_GET_FW_STATUS 0x001F
221#define MBOX_CMD_SET_ISNS_SERVICE 0x0021 222#define MBOX_CMD_SET_ISNS_SERVICE 0x0021
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index a3608e028bf6..b403a17106c5 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -27,6 +27,8 @@ int qla4xxx_relogin_device(struct scsi_qla_host * ha,
27 struct ddb_entry * ddb_entry); 27 struct ddb_entry * ddb_entry);
28int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, 28int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
29 int lun); 29 int lun);
30int qla4xxx_reset_target(struct scsi_qla_host * ha,
31 struct ddb_entry * ddb_entry);
30int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, 32int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
31 uint32_t offset, uint32_t len); 33 uint32_t offset, uint32_t len);
32int qla4xxx_get_firmware_status(struct scsi_qla_host * ha); 34int qla4xxx_get_firmware_status(struct scsi_qla_host * ha);
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 35cd73c72a68..c577d79bd7e8 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -713,6 +713,45 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
713 return status; 713 return status;
714} 714}
715 715
716/**
717 * qla4xxx_reset_target - issues target Reset
718 * @ha: Pointer to host adapter structure.
719 * @db_entry: Pointer to device database entry
720 * @un_entry: Pointer to lun entry structure
721 *
722 * This routine performs a TARGET RESET on the specified target.
723 * The caller must ensure that the ddb_entry pointers
724 * are valid before calling this routine.
725 **/
726int qla4xxx_reset_target(struct scsi_qla_host *ha,
727 struct ddb_entry *ddb_entry)
728{
729 uint32_t mbox_cmd[MBOX_REG_COUNT];
730 uint32_t mbox_sts[MBOX_REG_COUNT];
731 int status = QLA_SUCCESS;
732
733 DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no,
734 ddb_entry->os_target_id));
735
736 /*
737 * Send target reset command to ISP, so that the ISP will return all
738 * outstanding requests with RESET status
739 */
740 memset(&mbox_cmd, 0, sizeof(mbox_cmd));
741 memset(&mbox_sts, 0, sizeof(mbox_sts));
742
743 mbox_cmd[0] = MBOX_CMD_TARGET_WARM_RESET;
744 mbox_cmd[1] = ddb_entry->fw_ddb_index;
745 mbox_cmd[5] = 0x01; /* Immediate Command Enable */
746
747 qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
748 &mbox_sts[0]);
749 if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE &&
750 mbox_sts[0] != MBOX_STS_COMMAND_ERROR)
751 status = QLA_ERROR;
752
753 return status;
754}
716 755
717int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, 756int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
718 uint32_t offset, uint32_t len) 757 uint32_t offset, uint32_t len)
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 8b92f348f02c..31e605caf0f1 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -71,6 +71,7 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
71static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, 71static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
72 void (*done) (struct scsi_cmnd *)); 72 void (*done) (struct scsi_cmnd *));
73static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); 73static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
74static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
74static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); 75static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
75static int qla4xxx_slave_alloc(struct scsi_device *device); 76static int qla4xxx_slave_alloc(struct scsi_device *device);
76static int qla4xxx_slave_configure(struct scsi_device *device); 77static int qla4xxx_slave_configure(struct scsi_device *device);
@@ -84,6 +85,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
84 .queuecommand = qla4xxx_queuecommand, 85 .queuecommand = qla4xxx_queuecommand,
85 86
86 .eh_device_reset_handler = qla4xxx_eh_device_reset, 87 .eh_device_reset_handler = qla4xxx_eh_device_reset,
88 .eh_target_reset_handler = qla4xxx_eh_target_reset,
87 .eh_host_reset_handler = qla4xxx_eh_host_reset, 89 .eh_host_reset_handler = qla4xxx_eh_host_reset,
88 90
89 .slave_configure = qla4xxx_slave_configure, 91 .slave_configure = qla4xxx_slave_configure,
@@ -1482,7 +1484,7 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
1482} 1484}
1483 1485
1484/** 1486/**
1485 * qla4xxx_eh_wait_for_active_target_commands - wait for active cmds to finish. 1487 * qla4xxx_eh_wait_for_commands - wait for active cmds to finish.
1486 * @ha: pointer to to HBA 1488 * @ha: pointer to to HBA
1487 * @t: target id 1489 * @t: target id
1488 * @l: lun id 1490 * @l: lun id
@@ -1490,20 +1492,22 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
1490 * This function waits for all outstanding commands to a lun to complete. It 1492 * This function waits for all outstanding commands to a lun to complete. It
1491 * returns 0 if all pending commands are returned and 1 otherwise. 1493 * returns 0 if all pending commands are returned and 1 otherwise.
1492 **/ 1494 **/
1493static int qla4xxx_eh_wait_for_active_target_commands(struct scsi_qla_host *ha, 1495static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha,
1494 int t, int l) 1496 struct scsi_target *stgt,
1497 struct scsi_device *sdev)
1495{ 1498{
1496 int cnt; 1499 int cnt;
1497 int status = 0; 1500 int status = 0;
1498 struct scsi_cmnd *cmd; 1501 struct scsi_cmnd *cmd;
1499 1502
1500 /* 1503 /*
1501 * Waiting for all commands for the designated target in the active 1504 * Waiting for all commands for the designated target or dev
1502 * array 1505 * in the active array
1503 */ 1506 */
1504 for (cnt = 0; cnt < ha->host->can_queue; cnt++) { 1507 for (cnt = 0; cnt < ha->host->can_queue; cnt++) {
1505 cmd = scsi_host_find_tag(ha->host, cnt); 1508 cmd = scsi_host_find_tag(ha->host, cnt);
1506 if (cmd && cmd->device->id == t && cmd->device->lun == l) { 1509 if (cmd && stgt == scsi_target(cmd->device) &&
1510 (!sdev || sdev == cmd->device)) {
1507 if (!qla4xxx_eh_wait_on_command(ha, cmd)) { 1511 if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
1508 status++; 1512 status++;
1509 break; 1513 break;
@@ -1551,19 +1555,12 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
1551 /* Send marker. */ 1555 /* Send marker. */
1552 ha->marker_needed = 1; 1556 ha->marker_needed = 1;
1553 1557
1554 /* 1558 if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
1555 * If we are coming down the EH path, wait for all commands to complete 1559 cmd->device)) {
1556 * for the device. 1560 dev_info(&ha->pdev->dev,
1557 */ 1561 "DEVICE RESET FAILED - waiting for "
1558 if (cmd->device->host->shost_state == SHOST_RECOVERY) { 1562 "commands.\n");
1559 if (qla4xxx_eh_wait_for_active_target_commands(ha, 1563 goto eh_dev_reset_done;
1560 cmd->device->id,
1561 cmd->device->lun)){
1562 dev_info(&ha->pdev->dev,
1563 "DEVICE RESET FAILED - waiting for "
1564 "commands.\n");
1565 goto eh_dev_reset_done;
1566 }
1567 } 1564 }
1568 1565
1569 dev_info(&ha->pdev->dev, 1566 dev_info(&ha->pdev->dev,
@@ -1579,6 +1576,53 @@ eh_dev_reset_done:
1579} 1576}
1580 1577
1581/** 1578/**
1579 * qla4xxx_eh_target_reset - callback for target reset.
1580 * @cmd: Pointer to Linux's SCSI command structure
1581 *
1582 * This routine is called by the Linux OS to reset the target.
1583 **/
1584static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
1585{
1586 struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
1587 struct ddb_entry *ddb_entry = cmd->device->hostdata;
1588 int stat;
1589
1590 if (!ddb_entry)
1591 return FAILED;
1592
1593 starget_printk(KERN_INFO, scsi_target(cmd->device),
1594 "WARM TARGET RESET ISSUED.\n");
1595
1596 DEBUG2(printk(KERN_INFO
1597 "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, "
1598 "to=%x,dpc_flags=%lx, status=%x allowed=%d\n",
1599 ha->host_no, cmd, jiffies, cmd->timeout_per_command / HZ,
1600 ha->dpc_flags, cmd->result, cmd->allowed));
1601
1602 stat = qla4xxx_reset_target(ha, ddb_entry);
1603 if (stat != QLA_SUCCESS) {
1604 starget_printk(KERN_INFO, scsi_target(cmd->device),
1605 "WARM TARGET RESET FAILED.\n");
1606 return FAILED;
1607 }
1608
1609 /* Send marker. */
1610 ha->marker_needed = 1;
1611
1612 if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
1613 NULL)) {
1614 starget_printk(KERN_INFO, scsi_target(cmd->device),
1615 "WARM TARGET DEVICE RESET FAILED - "
1616 "waiting for commands.\n");
1617 return FAILED;
1618 }
1619
1620 starget_printk(KERN_INFO, scsi_target(cmd->device),
1621 "WARM TARGET RESET SUCCEEDED.\n");
1622 return SUCCESS;
1623}
1624
1625/**
1582 * qla4xxx_eh_host_reset - kernel callback 1626 * qla4xxx_eh_host_reset - kernel callback
1583 * @cmd: Pointer to Linux's SCSI command structure 1627 * @cmd: Pointer to Linux's SCSI command structure
1584 * 1628 *