aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla4xxx/ql4_os.c
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/ql4_os.c
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/ql4_os.c')
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c82
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);
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 *