diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_bsg.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_bsg.c | 376 |
1 files changed, 333 insertions, 43 deletions
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index c68883806c54..2f9bddd3c616 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * QLogic Fibre Channel HBA Driver | 2 | * QLogic Fibre Channel HBA Driver |
3 | * Copyright (c) 2003-2011 QLogic Corporation | 3 | * Copyright (c) 2003-2012 QLogic Corporation |
4 | * | 4 | * |
5 | * See LICENSE.qla2xxx for copyright and licensing details. | 5 | * See LICENSE.qla2xxx for copyright and licensing details. |
6 | */ | 6 | */ |
@@ -530,13 +530,13 @@ done_unmap_sg: | |||
530 | done: | 530 | done: |
531 | return rval; | 531 | return rval; |
532 | } | 532 | } |
533 | 533 | /* | |
534 | /* Set the port configuration to enable the | 534 | * Set the port configuration to enable the internal or external loopback |
535 | * internal loopback on ISP81XX | 535 | * depending on the loopback mode. |
536 | */ | 536 | */ |
537 | static inline int | 537 | static inline int |
538 | qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config, | 538 | qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config, |
539 | uint16_t *new_config) | 539 | uint16_t *new_config, uint16_t mode) |
540 | { | 540 | { |
541 | int ret = 0; | 541 | int ret = 0; |
542 | int rval = 0; | 542 | int rval = 0; |
@@ -545,8 +545,14 @@ qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config, | |||
545 | if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) | 545 | if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) |
546 | goto done_set_internal; | 546 | goto done_set_internal; |
547 | 547 | ||
548 | new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1); | 548 | if (mode == INTERNAL_LOOPBACK) |
549 | memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ; | 549 | new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1); |
550 | else if (mode == EXTERNAL_LOOPBACK) | ||
551 | new_config[0] = config[0] | (ENABLE_EXTERNAL_LOOPBACK << 1); | ||
552 | ql_dbg(ql_dbg_user, vha, 0x70be, | ||
553 | "new_config[0]=%02x\n", (new_config[0] & INTERNAL_LOOPBACK_MASK)); | ||
554 | |||
555 | memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3); | ||
550 | 556 | ||
551 | ha->notify_dcbx_comp = 1; | 557 | ha->notify_dcbx_comp = 1; |
552 | ret = qla81xx_set_port_config(vha, new_config); | 558 | ret = qla81xx_set_port_config(vha, new_config); |
@@ -562,9 +568,17 @@ qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config, | |||
562 | if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) { | 568 | if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) { |
563 | ql_dbg(ql_dbg_user, vha, 0x7022, | 569 | ql_dbg(ql_dbg_user, vha, 0x7022, |
564 | "State change notification not received.\n"); | 570 | "State change notification not received.\n"); |
565 | } else | 571 | rval = -EINVAL; |
566 | ql_dbg(ql_dbg_user, vha, 0x7023, | 572 | } else { |
567 | "State change received.\n"); | 573 | if (ha->flags.idc_compl_status) { |
574 | ql_dbg(ql_dbg_user, vha, 0x70c3, | ||
575 | "Bad status in IDC Completion AEN\n"); | ||
576 | rval = -EINVAL; | ||
577 | ha->flags.idc_compl_status = 0; | ||
578 | } else | ||
579 | ql_dbg(ql_dbg_user, vha, 0x7023, | ||
580 | "State change received.\n"); | ||
581 | } | ||
568 | 582 | ||
569 | ha->notify_dcbx_comp = 0; | 583 | ha->notify_dcbx_comp = 0; |
570 | 584 | ||
@@ -572,11 +586,9 @@ done_set_internal: | |||
572 | return rval; | 586 | return rval; |
573 | } | 587 | } |
574 | 588 | ||
575 | /* Set the port configuration to disable the | 589 | /* Disable loopback mode */ |
576 | * internal loopback on ISP81XX | ||
577 | */ | ||
578 | static inline int | 590 | static inline int |
579 | qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config, | 591 | qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config, |
580 | int wait) | 592 | int wait) |
581 | { | 593 | { |
582 | int ret = 0; | 594 | int ret = 0; |
@@ -589,8 +601,12 @@ qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config, | |||
589 | 601 | ||
590 | memset(new_config, 0 , sizeof(new_config)); | 602 | memset(new_config, 0 , sizeof(new_config)); |
591 | if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 == | 603 | if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 == |
592 | ENABLE_INTERNAL_LOOPBACK) { | 604 | ENABLE_INTERNAL_LOOPBACK || |
605 | (config[0] & INTERNAL_LOOPBACK_MASK) >> 1 == | ||
606 | ENABLE_EXTERNAL_LOOPBACK) { | ||
593 | new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK; | 607 | new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK; |
608 | ql_dbg(ql_dbg_user, vha, 0x70bf, "new_config[0]=%02x\n", | ||
609 | (new_config[0] & INTERNAL_LOOPBACK_MASK)); | ||
594 | memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ; | 610 | memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ; |
595 | 611 | ||
596 | ha->notify_dcbx_comp = wait; | 612 | ha->notify_dcbx_comp = wait; |
@@ -707,7 +723,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job) | |||
707 | 723 | ||
708 | elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; | 724 | elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; |
709 | 725 | ||
710 | if ((ha->current_topology == ISP_CFG_F || | 726 | if (atomic_read(&vha->loop_state) == LOOP_READY && |
727 | (ha->current_topology == ISP_CFG_F || | ||
711 | ((IS_QLA81XX(ha) || IS_QLA8031(ha)) && | 728 | ((IS_QLA81XX(ha) || IS_QLA8031(ha)) && |
712 | le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE | 729 | le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE |
713 | && req_data_len == MAX_ELS_FRAME_PAYLOAD)) && | 730 | && req_data_len == MAX_ELS_FRAME_PAYLOAD)) && |
@@ -729,30 +746,24 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job) | |||
729 | goto done_free_dma_req; | 746 | goto done_free_dma_req; |
730 | } | 747 | } |
731 | 748 | ||
732 | if (elreq.options != EXTERNAL_LOOPBACK) { | 749 | ql_dbg(ql_dbg_user, vha, 0x70c0, |
733 | ql_dbg(ql_dbg_user, vha, 0x7020, | 750 | "elreq.options=%04x\n", elreq.options); |
734 | "Internal: current port config = %x\n", | 751 | |
735 | config[0]); | 752 | if (elreq.options == EXTERNAL_LOOPBACK) |
736 | if (qla81xx_set_internal_loopback(vha, config, | 753 | if (IS_QLA8031(ha)) |
737 | new_config)) { | 754 | rval = qla81xx_set_loopback_mode(vha, |
738 | ql_log(ql_log_warn, vha, 0x7024, | 755 | config, new_config, elreq.options); |
739 | "Internal loopback failed.\n"); | 756 | else |
740 | bsg_job->reply->result = | 757 | rval = qla81xx_reset_loopback_mode(vha, |
741 | (DID_ERROR << 16); | 758 | config, 1); |
742 | rval = -EPERM; | 759 | else |
743 | goto done_free_dma_req; | 760 | rval = qla81xx_set_loopback_mode(vha, config, |
744 | } | 761 | new_config, elreq.options); |
745 | } else { | 762 | |
746 | /* For external loopback to work | 763 | if (rval) { |
747 | * ensure internal loopback is disabled | 764 | bsg_job->reply->result = (DID_ERROR << 16); |
748 | */ | 765 | rval = -EPERM; |
749 | if (qla81xx_reset_internal_loopback(vha, | 766 | goto done_free_dma_req; |
750 | config, 1)) { | ||
751 | bsg_job->reply->result = | ||
752 | (DID_ERROR << 16); | ||
753 | rval = -EPERM; | ||
754 | goto done_free_dma_req; | ||
755 | } | ||
756 | } | 767 | } |
757 | 768 | ||
758 | type = "FC_BSG_HST_VENDOR_LOOPBACK"; | 769 | type = "FC_BSG_HST_VENDOR_LOOPBACK"; |
@@ -766,7 +777,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job) | |||
766 | /* Revert back to original port config | 777 | /* Revert back to original port config |
767 | * Also clear internal loopback | 778 | * Also clear internal loopback |
768 | */ | 779 | */ |
769 | qla81xx_reset_internal_loopback(vha, | 780 | qla81xx_reset_loopback_mode(vha, |
770 | new_config, 0); | 781 | new_config, 0); |
771 | } | 782 | } |
772 | 783 | ||
@@ -1364,7 +1375,7 @@ qla2x00_read_optrom(struct fc_bsg_job *bsg_job) | |||
1364 | struct qla_hw_data *ha = vha->hw; | 1375 | struct qla_hw_data *ha = vha->hw; |
1365 | int rval = 0; | 1376 | int rval = 0; |
1366 | 1377 | ||
1367 | if (ha->flags.isp82xx_reset_hdlr_active) | 1378 | if (ha->flags.nic_core_reset_hdlr_active) |
1368 | return -EBUSY; | 1379 | return -EBUSY; |
1369 | 1380 | ||
1370 | rval = qla2x00_optrom_setup(bsg_job, vha, 0); | 1381 | rval = qla2x00_optrom_setup(bsg_job, vha, 0); |
@@ -1560,6 +1571,276 @@ done: | |||
1560 | } | 1571 | } |
1561 | 1572 | ||
1562 | static int | 1573 | static int |
1574 | qla2x00_write_i2c(struct fc_bsg_job *bsg_job) | ||
1575 | { | ||
1576 | struct Scsi_Host *host = bsg_job->shost; | ||
1577 | scsi_qla_host_t *vha = shost_priv(host); | ||
1578 | struct qla_hw_data *ha = vha->hw; | ||
1579 | int rval = 0; | ||
1580 | uint8_t bsg[DMA_POOL_SIZE]; | ||
1581 | struct qla_i2c_access *i2c = (void *)bsg; | ||
1582 | dma_addr_t sfp_dma; | ||
1583 | uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); | ||
1584 | if (!sfp) { | ||
1585 | bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = | ||
1586 | EXT_STATUS_NO_MEMORY; | ||
1587 | goto done; | ||
1588 | } | ||
1589 | |||
1590 | sg_copy_to_buffer(bsg_job->request_payload.sg_list, | ||
1591 | bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c)); | ||
1592 | |||
1593 | memcpy(sfp, i2c->buffer, i2c->length); | ||
1594 | rval = qla2x00_write_sfp(vha, sfp_dma, sfp, | ||
1595 | i2c->device, i2c->offset, i2c->length, i2c->option); | ||
1596 | |||
1597 | if (rval) { | ||
1598 | bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = | ||
1599 | EXT_STATUS_MAILBOX; | ||
1600 | goto dealloc; | ||
1601 | } | ||
1602 | |||
1603 | bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = 0; | ||
1604 | |||
1605 | dealloc: | ||
1606 | dma_pool_free(ha->s_dma_pool, sfp, sfp_dma); | ||
1607 | |||
1608 | done: | ||
1609 | bsg_job->reply_len = sizeof(struct fc_bsg_reply); | ||
1610 | bsg_job->reply->result = DID_OK << 16; | ||
1611 | bsg_job->job_done(bsg_job); | ||
1612 | |||
1613 | return 0; | ||
1614 | } | ||
1615 | |||
1616 | static int | ||
1617 | qla2x00_read_i2c(struct fc_bsg_job *bsg_job) | ||
1618 | { | ||
1619 | struct Scsi_Host *host = bsg_job->shost; | ||
1620 | scsi_qla_host_t *vha = shost_priv(host); | ||
1621 | struct qla_hw_data *ha = vha->hw; | ||
1622 | int rval = 0; | ||
1623 | uint8_t bsg[DMA_POOL_SIZE]; | ||
1624 | struct qla_i2c_access *i2c = (void *)bsg; | ||
1625 | dma_addr_t sfp_dma; | ||
1626 | uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); | ||
1627 | if (!sfp) { | ||
1628 | bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = | ||
1629 | EXT_STATUS_NO_MEMORY; | ||
1630 | goto done; | ||
1631 | } | ||
1632 | |||
1633 | sg_copy_to_buffer(bsg_job->request_payload.sg_list, | ||
1634 | bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c)); | ||
1635 | |||
1636 | rval = qla2x00_read_sfp(vha, sfp_dma, sfp, | ||
1637 | i2c->device, i2c->offset, i2c->length, i2c->option); | ||
1638 | |||
1639 | if (rval) { | ||
1640 | bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = | ||
1641 | EXT_STATUS_MAILBOX; | ||
1642 | goto dealloc; | ||
1643 | } | ||
1644 | |||
1645 | memcpy(i2c->buffer, sfp, i2c->length); | ||
1646 | sg_copy_from_buffer(bsg_job->reply_payload.sg_list, | ||
1647 | bsg_job->reply_payload.sg_cnt, i2c, sizeof(*i2c)); | ||
1648 | |||
1649 | bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = 0; | ||
1650 | |||
1651 | dealloc: | ||
1652 | dma_pool_free(ha->s_dma_pool, sfp, sfp_dma); | ||
1653 | |||
1654 | done: | ||
1655 | bsg_job->reply_len = sizeof(struct fc_bsg_reply); | ||
1656 | bsg_job->reply->reply_payload_rcv_len = sizeof(*i2c); | ||
1657 | bsg_job->reply->result = DID_OK << 16; | ||
1658 | bsg_job->job_done(bsg_job); | ||
1659 | |||
1660 | return 0; | ||
1661 | } | ||
1662 | |||
1663 | static int | ||
1664 | qla24xx_process_bidir_cmd(struct fc_bsg_job *bsg_job) | ||
1665 | { | ||
1666 | struct Scsi_Host *host = bsg_job->shost; | ||
1667 | scsi_qla_host_t *vha = shost_priv(host); | ||
1668 | struct qla_hw_data *ha = vha->hw; | ||
1669 | uint16_t thread_id; | ||
1670 | uint32_t rval = EXT_STATUS_OK; | ||
1671 | uint16_t req_sg_cnt = 0; | ||
1672 | uint16_t rsp_sg_cnt = 0; | ||
1673 | uint16_t nextlid = 0; | ||
1674 | uint32_t tot_dsds; | ||
1675 | srb_t *sp = NULL; | ||
1676 | uint32_t req_data_len = 0; | ||
1677 | uint32_t rsp_data_len = 0; | ||
1678 | |||
1679 | /* Check the type of the adapter */ | ||
1680 | if (!IS_BIDI_CAPABLE(ha)) { | ||
1681 | ql_log(ql_log_warn, vha, 0x70a0, | ||
1682 | "This adapter is not supported\n"); | ||
1683 | rval = EXT_STATUS_NOT_SUPPORTED; | ||
1684 | goto done; | ||
1685 | } | ||
1686 | |||
1687 | if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || | ||
1688 | test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || | ||
1689 | test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { | ||
1690 | rval = EXT_STATUS_BUSY; | ||
1691 | goto done; | ||
1692 | } | ||
1693 | |||
1694 | /* Check if host is online */ | ||
1695 | if (!vha->flags.online) { | ||
1696 | ql_log(ql_log_warn, vha, 0x70a1, | ||
1697 | "Host is not online\n"); | ||
1698 | rval = EXT_STATUS_DEVICE_OFFLINE; | ||
1699 | goto done; | ||
1700 | } | ||
1701 | |||
1702 | /* Check if cable is plugged in or not */ | ||
1703 | if (vha->device_flags & DFLG_NO_CABLE) { | ||
1704 | ql_log(ql_log_warn, vha, 0x70a2, | ||
1705 | "Cable is unplugged...\n"); | ||
1706 | rval = EXT_STATUS_INVALID_CFG; | ||
1707 | goto done; | ||
1708 | } | ||
1709 | |||
1710 | /* Check if the switch is connected or not */ | ||
1711 | if (ha->current_topology != ISP_CFG_F) { | ||
1712 | ql_log(ql_log_warn, vha, 0x70a3, | ||
1713 | "Host is not connected to the switch\n"); | ||
1714 | rval = EXT_STATUS_INVALID_CFG; | ||
1715 | goto done; | ||
1716 | } | ||
1717 | |||
1718 | /* Check if operating mode is P2P */ | ||
1719 | if (ha->operating_mode != P2P) { | ||
1720 | ql_log(ql_log_warn, vha, 0x70a4, | ||
1721 | "Host is operating mode is not P2p\n"); | ||
1722 | rval = EXT_STATUS_INVALID_CFG; | ||
1723 | goto done; | ||
1724 | } | ||
1725 | |||
1726 | thread_id = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; | ||
1727 | |||
1728 | mutex_lock(&ha->selflogin_lock); | ||
1729 | if (vha->self_login_loop_id == 0) { | ||
1730 | /* Initialize all required fields of fcport */ | ||
1731 | vha->bidir_fcport.vha = vha; | ||
1732 | vha->bidir_fcport.d_id.b.al_pa = vha->d_id.b.al_pa; | ||
1733 | vha->bidir_fcport.d_id.b.area = vha->d_id.b.area; | ||
1734 | vha->bidir_fcport.d_id.b.domain = vha->d_id.b.domain; | ||
1735 | vha->bidir_fcport.loop_id = vha->loop_id; | ||
1736 | |||
1737 | if (qla2x00_fabric_login(vha, &(vha->bidir_fcport), &nextlid)) { | ||
1738 | ql_log(ql_log_warn, vha, 0x70a7, | ||
1739 | "Failed to login port %06X for bidirectional IOCB\n", | ||
1740 | vha->bidir_fcport.d_id.b24); | ||
1741 | mutex_unlock(&ha->selflogin_lock); | ||
1742 | rval = EXT_STATUS_MAILBOX; | ||
1743 | goto done; | ||
1744 | } | ||
1745 | vha->self_login_loop_id = nextlid - 1; | ||
1746 | |||
1747 | } | ||
1748 | /* Assign the self login loop id to fcport */ | ||
1749 | mutex_unlock(&ha->selflogin_lock); | ||
1750 | |||
1751 | vha->bidir_fcport.loop_id = vha->self_login_loop_id; | ||
1752 | |||
1753 | req_sg_cnt = dma_map_sg(&ha->pdev->dev, | ||
1754 | bsg_job->request_payload.sg_list, | ||
1755 | bsg_job->request_payload.sg_cnt, | ||
1756 | DMA_TO_DEVICE); | ||
1757 | |||
1758 | if (!req_sg_cnt) { | ||
1759 | rval = EXT_STATUS_NO_MEMORY; | ||
1760 | goto done; | ||
1761 | } | ||
1762 | |||
1763 | rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, | ||
1764 | bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt, | ||
1765 | DMA_FROM_DEVICE); | ||
1766 | |||
1767 | if (!rsp_sg_cnt) { | ||
1768 | rval = EXT_STATUS_NO_MEMORY; | ||
1769 | goto done_unmap_req_sg; | ||
1770 | } | ||
1771 | |||
1772 | if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || | ||
1773 | (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) { | ||
1774 | ql_dbg(ql_dbg_user, vha, 0x70a9, | ||
1775 | "Dma mapping resulted in different sg counts " | ||
1776 | "[request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt: " | ||
1777 | "%x dma_reply_sg_cnt: %x]\n", | ||
1778 | bsg_job->request_payload.sg_cnt, req_sg_cnt, | ||
1779 | bsg_job->reply_payload.sg_cnt, rsp_sg_cnt); | ||
1780 | rval = EXT_STATUS_NO_MEMORY; | ||
1781 | goto done_unmap_sg; | ||
1782 | } | ||
1783 | |||
1784 | if (req_data_len != rsp_data_len) { | ||
1785 | rval = EXT_STATUS_BUSY; | ||
1786 | ql_log(ql_log_warn, vha, 0x70aa, | ||
1787 | "req_data_len != rsp_data_len\n"); | ||
1788 | goto done_unmap_sg; | ||
1789 | } | ||
1790 | |||
1791 | req_data_len = bsg_job->request_payload.payload_len; | ||
1792 | rsp_data_len = bsg_job->reply_payload.payload_len; | ||
1793 | |||
1794 | |||
1795 | /* Alloc SRB structure */ | ||
1796 | sp = qla2x00_get_sp(vha, &(vha->bidir_fcport), GFP_KERNEL); | ||
1797 | if (!sp) { | ||
1798 | ql_dbg(ql_dbg_user, vha, 0x70ac, | ||
1799 | "Alloc SRB structure failed\n"); | ||
1800 | rval = EXT_STATUS_NO_MEMORY; | ||
1801 | goto done_unmap_sg; | ||
1802 | } | ||
1803 | |||
1804 | /*Populate srb->ctx with bidir ctx*/ | ||
1805 | sp->u.bsg_job = bsg_job; | ||
1806 | sp->free = qla2x00_bsg_sp_free; | ||
1807 | sp->type = SRB_BIDI_CMD; | ||
1808 | sp->done = qla2x00_bsg_job_done; | ||
1809 | |||
1810 | /* Add the read and write sg count */ | ||
1811 | tot_dsds = rsp_sg_cnt + req_sg_cnt; | ||
1812 | |||
1813 | rval = qla2x00_start_bidir(sp, vha, tot_dsds); | ||
1814 | if (rval != EXT_STATUS_OK) | ||
1815 | goto done_free_srb; | ||
1816 | /* the bsg request will be completed in the interrupt handler */ | ||
1817 | return rval; | ||
1818 | |||
1819 | done_free_srb: | ||
1820 | mempool_free(sp, ha->srb_mempool); | ||
1821 | done_unmap_sg: | ||
1822 | dma_unmap_sg(&ha->pdev->dev, | ||
1823 | bsg_job->reply_payload.sg_list, | ||
1824 | bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
1825 | done_unmap_req_sg: | ||
1826 | dma_unmap_sg(&ha->pdev->dev, | ||
1827 | bsg_job->request_payload.sg_list, | ||
1828 | bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
1829 | done: | ||
1830 | |||
1831 | /* Return an error vendor specific response | ||
1832 | * and complete the bsg request | ||
1833 | */ | ||
1834 | bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = rval; | ||
1835 | bsg_job->reply_len = sizeof(struct fc_bsg_reply); | ||
1836 | bsg_job->reply->reply_payload_rcv_len = 0; | ||
1837 | bsg_job->reply->result = (DID_OK) << 16; | ||
1838 | bsg_job->job_done(bsg_job); | ||
1839 | /* Always retrun success, vendor rsp carries correct status */ | ||
1840 | return 0; | ||
1841 | } | ||
1842 | |||
1843 | static int | ||
1563 | qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) | 1844 | qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) |
1564 | { | 1845 | { |
1565 | switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) { | 1846 | switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) { |
@@ -1596,6 +1877,15 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) | |||
1596 | case QL_VND_WRITE_FRU_STATUS: | 1877 | case QL_VND_WRITE_FRU_STATUS: |
1597 | return qla2x00_write_fru_status(bsg_job); | 1878 | return qla2x00_write_fru_status(bsg_job); |
1598 | 1879 | ||
1880 | case QL_VND_WRITE_I2C: | ||
1881 | return qla2x00_write_i2c(bsg_job); | ||
1882 | |||
1883 | case QL_VND_READ_I2C: | ||
1884 | return qla2x00_read_i2c(bsg_job); | ||
1885 | |||
1886 | case QL_VND_DIAG_IO_CMD: | ||
1887 | return qla24xx_process_bidir_cmd(bsg_job); | ||
1888 | |||
1599 | default: | 1889 | default: |
1600 | bsg_job->reply->result = (DID_ERROR << 16); | 1890 | bsg_job->reply->result = (DID_ERROR << 16); |
1601 | bsg_job->job_done(bsg_job); | 1891 | bsg_job->job_done(bsg_job); |