diff options
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_os.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 96 |
1 files changed, 74 insertions, 22 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 8b92f348f02c..0c786944d2c2 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; |
@@ -1548,24 +1552,19 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) | |||
1548 | goto eh_dev_reset_done; | 1552 | goto eh_dev_reset_done; |
1549 | } | 1553 | } |
1550 | 1554 | ||
1551 | /* Send marker. */ | 1555 | if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), |
1552 | ha->marker_needed = 1; | 1556 | cmd->device)) { |
1553 | 1557 | dev_info(&ha->pdev->dev, | |
1554 | /* | 1558 | "DEVICE RESET FAILED - waiting for " |
1555 | * If we are coming down the EH path, wait for all commands to complete | 1559 | "commands.\n"); |
1556 | * for the device. | 1560 | goto eh_dev_reset_done; |
1557 | */ | ||
1558 | if (cmd->device->host->shost_state == SHOST_RECOVERY) { | ||
1559 | if (qla4xxx_eh_wait_for_active_target_commands(ha, | ||
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 | } | 1561 | } |
1568 | 1562 | ||
1563 | /* Send marker. */ | ||
1564 | if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, | ||
1565 | MM_LUN_RESET) != QLA_SUCCESS) | ||
1566 | goto eh_dev_reset_done; | ||
1567 | |||
1569 | dev_info(&ha->pdev->dev, | 1568 | dev_info(&ha->pdev->dev, |
1570 | "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", | 1569 | "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", |
1571 | ha->host_no, cmd->device->channel, cmd->device->id, | 1570 | ha->host_no, cmd->device->channel, cmd->device->id, |
@@ -1579,6 +1578,59 @@ eh_dev_reset_done: | |||
1579 | } | 1578 | } |
1580 | 1579 | ||
1581 | /** | 1580 | /** |
1581 | * qla4xxx_eh_target_reset - callback for target reset. | ||
1582 | * @cmd: Pointer to Linux's SCSI command structure | ||
1583 | * | ||
1584 | * This routine is called by the Linux OS to reset the target. | ||
1585 | **/ | ||
1586 | static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) | ||
1587 | { | ||
1588 | struct scsi_qla_host *ha = to_qla_host(cmd->device->host); | ||
1589 | struct ddb_entry *ddb_entry = cmd->device->hostdata; | ||
1590 | int stat; | ||
1591 | |||
1592 | if (!ddb_entry) | ||
1593 | return FAILED; | ||
1594 | |||
1595 | starget_printk(KERN_INFO, scsi_target(cmd->device), | ||
1596 | "WARM TARGET RESET ISSUED.\n"); | ||
1597 | |||
1598 | DEBUG2(printk(KERN_INFO | ||
1599 | "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, " | ||
1600 | "to=%x,dpc_flags=%lx, status=%x allowed=%d\n", | ||
1601 | ha->host_no, cmd, jiffies, cmd->timeout_per_command / HZ, | ||
1602 | ha->dpc_flags, cmd->result, cmd->allowed)); | ||
1603 | |||
1604 | stat = qla4xxx_reset_target(ha, ddb_entry); | ||
1605 | if (stat != QLA_SUCCESS) { | ||
1606 | starget_printk(KERN_INFO, scsi_target(cmd->device), | ||
1607 | "WARM TARGET RESET FAILED.\n"); | ||
1608 | return FAILED; | ||
1609 | } | ||
1610 | |||
1611 | if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), | ||
1612 | NULL)) { | ||
1613 | starget_printk(KERN_INFO, scsi_target(cmd->device), | ||
1614 | "WARM TARGET DEVICE RESET FAILED - " | ||
1615 | "waiting for commands.\n"); | ||
1616 | return FAILED; | ||
1617 | } | ||
1618 | |||
1619 | /* Send marker. */ | ||
1620 | if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, | ||
1621 | MM_TGT_WARM_RESET) != QLA_SUCCESS) { | ||
1622 | starget_printk(KERN_INFO, scsi_target(cmd->device), | ||
1623 | "WARM TARGET DEVICE RESET FAILED - " | ||
1624 | "marker iocb failed.\n"); | ||
1625 | return FAILED; | ||
1626 | } | ||
1627 | |||
1628 | starget_printk(KERN_INFO, scsi_target(cmd->device), | ||
1629 | "WARM TARGET RESET SUCCEEDED.\n"); | ||
1630 | return SUCCESS; | ||
1631 | } | ||
1632 | |||
1633 | /** | ||
1582 | * qla4xxx_eh_host_reset - kernel callback | 1634 | * qla4xxx_eh_host_reset - kernel callback |
1583 | * @cmd: Pointer to Linux's SCSI command structure | 1635 | * @cmd: Pointer to Linux's SCSI command structure |
1584 | * | 1636 | * |