]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 17 Jul 2017 19:26:12 +0000 (12:26 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 17 Jul 2017 19:26:12 +0000 (12:26 -0700)
Pull SCSI fixes from James Bottomley:
 "This is actually just a small set of mainly bug fixes for the original
  merge window code plus a few trivial updates and qedi boot from SAN
  support feature patch"

* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
  scsi: libfc: pass an error pointer to fc_disc_error()
  scsi: hisi_sas: make several const arrays static
  scsi: qla2xxx: Off by one in qlt_ctio_to_cmd()
  scsi: sg: fix SG_DXFER_FROM_DEV transfers
  scsi: virtio_scsi: always read VPD pages for multiqueue too
  scsi: qedf: fix spelling mistake: "offlading" -> "offloading"
  scsi: qedi: fix another spelling mistake: "alloction" -> "allocation"
  scsi: isci: fix typo in function names
  scsi: cxlflash: return -EFAULT if copy_from_user() fails
  scsi: qedi: Add support for Boot from SAN over iSCSI offload

12 files changed:
drivers/scsi/cxlflash/main.c
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
drivers/scsi/isci/request.c
drivers/scsi/libfc/fc_disc.c
drivers/scsi/qedf/qedf_main.c
drivers/scsi/qedi/qedi.h
drivers/scsi/qedi/qedi_fw.c
drivers/scsi/qedi/qedi_main.c
drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h [new file with mode: 0644]
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/sg.c
drivers/scsi/virtio_scsi.c

index 077f62e208aaef5125756ecd30273176698a7bc7..6a4367cc9caabea8f0bbc1519d309ab50b55578f 100644 (file)
@@ -3401,9 +3401,10 @@ static int cxlflash_afu_debug(struct cxlflash_cfg *cfg,
                if (is_write) {
                        req_flags |= SISL_REQ_FLAGS_HOST_WRITE;
 
-                       rc = copy_from_user(kbuf, ubuf, ulen);
-                       if (unlikely(rc))
+                       if (copy_from_user(kbuf, ubuf, ulen)) {
+                               rc = -EFAULT;
                                goto out;
+                       }
                }
        }
 
@@ -3431,8 +3432,10 @@ static int cxlflash_afu_debug(struct cxlflash_cfg *cfg,
                goto out;
        }
 
-       if (ulen && !is_write)
-               rc = copy_to_user(ubuf, kbuf, ulen);
+       if (ulen && !is_write) {
+               if (copy_to_user(ubuf, kbuf, ulen))
+                       rc = -EFAULT;
+       }
 out:
        kfree(buf);
        dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
index 551d103c27f1303b5299e6d2ff80e8cd93b777ff..2bfea7082e3a070f0e6e44f27837df86b8f75c89 100644 (file)
@@ -1693,7 +1693,7 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
 
 static int parse_trans_tx_err_code_v2_hw(u32 err_msk)
 {
-       const u8 trans_tx_err_code_prio[] = {
+       static const u8 trans_tx_err_code_prio[] = {
                TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS,
                TRANS_TX_ERR_PHY_NOT_ENABLE,
                TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION,
@@ -1738,7 +1738,7 @@ static int parse_trans_tx_err_code_v2_hw(u32 err_msk)
 
 static int parse_trans_rx_err_code_v2_hw(u32 err_msk)
 {
-       const u8 trans_rx_err_code_prio[] = {
+       static const u8 trans_rx_err_code_prio[] = {
                TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR,
                TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR,
                TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM,
@@ -1784,7 +1784,7 @@ static int parse_trans_rx_err_code_v2_hw(u32 err_msk)
 
 static int parse_dma_tx_err_code_v2_hw(u32 err_msk)
 {
-       const u8 dma_tx_err_code_prio[] = {
+       static const u8 dma_tx_err_code_prio[] = {
                DMA_TX_UNEXP_XFER_ERR,
                DMA_TX_UNEXP_RETRANS_ERR,
                DMA_TX_XFER_LEN_OVERFLOW,
@@ -1810,7 +1810,7 @@ static int parse_dma_tx_err_code_v2_hw(u32 err_msk)
 
 static int parse_sipc_rx_err_code_v2_hw(u32 err_msk)
 {
-       const u8 sipc_rx_err_code_prio[] = {
+       static const u8 sipc_rx_err_code_prio[] = {
                SIPC_RX_FIS_STATUS_ERR_BIT_VLD,
                SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR,
                SIPC_RX_FIS_STATUS_BSY_BIT_ERR,
@@ -1836,7 +1836,7 @@ static int parse_sipc_rx_err_code_v2_hw(u32 err_msk)
 
 static int parse_dma_rx_err_code_v2_hw(u32 err_msk)
 {
-       const u8 dma_rx_err_code_prio[] = {
+       static const u8 dma_rx_err_code_prio[] = {
                DMA_RX_UNKNOWN_FRM_ERR,
                DMA_RX_DATA_LEN_OVERFLOW,
                DMA_RX_DATA_LEN_UNDERFLOW,
index 47f66e9497451e290112852fa5a3f6503b4f33eb..ed197bc8e801a604029ac12e93bf24d9bdce7e34 100644 (file)
@@ -213,7 +213,7 @@ static void sci_task_request_build_ssp_task_iu(struct isci_request *ireq)
  * @task_context:
  *
  */
-static void scu_ssp_reqeust_construct_task_context(
+static void scu_ssp_request_construct_task_context(
        struct isci_request *ireq,
        struct scu_task_context *task_context)
 {
@@ -425,7 +425,7 @@ static void scu_ssp_io_request_construct_task_context(struct isci_request *ireq,
        u8 prot_type = scsi_get_prot_type(scmd);
        u8 prot_op = scsi_get_prot_op(scmd);
 
-       scu_ssp_reqeust_construct_task_context(ireq, task_context);
+       scu_ssp_request_construct_task_context(ireq, task_context);
 
        task_context->ssp_command_iu_length =
                sizeof(struct ssp_cmd_iu) / sizeof(u32);
@@ -472,7 +472,7 @@ static void scu_ssp_task_request_construct_task_context(struct isci_request *ire
 {
        struct scu_task_context *task_context = ireq->tc;
 
-       scu_ssp_reqeust_construct_task_context(ireq, task_context);
+       scu_ssp_request_construct_task_context(ireq, task_context);
 
        task_context->control_frame                = 1;
        task_context->priority                     = SCU_TASK_PRIORITY_HIGH;
@@ -495,7 +495,7 @@ static void scu_ssp_task_request_construct_task_context(struct isci_request *ire
  * the command buffer is complete. none Revisit task context construction to
  * determine what is common for SSP/SMP/STP task context structures.
  */
-static void scu_sata_reqeust_construct_task_context(
+static void scu_sata_request_construct_task_context(
        struct isci_request *ireq,
        struct scu_task_context *task_context)
 {
@@ -562,7 +562,7 @@ static void scu_stp_raw_request_construct_task_context(struct isci_request *ireq
 {
        struct scu_task_context *task_context = ireq->tc;
 
-       scu_sata_reqeust_construct_task_context(ireq, task_context);
+       scu_sata_request_construct_task_context(ireq, task_context);
 
        task_context->control_frame         = 0;
        task_context->priority              = SCU_TASK_PRIORITY_NORMAL;
@@ -613,7 +613,7 @@ static void sci_stp_optimized_request_construct(struct isci_request *ireq,
        struct scu_task_context *task_context = ireq->tc;
 
        /* Build the STP task context structure */
-       scu_sata_reqeust_construct_task_context(ireq, task_context);
+       scu_sata_request_construct_task_context(ireq, task_context);
 
        /* Copy over the SGL elements */
        sci_request_build_sgl(ireq);
@@ -1401,7 +1401,7 @@ static enum sci_status sci_stp_request_pio_data_out_transmit_data(struct isci_re
  * @data_buffer: The buffer of data to be copied.
  * @length: The length of the data transfer.
  *
- * Copy the data from the buffer for the length specified to the IO reqeust SGL
+ * Copy the data from the buffer for the length specified to the IO request SGL
  * specified data region. enum sci_status
  */
 static enum sci_status
index fd501f8dbb1107fe7f567ec3e66cf7c9e6471083..8660f923ace02120eb63c2ac11724448d4cbd060 100644 (file)
@@ -573,7 +573,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,
                event = DISC_EV_FAILED;
        }
        if (error)
-               fc_disc_error(disc, fp);
+               fc_disc_error(disc, ERR_PTR(error));
        else if (event != DISC_EV_NONE)
                fc_disc_done(disc, event);
        fc_frame_free(fp);
index b58bba4604e8cfce57fd320d53043bb293845765..7786c97e033fdcdd9643a41dd1d0bb928036d65b 100644 (file)
@@ -1227,7 +1227,7 @@ static void qedf_rport_event_handler(struct fc_lport *lport,
 
                if (rdata->spp_type != FC_TYPE_FCP) {
                        QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
-                           "Not offlading since since spp type isn't FCP\n");
+                           "Not offloading since spp type isn't FCP\n");
                        break;
                }
                if (!(rdata->ids.roles & FC_RPORT_ROLE_FCP_TARGET)) {
index 32632c9b22766d59e223a256c430810a4fa33bec..91d2f51c351b4d6940d04a1e4a261f2d816e7b04 100644 (file)
 #include <linux/qed/qed_iscsi_if.h>
 #include <linux/qed/qed_ll2_if.h>
 #include "qedi_version.h"
+#include "qedi_nvm_iscsi_cfg.h"
 
 #define QEDI_MODULE_NAME               "qedi"
 
 struct qedi_endpoint;
 
+#ifndef GET_FIELD2
+#define GET_FIELD2(value, name) \
+       (((value) & (name ## _MASK)) >> (name ## _OFFSET))
+#endif
+
 /*
  * PCI function probe defines
  */
@@ -66,6 +72,11 @@ struct qedi_endpoint;
 #define QEDI_HW_DMA_BOUNDARY   0xfff
 #define QEDI_PATH_HANDLE       0xFE0000000UL
 
+enum qedi_nvm_tgts {
+       QEDI_NVM_TGT_PRI,
+       QEDI_NVM_TGT_SEC,
+};
+
 struct qedi_uio_ctrl {
        /* meta data */
        u32 uio_hsi_version;
@@ -283,6 +294,8 @@ struct qedi_ctx {
        void *bdq_pbl_list;
        dma_addr_t bdq_pbl_list_dma;
        u8 bdq_pbl_list_num_entries;
+       struct nvm_iscsi_cfg *iscsi_cfg;
+       dma_addr_t nvm_buf_dma;
        void __iomem *bdq_primary_prod;
        void __iomem *bdq_secondary_prod;
        u16 bdq_prod_idx;
@@ -337,6 +350,10 @@ struct qedi_ctx {
        bool use_fast_sge;
 
        atomic_t num_offloads;
+#define SYSFS_FLAG_FW_SEL_BOOT 2
+#define IPV6_LEN       41
+#define IPV4_LEN       17
+       struct iscsi_boot_kset *boot_kset;
 };
 
 struct qedi_work {
index 19254bd739d9c9e32b300d24fd418fc6f4ebd2b1..93d54acd4a22f70f7be57470056166f58ed69b0d 100644 (file)
@@ -1411,7 +1411,7 @@ static void qedi_tmf_work(struct work_struct *work)
 
        list_work = kzalloc(sizeof(*list_work), GFP_ATOMIC);
        if (!list_work) {
-               QEDI_ERR(&qedi->dbg_ctx, "Memory alloction failed\n");
+               QEDI_ERR(&qedi->dbg_ctx, "Memory allocation failed\n");
                goto abort_ret;
        }
 
index 5f5a4ef2e52965647e1e3db5b4cdd7bdb8021af8..2c37836848152f91b394bfeea4e120ce2d35f46a 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mm.h>
 #include <linux/if_vlan.h>
 #include <linux/cpu.h>
+#include <linux/iscsi_boot_sysfs.h>
 
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -1143,6 +1144,30 @@ exit_setup_int:
        return rc;
 }
 
+static void qedi_free_nvm_iscsi_cfg(struct qedi_ctx *qedi)
+{
+       if (qedi->iscsi_cfg)
+               dma_free_coherent(&qedi->pdev->dev,
+                                 sizeof(struct nvm_iscsi_cfg),
+                                 qedi->iscsi_cfg, qedi->nvm_buf_dma);
+}
+
+static int qedi_alloc_nvm_iscsi_cfg(struct qedi_ctx *qedi)
+{
+       qedi->iscsi_cfg = dma_zalloc_coherent(&qedi->pdev->dev,
+                                            sizeof(struct nvm_iscsi_cfg),
+                                            &qedi->nvm_buf_dma, GFP_KERNEL);
+       if (!qedi->iscsi_cfg) {
+               QEDI_ERR(&qedi->dbg_ctx, "Could not allocate NVM BUF.\n");
+               return -ENOMEM;
+       }
+       QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+                 "NVM BUF addr=0x%p dma=0x%llx.\n", qedi->iscsi_cfg,
+                 qedi->nvm_buf_dma);
+
+       return 0;
+}
+
 static void qedi_free_bdq(struct qedi_ctx *qedi)
 {
        int i;
@@ -1183,6 +1208,7 @@ static void qedi_free_global_queues(struct qedi_ctx *qedi)
                kfree(gl[i]);
        }
        qedi_free_bdq(qedi);
+       qedi_free_nvm_iscsi_cfg(qedi);
 }
 
 static int qedi_alloc_bdq(struct qedi_ctx *qedi)
@@ -1309,6 +1335,11 @@ static int qedi_alloc_global_queues(struct qedi_ctx *qedi)
        if (rc)
                goto mem_alloc_failure;
 
+       /* Allocate DMA coherent buffers for NVM_ISCSI_CFG */
+       rc = qedi_alloc_nvm_iscsi_cfg(qedi);
+       if (rc)
+               goto mem_alloc_failure;
+
        /* Allocate a CQ and an associated PBL for each MSI-X
         * vector.
         */
@@ -1671,6 +1702,387 @@ void qedi_reset_host_mtu(struct qedi_ctx *qedi, u16 mtu)
        qedi_ops->ll2->start(qedi->cdev, &params);
 }
 
+/**
+ * qedi_get_nvram_block: - Scan through the iSCSI NVRAM block (while accounting
+ * for gaps) for the matching absolute-pf-id of the QEDI device.
+ */
+static struct nvm_iscsi_block *
+qedi_get_nvram_block(struct qedi_ctx *qedi)
+{
+       int i;
+       u8 pf;
+       u32 flags;
+       struct nvm_iscsi_block *block;
+
+       pf = qedi->dev_info.common.abs_pf_id;
+       block = &qedi->iscsi_cfg->block[0];
+       for (i = 0; i < NUM_OF_ISCSI_PF_SUPPORTED; i++, block++) {
+               flags = ((block->id) & NVM_ISCSI_CFG_BLK_CTRL_FLAG_MASK) >>
+                       NVM_ISCSI_CFG_BLK_CTRL_FLAG_OFFSET;
+               if (flags & (NVM_ISCSI_CFG_BLK_CTRL_FLAG_IS_NOT_EMPTY |
+                               NVM_ISCSI_CFG_BLK_CTRL_FLAG_PF_MAPPED) &&
+                       (pf == (block->id & NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_MASK)
+                               >> NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_OFFSET))
+                       return block;
+       }
+       return NULL;
+}
+
+static ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf)
+{
+       struct qedi_ctx *qedi = data;
+       struct nvm_iscsi_initiator *initiator;
+       char *str = buf;
+       int rc = 1;
+       u32 ipv6_en, dhcp_en, ip_len;
+       struct nvm_iscsi_block *block;
+       char *fmt, *ip, *sub, *gw;
+
+       block = qedi_get_nvram_block(qedi);
+       if (!block)
+               return 0;
+
+       initiator = &block->initiator;
+       ipv6_en = block->generic.ctrl_flags &
+                 NVM_ISCSI_CFG_GEN_IPV6_ENABLED;
+       dhcp_en = block->generic.ctrl_flags &
+                 NVM_ISCSI_CFG_GEN_DHCP_TCPIP_CONFIG_ENABLED;
+       /* Static IP assignments. */
+       fmt = ipv6_en ? "%pI6\n" : "%pI4\n";
+       ip = ipv6_en ? initiator->ipv6.addr.byte : initiator->ipv4.addr.byte;
+       ip_len = ipv6_en ? IPV6_LEN : IPV4_LEN;
+       sub = ipv6_en ? initiator->ipv6.subnet_mask.byte :
+             initiator->ipv4.subnet_mask.byte;
+       gw = ipv6_en ? initiator->ipv6.gateway.byte :
+            initiator->ipv4.gateway.byte;
+       /* DHCP IP adjustments. */
+       fmt = dhcp_en ? "%s\n" : fmt;
+       if (dhcp_en) {
+               ip = ipv6_en ? "0::0" : "0.0.0.0";
+               sub = ip;
+               gw = ip;
+               ip_len = ipv6_en ? 5 : 8;
+       }
+
+       switch (type) {
+       case ISCSI_BOOT_ETH_IP_ADDR:
+               rc = snprintf(str, ip_len, fmt, ip);
+               break;
+       case ISCSI_BOOT_ETH_SUBNET_MASK:
+               rc = snprintf(str, ip_len, fmt, sub);
+               break;
+       case ISCSI_BOOT_ETH_GATEWAY:
+               rc = snprintf(str, ip_len, fmt, gw);
+               break;
+       case ISCSI_BOOT_ETH_FLAGS:
+               rc = snprintf(str, 3, "%hhd\n",
+                             SYSFS_FLAG_FW_SEL_BOOT);
+               break;
+       case ISCSI_BOOT_ETH_INDEX:
+               rc = snprintf(str, 3, "0\n");
+               break;
+       case ISCSI_BOOT_ETH_MAC:
+               rc = sysfs_format_mac(str, qedi->mac, ETH_ALEN);
+               break;
+       case ISCSI_BOOT_ETH_VLAN:
+               rc = snprintf(str, 12, "%d\n",
+                             GET_FIELD2(initiator->generic_cont0,
+                                        NVM_ISCSI_CFG_INITIATOR_VLAN));
+               break;
+       case ISCSI_BOOT_ETH_ORIGIN:
+               if (dhcp_en)
+                       rc = snprintf(str, 3, "3\n");
+               break;
+       default:
+               rc = 0;
+               break;
+       }
+
+       return rc;
+}
+
+static umode_t qedi_eth_get_attr_visibility(void *data, int type)
+{
+       int rc = 1;
+
+       switch (type) {
+       case ISCSI_BOOT_ETH_FLAGS:
+       case ISCSI_BOOT_ETH_MAC:
+       case ISCSI_BOOT_ETH_INDEX:
+       case ISCSI_BOOT_ETH_IP_ADDR:
+       case ISCSI_BOOT_ETH_SUBNET_MASK:
+       case ISCSI_BOOT_ETH_GATEWAY:
+       case ISCSI_BOOT_ETH_ORIGIN:
+       case ISCSI_BOOT_ETH_VLAN:
+               rc = 0444;
+               break;
+       default:
+               rc = 0;
+               break;
+       }
+       return rc;
+}
+
+static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf)
+{
+       struct qedi_ctx *qedi = data;
+       struct nvm_iscsi_initiator *initiator;
+       char *str = buf;
+       int rc;
+       struct nvm_iscsi_block *block;
+
+       block = qedi_get_nvram_block(qedi);
+       if (!block)
+               return 0;
+
+       initiator = &block->initiator;
+
+       switch (type) {
+       case ISCSI_BOOT_INI_INITIATOR_NAME:
+               rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n",
+                             initiator->initiator_name.byte);
+               break;
+       default:
+               rc = 0;
+               break;
+       }
+       return rc;
+}
+
+static umode_t qedi_ini_get_attr_visibility(void *data, int type)
+{
+       int rc;
+
+       switch (type) {
+       case ISCSI_BOOT_INI_INITIATOR_NAME:
+               rc = 0444;
+               break;
+       default:
+               rc = 0;
+               break;
+       }
+       return rc;
+}
+
+static ssize_t
+qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type,
+                       char *buf, enum qedi_nvm_tgts idx)
+{
+       char *str = buf;
+       int rc = 1;
+       u32 ctrl_flags, ipv6_en, chap_en, mchap_en, ip_len;
+       struct nvm_iscsi_block *block;
+       char *chap_name, *chap_secret;
+       char *mchap_name, *mchap_secret;
+
+       block = qedi_get_nvram_block(qedi);
+       if (!block)
+               goto exit_show_tgt_info;
+
+       QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_EVT,
+                 "Port:%d, tgt_idx:%d\n",
+                 GET_FIELD2(block->id, NVM_ISCSI_CFG_BLK_MAPPED_PF_ID), idx);
+
+       ctrl_flags = block->target[idx].ctrl_flags &
+                    NVM_ISCSI_CFG_TARGET_ENABLED;
+
+       if (!ctrl_flags) {
+               QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_EVT,
+                         "Target disabled\n");
+               goto exit_show_tgt_info;
+       }
+
+       ipv6_en = block->generic.ctrl_flags &
+                 NVM_ISCSI_CFG_GEN_IPV6_ENABLED;
+       ip_len = ipv6_en ? IPV6_LEN : IPV4_LEN;
+       chap_en = block->generic.ctrl_flags &
+                 NVM_ISCSI_CFG_GEN_CHAP_ENABLED;
+       chap_name = chap_en ? block->initiator.chap_name.byte : NULL;
+       chap_secret = chap_en ? block->initiator.chap_password.byte : NULL;
+
+       mchap_en = block->generic.ctrl_flags &
+                 NVM_ISCSI_CFG_GEN_CHAP_MUTUAL_ENABLED;
+       mchap_name = mchap_en ? block->target[idx].chap_name.byte : NULL;
+       mchap_secret = mchap_en ? block->target[idx].chap_password.byte : NULL;
+
+       switch (type) {
+       case ISCSI_BOOT_TGT_NAME:
+               rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n",
+                             block->target[idx].target_name.byte);
+               break;
+       case ISCSI_BOOT_TGT_IP_ADDR:
+               if (ipv6_en)
+                       rc = snprintf(str, ip_len, "%pI6\n",
+                                     block->target[idx].ipv6_addr.byte);
+               else
+                       rc = snprintf(str, ip_len, "%pI4\n",
+                                     block->target[idx].ipv4_addr.byte);
+               break;
+       case ISCSI_BOOT_TGT_PORT:
+               rc = snprintf(str, 12, "%d\n",
+                             GET_FIELD2(block->target[idx].generic_cont0,
+                                        NVM_ISCSI_CFG_TARGET_TCP_PORT));
+               break;
+       case ISCSI_BOOT_TGT_LUN:
+               rc = snprintf(str, 22, "%.*d\n",
+                             block->target[idx].lun.value[1],
+                             block->target[idx].lun.value[0]);
+               break;
+       case ISCSI_BOOT_TGT_CHAP_NAME:
+               rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n",
+                             chap_name);
+               break;
+       case ISCSI_BOOT_TGT_CHAP_SECRET:
+               rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n",
+                             chap_secret);
+               break;
+       case ISCSI_BOOT_TGT_REV_CHAP_NAME:
+               rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n",
+                             mchap_name);
+               break;
+       case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
+               rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n",
+                             mchap_secret);
+               break;
+       case ISCSI_BOOT_TGT_FLAGS:
+               rc = snprintf(str, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT);
+               break;
+       case ISCSI_BOOT_TGT_NIC_ASSOC:
+               rc = snprintf(str, 3, "0\n");
+               break;
+       default:
+               rc = 0;
+               break;
+       }
+
+exit_show_tgt_info:
+       return rc;
+}
+
+static ssize_t qedi_show_boot_tgt_pri_info(void *data, int type, char *buf)
+{
+       struct qedi_ctx *qedi = data;
+
+       return qedi_show_boot_tgt_info(qedi, type, buf, QEDI_NVM_TGT_PRI);
+}
+
+static ssize_t qedi_show_boot_tgt_sec_info(void *data, int type, char *buf)
+{
+       struct qedi_ctx *qedi = data;
+
+       return qedi_show_boot_tgt_info(qedi, type, buf, QEDI_NVM_TGT_SEC);
+}
+
+static umode_t qedi_tgt_get_attr_visibility(void *data, int type)
+{
+       int rc;
+
+       switch (type) {
+       case ISCSI_BOOT_TGT_NAME:
+       case ISCSI_BOOT_TGT_IP_ADDR:
+       case ISCSI_BOOT_TGT_PORT:
+       case ISCSI_BOOT_TGT_LUN:
+       case ISCSI_BOOT_TGT_CHAP_NAME:
+       case ISCSI_BOOT_TGT_CHAP_SECRET:
+       case ISCSI_BOOT_TGT_REV_CHAP_NAME:
+       case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
+       case ISCSI_BOOT_TGT_NIC_ASSOC:
+       case ISCSI_BOOT_TGT_FLAGS:
+               rc = 0444;
+               break;
+       default:
+               rc = 0;
+               break;
+       }
+       return rc;
+}
+
+static void qedi_boot_release(void *data)
+{
+       struct qedi_ctx *qedi = data;
+
+       scsi_host_put(qedi->shost);
+}
+
+static int qedi_get_boot_info(struct qedi_ctx *qedi)
+{
+       int ret = 1;
+       u16 len;
+
+       len = sizeof(struct nvm_iscsi_cfg);
+
+       QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+                 "Get NVM iSCSI CFG image\n");
+       ret = qedi_ops->common->nvm_get_image(qedi->cdev,
+                                             QED_NVM_IMAGE_ISCSI_CFG,
+                                             (char *)qedi->iscsi_cfg, len);
+       if (ret)
+               QEDI_ERR(&qedi->dbg_ctx,
+                        "Could not get NVM image. ret = %d\n", ret);
+
+       return ret;
+}
+
+static int qedi_setup_boot_info(struct qedi_ctx *qedi)
+{
+       struct iscsi_boot_kobj *boot_kobj;
+
+       if (qedi_get_boot_info(qedi))
+               return -EPERM;
+
+       qedi->boot_kset = iscsi_boot_create_host_kset(qedi->shost->host_no);
+       if (!qedi->boot_kset)
+               goto kset_free;
+
+       if (!scsi_host_get(qedi->shost))
+               goto kset_free;
+
+       boot_kobj = iscsi_boot_create_target(qedi->boot_kset, 0, qedi,
+                                            qedi_show_boot_tgt_pri_info,
+                                            qedi_tgt_get_attr_visibility,
+                                            qedi_boot_release);
+       if (!boot_kobj)
+               goto put_host;
+
+       if (!scsi_host_get(qedi->shost))
+               goto kset_free;
+
+       boot_kobj = iscsi_boot_create_target(qedi->boot_kset, 1, qedi,
+                                            qedi_show_boot_tgt_sec_info,
+                                            qedi_tgt_get_attr_visibility,
+                                            qedi_boot_release);
+       if (!boot_kobj)
+               goto put_host;
+
+       if (!scsi_host_get(qedi->shost))
+               goto kset_free;
+
+       boot_kobj = iscsi_boot_create_initiator(qedi->boot_kset, 0, qedi,
+                                               qedi_show_boot_ini_info,
+                                               qedi_ini_get_attr_visibility,
+                                               qedi_boot_release);
+       if (!boot_kobj)
+               goto put_host;
+
+       if (!scsi_host_get(qedi->shost))
+               goto kset_free;
+
+       boot_kobj = iscsi_boot_create_ethernet(qedi->boot_kset, 0, qedi,
+                                              qedi_show_boot_eth_info,
+                                              qedi_eth_get_attr_visibility,
+                                              qedi_boot_release);
+       if (!boot_kobj)
+               goto put_host;
+
+       return 0;
+
+put_host:
+       scsi_host_put(qedi->shost);
+kset_free:
+       iscsi_boot_destroy_kset(qedi->boot_kset);
+       return -ENOMEM;
+}
+
 static void __qedi_remove(struct pci_dev *pdev, int mode)
 {
        struct qedi_ctx *qedi = pci_get_drvdata(pdev);
@@ -1724,6 +2136,9 @@ static void __qedi_remove(struct pci_dev *pdev, int mode)
                        qedi->ll2_recv_thread = NULL;
                }
                qedi_ll2_free_skbs(qedi);
+
+               if (qedi->boot_kset)
+                       iscsi_boot_destroy_kset(qedi->boot_kset);
        }
 }
 
@@ -1967,6 +2382,10 @@ static int __qedi_probe(struct pci_dev *pdev, int mode)
                /* F/w needs 1st task context memory entry for performance */
                set_bit(QEDI_RESERVE_TASK_ID, qedi->task_idx_map);
                atomic_set(&qedi->num_offloads, 0);
+
+               if (qedi_setup_boot_info(qedi))
+                       QEDI_ERR(&qedi->dbg_ctx,
+                                "No iSCSI boot target configured\n");
        }
 
        return 0;
diff --git a/drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h b/drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h
new file mode 100644 (file)
index 0000000..df39b69
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * QLogic iSCSI Offload Driver
+ * Copyright (c) 2016 Cavium Inc.
+ *
+ * This software is available under the terms of the GNU General Public License
+ * (GPL) Version 2, available from the file COPYING in the main directory of
+ * this source tree.
+ */
+
+#ifndef NVM_ISCSI_CFG_H
+#define NVM_ISCSI_CFG_H
+
+#define NUM_OF_ISCSI_TARGET_PER_PF    4   /* Defined as per the
+                                          * ISCSI IBFT constraint
+                                          */
+#define NUM_OF_ISCSI_PF_SUPPORTED     4   /* One PF per Port -
+                                          * assuming 4 port card
+                                          */
+
+#define NVM_ISCSI_CFG_DHCP_NAME_MAX_LEN  256
+
+union nvm_iscsi_dhcp_vendor_id {
+       u32 value[NVM_ISCSI_CFG_DHCP_NAME_MAX_LEN / 4];
+       u8  byte[NVM_ISCSI_CFG_DHCP_NAME_MAX_LEN];
+};
+
+#define NVM_ISCSI_IPV4_ADDR_BYTE_LEN 4
+union nvm_iscsi_ipv4_addr {
+       u32 addr;
+       u8  byte[NVM_ISCSI_IPV4_ADDR_BYTE_LEN];
+};
+
+#define NVM_ISCSI_IPV6_ADDR_BYTE_LEN 16
+union nvm_iscsi_ipv6_addr {
+       u32 addr[4];
+       u8  byte[NVM_ISCSI_IPV6_ADDR_BYTE_LEN];
+};
+
+struct nvm_iscsi_initiator_ipv4 {
+       union nvm_iscsi_ipv4_addr addr;                         /* 0x0 */
+       union nvm_iscsi_ipv4_addr subnet_mask;                  /* 0x4 */
+       union nvm_iscsi_ipv4_addr gateway;                      /* 0x8 */
+       union nvm_iscsi_ipv4_addr primary_dns;                  /* 0xC */
+       union nvm_iscsi_ipv4_addr secondary_dns;                /* 0x10 */
+       union nvm_iscsi_ipv4_addr dhcp_addr;                    /* 0x14 */
+
+       union nvm_iscsi_ipv4_addr isns_server;                  /* 0x18 */
+       union nvm_iscsi_ipv4_addr slp_server;                   /* 0x1C */
+       union nvm_iscsi_ipv4_addr primay_radius_server;         /* 0x20 */
+       union nvm_iscsi_ipv4_addr secondary_radius_server;      /* 0x24 */
+
+       union nvm_iscsi_ipv4_addr rsvd[4];                      /* 0x28 */
+};
+
+struct nvm_iscsi_initiator_ipv6 {
+       union nvm_iscsi_ipv6_addr addr;                         /* 0x0 */
+       union nvm_iscsi_ipv6_addr subnet_mask;                  /* 0x10 */
+       union nvm_iscsi_ipv6_addr gateway;                      /* 0x20 */
+       union nvm_iscsi_ipv6_addr primary_dns;                  /* 0x30 */
+       union nvm_iscsi_ipv6_addr secondary_dns;                /* 0x40 */
+       union nvm_iscsi_ipv6_addr dhcp_addr;                    /* 0x50 */
+
+       union nvm_iscsi_ipv6_addr isns_server;                  /* 0x60 */
+       union nvm_iscsi_ipv6_addr slp_server;                   /* 0x70 */
+       union nvm_iscsi_ipv6_addr primay_radius_server;         /* 0x80 */
+       union nvm_iscsi_ipv6_addr secondary_radius_server;      /* 0x90 */
+
+       union nvm_iscsi_ipv6_addr rsvd[3];                      /* 0xA0 */
+
+       u32   config;                                           /* 0xD0 */
+#define NVM_ISCSI_CFG_INITIATOR_IPV6_SUBNET_MASK_PREFIX_MASK      0x000000FF
+#define NVM_ISCSI_CFG_INITIATOR_IPV6_SUBNET_MASK_PREFIX_OFFSET    0
+
+       u32   rsvd_1[3];
+};
+
+#define NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN  256
+union nvm_iscsi_name {
+       u32 value[NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN / 4];
+       u8  byte[NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN];
+};
+
+#define NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN  256
+union nvm_iscsi_chap_name {
+       u32 value[NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN / 4];
+       u8  byte[NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN];
+};
+
+#define NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN  16 /* md5 need per RFC1996
+                                           * is 16 octets
+                                           */
+union nvm_iscsi_chap_password {
+       u32 value[NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN / 4];
+       u8 byte[NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN];
+};
+
+union nvm_iscsi_lun {
+       u8  byte[8];
+       u32 value[2];
+};
+
+struct nvm_iscsi_generic {
+       u32 ctrl_flags;                                         /* 0x0 */
+#define NVM_ISCSI_CFG_GEN_CHAP_ENABLED                 BIT(0)
+#define NVM_ISCSI_CFG_GEN_DHCP_TCPIP_CONFIG_ENABLED    BIT(1)
+#define NVM_ISCSI_CFG_GEN_DHCP_ISCSI_CONFIG_ENABLED    BIT(2)
+#define NVM_ISCSI_CFG_GEN_IPV6_ENABLED                 BIT(3)
+#define NVM_ISCSI_CFG_GEN_IPV4_FALLBACK_ENABLED        BIT(4)
+#define NVM_ISCSI_CFG_GEN_ISNS_WORLD_LOGIN             BIT(5)
+#define NVM_ISCSI_CFG_GEN_ISNS_SELECTIVE_LOGIN         BIT(6)
+#define NVM_ISCSI_CFG_GEN_ADDR_REDIRECT_ENABLED               BIT(7)
+#define NVM_ISCSI_CFG_GEN_CHAP_MUTUAL_ENABLED          BIT(8)
+
+       u32 timeout;                                            /* 0x4 */
+#define NVM_ISCSI_CFG_GEN_DHCP_REQUEST_TIMEOUT_MASK       0x0000FFFF
+#define NVM_ISCSI_CFG_GEN_DHCP_REQUEST_TIMEOUT_OFFSET     0
+#define NVM_ISCSI_CFG_GEN_PORT_LOGIN_TIMEOUT_MASK         0xFFFF0000
+#define NVM_ISCSI_CFG_GEN_PORT_LOGIN_TIMEOUT_OFFSET       16
+
+       union nvm_iscsi_dhcp_vendor_id  dhcp_vendor_id;         /* 0x8  */
+       u32 rsvd[62];                                           /* 0x108 */
+};
+
+struct nvm_iscsi_initiator {
+       struct nvm_iscsi_initiator_ipv4 ipv4;                   /* 0x0 */
+       struct nvm_iscsi_initiator_ipv6 ipv6;                   /* 0x38 */
+
+       union nvm_iscsi_name           initiator_name;          /* 0x118 */
+       union nvm_iscsi_chap_name      chap_name;               /* 0x218 */
+       union nvm_iscsi_chap_password  chap_password;           /* 0x318 */
+
+       u32 generic_cont0;                                      /* 0x398 */
+#define NVM_ISCSI_CFG_INITIATOR_VLAN_MASK              0x0000FFFF
+#define NVM_ISCSI_CFG_INITIATOR_VLAN_OFFSET            0
+#define NVM_ISCSI_CFG_INITIATOR_IP_VERSION_MASK                0x00030000
+#define NVM_ISCSI_CFG_INITIATOR_IP_VERSION_OFFSET      16
+#define NVM_ISCSI_CFG_INITIATOR_IP_VERSION_4           1
+#define NVM_ISCSI_CFG_INITIATOR_IP_VERSION_6           2
+#define NVM_ISCSI_CFG_INITIATOR_IP_VERSION_4_AND_6     3
+
+       u32 ctrl_flags;
+#define NVM_ISCSI_CFG_INITIATOR_IP_VERSION_PRIORITY_V6     BIT(0)
+#define NVM_ISCSI_CFG_INITIATOR_VLAN_ENABLED               BIT(1)
+
+       u32 rsvd[116];                                          /* 0x32C */
+};
+
+struct nvm_iscsi_target {
+       u32 ctrl_flags;                                         /* 0x0 */
+#define NVM_ISCSI_CFG_TARGET_ENABLED            BIT(0)
+#define NVM_ISCSI_CFG_BOOT_TIME_LOGIN_STATUS    BIT(1)
+
+       u32 generic_cont0;                                      /* 0x4 */
+#define NVM_ISCSI_CFG_TARGET_TCP_PORT_MASK      0x0000FFFF
+#define NVM_ISCSI_CFG_TARGET_TCP_PORT_OFFSET    0
+
+       u32 ip_ver;
+#define NVM_ISCSI_CFG_IPv4       4
+#define NVM_ISCSI_CFG_IPv6       6
+
+       u32 rsvd_1[7];                                          /* 0x24 */
+       union nvm_iscsi_ipv4_addr ipv4_addr;                    /* 0x28 */
+       union nvm_iscsi_ipv6_addr ipv6_addr;                    /* 0x2C */
+       union nvm_iscsi_lun lun;                                /* 0x3C */
+
+       union nvm_iscsi_name           target_name;             /* 0x44 */
+       union nvm_iscsi_chap_name      chap_name;               /* 0x144 */
+       union nvm_iscsi_chap_password  chap_password;           /* 0x244 */
+
+       u32 rsvd_2[107];                                        /* 0x2C4 */
+};
+
+struct nvm_iscsi_block {
+       u32 id;                                                 /* 0x0 */
+#define NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_MASK         0x0000000F
+#define NVM_ISCSI_CFG_BLK_MAPPED_PF_ID_OFFSET       0
+#define NVM_ISCSI_CFG_BLK_CTRL_FLAG_MASK            0x00000FF0
+#define NVM_ISCSI_CFG_BLK_CTRL_FLAG_OFFSET          4
+#define NVM_ISCSI_CFG_BLK_CTRL_FLAG_IS_NOT_EMPTY    BIT(0)
+#define NVM_ISCSI_CFG_BLK_CTRL_FLAG_PF_MAPPED       BIT(1)
+
+       u32 rsvd_1[5];                                          /* 0x4 */
+
+       struct nvm_iscsi_generic     generic;                   /* 0x18 */
+       struct nvm_iscsi_initiator   initiator;                 /* 0x218 */
+       struct nvm_iscsi_target      target[NUM_OF_ISCSI_TARGET_PER_PF];
+                                                               /* 0x718 */
+
+       u32 rsvd_2[58];                                         /* 0x1718 */
+       /* total size - 0x1800 - 6K block */
+};
+
+struct nvm_iscsi_cfg {
+       u32 id;                                                 /* 0x0 */
+#define NVM_ISCSI_CFG_BLK_VERSION_MINOR_MASK     0x000000FF
+#define NVM_ISCSI_CFG_BLK_VERSION_MAJOR_MASK     0x0000FF00
+#define NVM_ISCSI_CFG_BLK_SIGNATURE_MASK         0xFFFF0000
+#define NVM_ISCSI_CFG_BLK_SIGNATURE              0x49430000 /* IC - Iscsi
+                                                            * Config
+                                                            */
+
+#define NVM_ISCSI_CFG_BLK_VERSION_MAJOR          0
+#define NVM_ISCSI_CFG_BLK_VERSION_MINOR          10
+#define NVM_ISCSI_CFG_BLK_VERSION ((NVM_ISCSI_CFG_BLK_VERSION_MAJOR << 8) | \
+                                  NVM_ISCSI_CFG_BLK_VERSION_MINOR)
+
+       struct nvm_iscsi_block  block[NUM_OF_ISCSI_PF_SUPPORTED]; /* 0x4 */
+};
+
+#endif
index c2dc836dc4843e79ad6239186b650a14f1f91693..e101cd3043b94539a2893e77aa9949c8fd9c7acb 100644 (file)
@@ -3727,7 +3727,7 @@ static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha,
        h &= QLA_CMD_HANDLE_MASK;
 
        if (h != QLA_TGT_NULL_HANDLE) {
-               if (unlikely(h > req->num_outstanding_cmds)) {
+               if (unlikely(h >= req->num_outstanding_cmds)) {
                        ql_dbg(ql_dbg_tgt, vha, 0xe052,
                            "qla_target(%d): Wrong handle %x received\n",
                            vha->vp_idx, handle);
index 21225d62b0c1f4424bc72f57f8daf109cabffb7e..1e82d4128a84800d3f96011c49e0b3fc12c55d8e 100644 (file)
@@ -758,8 +758,11 @@ static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
                if (hp->dxferp || hp->dxfer_len > 0)
                        return false;
                return true;
-       case SG_DXFER_TO_DEV:
        case SG_DXFER_FROM_DEV:
+               if (hp->dxfer_len < 0)
+                       return false;
+               return true;
+       case SG_DXFER_TO_DEV:
        case SG_DXFER_TO_FROM_DEV:
                if (!hp->dxferp || hp->dxfer_len == 0)
                        return false;
index 8b93197daefe33c2330377dcac7dcf6d8c46c048..9be211d68b1596b4a9b482fa4e17888b6f559e39 100644 (file)
@@ -837,6 +837,7 @@ static struct scsi_host_template virtscsi_host_template_multi = {
        .eh_abort_handler = virtscsi_abort,
        .eh_device_reset_handler = virtscsi_device_reset,
        .eh_timed_out = virtscsi_eh_timed_out,
+       .slave_alloc = virtscsi_device_alloc,
 
        .can_queue = 1024,
        .dma_boundary = UINT_MAX,