diff options
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_os.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 135 |
1 files changed, 123 insertions, 12 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 2ccad36bee9f..38b1d38afca5 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
@@ -74,6 +74,7 @@ static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); | |||
74 | */ | 74 | */ |
75 | static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, | 75 | static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, |
76 | void (*done) (struct scsi_cmnd *)); | 76 | void (*done) (struct scsi_cmnd *)); |
77 | static int qla4xxx_eh_abort(struct scsi_cmnd *cmd); | ||
77 | static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); | 78 | static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); |
78 | static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); | 79 | static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); |
79 | static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); | 80 | static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); |
@@ -88,6 +89,7 @@ static struct scsi_host_template qla4xxx_driver_template = { | |||
88 | .proc_name = DRIVER_NAME, | 89 | .proc_name = DRIVER_NAME, |
89 | .queuecommand = qla4xxx_queuecommand, | 90 | .queuecommand = qla4xxx_queuecommand, |
90 | 91 | ||
92 | .eh_abort_handler = qla4xxx_eh_abort, | ||
91 | .eh_device_reset_handler = qla4xxx_eh_device_reset, | 93 | .eh_device_reset_handler = qla4xxx_eh_device_reset, |
92 | .eh_target_reset_handler = qla4xxx_eh_target_reset, | 94 | .eh_target_reset_handler = qla4xxx_eh_target_reset, |
93 | .eh_host_reset_handler = qla4xxx_eh_host_reset, | 95 | .eh_host_reset_handler = qla4xxx_eh_host_reset, |
@@ -384,12 +386,12 @@ static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, | |||
384 | if (!srb) | 386 | if (!srb) |
385 | return srb; | 387 | return srb; |
386 | 388 | ||
387 | atomic_set(&srb->ref_count, 1); | 389 | kref_init(&srb->srb_ref); |
388 | srb->ha = ha; | 390 | srb->ha = ha; |
389 | srb->ddb = ddb_entry; | 391 | srb->ddb = ddb_entry; |
390 | srb->cmd = cmd; | 392 | srb->cmd = cmd; |
391 | srb->flags = 0; | 393 | srb->flags = 0; |
392 | cmd->SCp.ptr = (void *)srb; | 394 | CMD_SP(cmd) = (void *)srb; |
393 | cmd->scsi_done = done; | 395 | cmd->scsi_done = done; |
394 | 396 | ||
395 | return srb; | 397 | return srb; |
@@ -403,12 +405,14 @@ static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb) | |||
403 | scsi_dma_unmap(cmd); | 405 | scsi_dma_unmap(cmd); |
404 | srb->flags &= ~SRB_DMA_VALID; | 406 | srb->flags &= ~SRB_DMA_VALID; |
405 | } | 407 | } |
406 | cmd->SCp.ptr = NULL; | 408 | CMD_SP(cmd) = NULL; |
407 | } | 409 | } |
408 | 410 | ||
409 | void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb) | 411 | void qla4xxx_srb_compl(struct kref *ref) |
410 | { | 412 | { |
413 | struct srb *srb = container_of(ref, struct srb, srb_ref); | ||
411 | struct scsi_cmnd *cmd = srb->cmd; | 414 | struct scsi_cmnd *cmd = srb->cmd; |
415 | struct scsi_qla_host *ha = srb->ha; | ||
412 | 416 | ||
413 | qla4xxx_srb_free_dma(ha, srb); | 417 | qla4xxx_srb_free_dma(ha, srb); |
414 | 418 | ||
@@ -685,6 +689,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) | |||
685 | test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || | 689 | test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || |
686 | test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || | 690 | test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || |
687 | test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || | 691 | test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || |
692 | test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) || | ||
688 | test_bit(DPC_AEN, &ha->dpc_flags)) && | 693 | test_bit(DPC_AEN, &ha->dpc_flags)) && |
689 | ha->dpc_thread) { | 694 | ha->dpc_thread) { |
690 | DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" | 695 | DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" |
@@ -886,11 +891,10 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha) | |||
886 | srb = qla4xxx_del_from_active_array(ha, i); | 891 | srb = qla4xxx_del_from_active_array(ha, i); |
887 | if (srb != NULL) { | 892 | if (srb != NULL) { |
888 | srb->cmd->result = DID_RESET << 16; | 893 | srb->cmd->result = DID_RESET << 16; |
889 | qla4xxx_srb_compl(ha, srb); | 894 | kref_put(&srb->srb_ref, qla4xxx_srb_compl); |
890 | } | 895 | } |
891 | } | 896 | } |
892 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 897 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
893 | |||
894 | } | 898 | } |
895 | 899 | ||
896 | /** | 900 | /** |
@@ -1069,6 +1073,54 @@ static void qla4xxx_do_dpc(struct work_struct *work) | |||
1069 | if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) | 1073 | if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) |
1070 | qla4xxx_get_dhcp_ip_address(ha); | 1074 | qla4xxx_get_dhcp_ip_address(ha); |
1071 | 1075 | ||
1076 | /* ---- link change? --- */ | ||
1077 | if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { | ||
1078 | if (!test_bit(AF_LINK_UP, &ha->flags)) { | ||
1079 | /* ---- link down? --- */ | ||
1080 | list_for_each_entry_safe(ddb_entry, dtemp, | ||
1081 | &ha->ddb_list, list) { | ||
1082 | if (atomic_read(&ddb_entry->state) == | ||
1083 | DDB_STATE_ONLINE) | ||
1084 | qla4xxx_mark_device_missing(ha, | ||
1085 | ddb_entry); | ||
1086 | } | ||
1087 | } else { | ||
1088 | /* ---- link up? --- * | ||
1089 | * F/W will auto login to all devices ONLY ONCE after | ||
1090 | * link up during driver initialization and runtime | ||
1091 | * fatal error recovery. Therefore, the driver must | ||
1092 | * manually relogin to devices when recovering from | ||
1093 | * connection failures, logouts, expired KATO, etc. */ | ||
1094 | |||
1095 | list_for_each_entry_safe(ddb_entry, dtemp, | ||
1096 | &ha->ddb_list, list) { | ||
1097 | if ((atomic_read(&ddb_entry->state) == | ||
1098 | DDB_STATE_MISSING) || | ||
1099 | (atomic_read(&ddb_entry->state) == | ||
1100 | DDB_STATE_DEAD)) { | ||
1101 | if (ddb_entry->fw_ddb_device_state == | ||
1102 | DDB_DS_SESSION_ACTIVE) { | ||
1103 | atomic_set(&ddb_entry->state, | ||
1104 | DDB_STATE_ONLINE); | ||
1105 | dev_info(&ha->pdev->dev, | ||
1106 | "scsi%ld: %s: ddb[%d]" | ||
1107 | " os[%d] marked" | ||
1108 | " ONLINE\n", | ||
1109 | ha->host_no, __func__, | ||
1110 | ddb_entry->fw_ddb_index, | ||
1111 | ddb_entry->os_target_id); | ||
1112 | |||
1113 | iscsi_unblock_session( | ||
1114 | ddb_entry->sess); | ||
1115 | } else | ||
1116 | qla4xxx_relogin_device( | ||
1117 | ha, ddb_entry); | ||
1118 | } | ||
1119 | |||
1120 | } | ||
1121 | } | ||
1122 | } | ||
1123 | |||
1072 | /* ---- relogin device? --- */ | 1124 | /* ---- relogin device? --- */ |
1073 | if (adapter_up(ha) && | 1125 | if (adapter_up(ha) && |
1074 | test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { | 1126 | test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { |
@@ -1430,12 +1482,14 @@ static void qla4xxx_slave_destroy(struct scsi_device *sdev) | |||
1430 | struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index) | 1482 | struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index) |
1431 | { | 1483 | { |
1432 | struct srb *srb = NULL; | 1484 | struct srb *srb = NULL; |
1433 | struct scsi_cmnd *cmd; | 1485 | struct scsi_cmnd *cmd = NULL; |
1434 | 1486 | ||
1435 | if (!(cmd = scsi_host_find_tag(ha->host, index))) | 1487 | cmd = scsi_host_find_tag(ha->host, index); |
1488 | if (!cmd) | ||
1436 | return srb; | 1489 | return srb; |
1437 | 1490 | ||
1438 | if (!(srb = (struct srb *)cmd->host_scribble)) | 1491 | srb = (struct srb *)CMD_SP(cmd); |
1492 | if (!srb) | ||
1439 | return srb; | 1493 | return srb; |
1440 | 1494 | ||
1441 | /* update counters */ | 1495 | /* update counters */ |
@@ -1443,14 +1497,15 @@ struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t in | |||
1443 | ha->req_q_count += srb->iocb_cnt; | 1497 | ha->req_q_count += srb->iocb_cnt; |
1444 | ha->iocb_cnt -= srb->iocb_cnt; | 1498 | ha->iocb_cnt -= srb->iocb_cnt; |
1445 | if (srb->cmd) | 1499 | if (srb->cmd) |
1446 | srb->cmd->host_scribble = NULL; | 1500 | srb->cmd->host_scribble = |
1501 | (unsigned char *)(unsigned long) MAX_SRBS; | ||
1447 | } | 1502 | } |
1448 | return srb; | 1503 | return srb; |
1449 | } | 1504 | } |
1450 | 1505 | ||
1451 | /** | 1506 | /** |
1452 | * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware | 1507 | * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware |
1453 | * @ha: actual ha whose done queue will contain the comd returned by firmware. | 1508 | * @ha: Pointer to host adapter structure. |
1454 | * @cmd: Scsi Command to wait on. | 1509 | * @cmd: Scsi Command to wait on. |
1455 | * | 1510 | * |
1456 | * This routine waits for the command to be returned by the Firmware | 1511 | * This routine waits for the command to be returned by the Firmware |
@@ -1465,7 +1520,7 @@ static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, | |||
1465 | 1520 | ||
1466 | do { | 1521 | do { |
1467 | /* Checking to see if its returned to OS */ | 1522 | /* Checking to see if its returned to OS */ |
1468 | rp = (struct srb *) cmd->SCp.ptr; | 1523 | rp = (struct srb *) CMD_SP(cmd); |
1469 | if (rp == NULL) { | 1524 | if (rp == NULL) { |
1470 | done++; | 1525 | done++; |
1471 | break; | 1526 | break; |
@@ -1534,6 +1589,62 @@ static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha, | |||
1534 | } | 1589 | } |
1535 | 1590 | ||
1536 | /** | 1591 | /** |
1592 | * qla4xxx_eh_abort - callback for abort task. | ||
1593 | * @cmd: Pointer to Linux's SCSI command structure | ||
1594 | * | ||
1595 | * This routine is called by the Linux OS to abort the specified | ||
1596 | * command. | ||
1597 | **/ | ||
1598 | static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) | ||
1599 | { | ||
1600 | struct scsi_qla_host *ha = to_qla_host(cmd->device->host); | ||
1601 | unsigned int id = cmd->device->id; | ||
1602 | unsigned int lun = cmd->device->lun; | ||
1603 | unsigned long serial = cmd->serial_number; | ||
1604 | struct srb *srb = NULL; | ||
1605 | int ret = SUCCESS; | ||
1606 | int wait = 0; | ||
1607 | |||
1608 | dev_info(&ha->pdev->dev, | ||
1609 | "scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n", | ||
1610 | ha->host_no, id, lun, cmd, serial); | ||
1611 | |||
1612 | srb = (struct srb *) CMD_SP(cmd); | ||
1613 | |||
1614 | if (!srb) | ||
1615 | return SUCCESS; | ||
1616 | |||
1617 | kref_get(&srb->srb_ref); | ||
1618 | |||
1619 | if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) { | ||
1620 | DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n", | ||
1621 | ha->host_no, id, lun)); | ||
1622 | ret = FAILED; | ||
1623 | } else { | ||
1624 | DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n", | ||
1625 | ha->host_no, id, lun)); | ||
1626 | wait = 1; | ||
1627 | } | ||
1628 | |||
1629 | kref_put(&srb->srb_ref, qla4xxx_srb_compl); | ||
1630 | |||
1631 | /* Wait for command to complete */ | ||
1632 | if (wait) { | ||
1633 | if (!qla4xxx_eh_wait_on_command(ha, cmd)) { | ||
1634 | DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n", | ||
1635 | ha->host_no, id, lun)); | ||
1636 | ret = FAILED; | ||
1637 | } | ||
1638 | } | ||
1639 | |||
1640 | dev_info(&ha->pdev->dev, | ||
1641 | "scsi%ld:%d:%d: Abort command - %s\n", | ||
1642 | ha->host_no, id, lun, (ret == SUCCESS) ? "succeded" : "failed"); | ||
1643 | |||
1644 | return ret; | ||
1645 | } | ||
1646 | |||
1647 | /** | ||
1537 | * qla4xxx_eh_device_reset - callback for target reset. | 1648 | * qla4xxx_eh_device_reset - callback for target reset. |
1538 | * @cmd: Pointer to Linux's SCSI command structure | 1649 | * @cmd: Pointer to Linux's SCSI command structure |
1539 | * | 1650 | * |