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/ql4_os.c | |
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/ql4_os.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 82 |
1 files changed, 63 insertions, 19 deletions
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 | * |