diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2008-02-29 19:25:20 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-04-07 13:15:43 -0400 |
commit | ce5450392fa3ab54f0a84aa3b7589f8d6f2a58af (patch) | |
tree | 17b051094ab95842b41d9ef3bdb5b2a1ef20370a /drivers/scsi/qla4xxx | |
parent | 30bd7df8ced23eefec87a5cda96dc99b002ed9da (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.h | 1 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_glbl.h | 2 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_mbx.c | 39 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 82 |
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); |
28 | int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, | 28 | int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, |
29 | int lun); | 29 | int lun); |
30 | int qla4xxx_reset_target(struct scsi_qla_host * ha, | ||
31 | struct ddb_entry * ddb_entry); | ||
30 | int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, | 32 | int 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); |
32 | int qla4xxx_get_firmware_status(struct scsi_qla_host * ha); | 34 | int 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 | **/ | ||
726 | int 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 | ||
717 | int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, | 756 | int 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); | |||
71 | static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, | 71 | static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, |
72 | void (*done) (struct scsi_cmnd *)); | 72 | void (*done) (struct scsi_cmnd *)); |
73 | static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); | 73 | static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); |
74 | static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); | ||
74 | static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); | 75 | static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); |
75 | static int qla4xxx_slave_alloc(struct scsi_device *device); | 76 | static int qla4xxx_slave_alloc(struct scsi_device *device); |
76 | static int qla4xxx_slave_configure(struct scsi_device *device); | 77 | static 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 | **/ |
1493 | static int qla4xxx_eh_wait_for_active_target_commands(struct scsi_qla_host *ha, | 1495 | static 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 | **/ | ||
1584 | static 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 | * |