---
 drivers/scsi/lpfc/lpfc.h         |  41 ++++
 drivers/scsi/lpfc/lpfc_attr.c    |  65 ++++++-
 drivers/scsi/lpfc/lpfc_crtn.h    |   3 +-
 drivers/scsi/lpfc/lpfc_hbadisc.c |   3 +
 drivers/scsi/lpfc/lpfc_init.c    |  24 ++-
 drivers/scsi/lpfc/lpfc_mbox.c    |   4 +-
 drivers/scsi/lpfc/lpfc_scsi.c    | 410 ++++++++++++++++++++++++++++++++++++---
 drivers/scsi/lpfc/lpfc_scsi.h    |   7 +-
 drivers/scsi/lpfc/lpfc_sli.c     |  36 ++--
 9 files changed, 532 insertions(+), 61 deletions(-)

diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 922e59d..e192c2d 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -295,6 +295,42 @@ enum hba_state {
        LPFC_HBA_ERROR       =  -1
 };
 
+/* Structure used to identify all devices controlled
+ * by the External DIF logic.
+ */
+struct lpfc_external_dif_support {
+       struct list_head listentry;
+       struct lpfc_name portName;
+       uint64_t lun;
+       uint16_t sid;
+       uint8_t dif_info;
+       uint8_t reserved1;
+};
+
+/* Struct used to identify External DIF vendor specific info */
+struct lpfc_vendor_dif {
+       uint8_t length;
+       uint8_t version;
+       uint8_t dif_info;
+#define LPFC_FDIF_ATO          0x01
+#define LPFC_FDIF_REFCHK       0x02
+#define LPFC_FDIF_APPCHK       0x04
+#define LPFC_FDIF_GRDCHK       0x08
+#define LPFC_FDIF_SPTMASK      0x70
+#define LPFC_FDIF_PROTECT      0x80
+       uint8_t reserved1;
+};
+
+/* Defines used to identify a External DIF device */
+#define LPFC_INQ_VID_OFFSET    8
+#define LPFC_INQ_VDIF_OFFSET   168
+#define LPFC_INQ_FDIF_SZ       (LPFC_INQ_VDIF_OFFSET + 4)
+#define LPFC_INQ_FDIF_VENDOR   "3PARdata"      /* Vendor Identification */
+#define LPFC_INQ_FDIF_VERSION  1
+#define LPFC_INQ_FDIF_SIZE     2
+#define LPFC_FDIF_CDB_PROTECT  0x20            /* Set RD/WR PROTECT = 001 */
+
+
 struct lpfc_vport {
        struct lpfc_hba *phba;
        struct list_head listentry;
@@ -441,6 +477,10 @@ struct lpfc_vport {
        unsigned long rcv_buffer_time_stamp;
        uint32_t vport_flag;
 #define STATIC_VPORT   1
+
+       /* Used to discover External DIF devices */
+       struct list_head external_dif_list;
+       spinlock_t external_dif_lock;   /* lock for external_dif_list */
 };
 
 struct hbq_s {
@@ -739,6 +779,7 @@ struct lpfc_hba {
 #define OAS_LUN_VALID  0x04
        uint32_t cfg_XLanePriority;
        uint32_t cfg_enable_bg;
+       uint32_t cfg_external_dif;
        uint32_t cfg_hostmem_hgp;
        uint32_t cfg_log_verbose;
        uint32_t cfg_aer_support;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index faf0e8c..891e2d1 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -135,16 +135,29 @@ lpfc_bg_info_show(struct device *dev, struct 
device_attribute *attr,
        struct Scsi_Host *shost = class_to_shost(dev);
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
        struct lpfc_hba   *phba = vport->phba;
+       int len = 0;
 
-       if (phba->cfg_enable_bg)
+       if (phba->cfg_enable_bg) {
                if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
-                       return snprintf(buf, PAGE_SIZE, "BlockGuard Enabled\n");
+                       len +=  snprintf(buf, PAGE_SIZE,
+                                        "BlockGuard Enabled\n");
                else
-                       return snprintf(buf, PAGE_SIZE,
+                       len +=  snprintf(buf, PAGE_SIZE,
                                        "BlockGuard Not Supported\n");
-       else
-                       return snprintf(buf, PAGE_SIZE,
+       } else {
+                       len +=  snprintf(buf, PAGE_SIZE,
                                        "BlockGuard Disabled\n");
+       }
+
+       if (phba->cfg_external_dif) {
+               if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
+                       len += snprintf(buf + len, PAGE_SIZE,
+                                       "External DIF Enabled\n");
+               else
+                       len += snprintf(buf + len, PAGE_SIZE,
+                                       "External DIF Not Supported\n");
+       }
+       return len;
 }
 
 static ssize_t
@@ -4681,6 +4694,30 @@ LPFC_ATTR_R(EnableXLane, 0, 0, 1, "Enable Express Lane 
Feature.");
 */
 LPFC_ATTR_RW(XLanePriority, 0, 0x0, 0x7f, "CS_CTL for Express Lane Feature.");
 
+
+/*
+ * For T10 DIF / protection data support, the driver supports 4 modes
+ * of operation.
+ *
+ * Mode 1: (lpfc_enable_bg=1 lpfc_external_dif=1)
+ * All normal T10 DIF devices are supported.
+ * External DIF devices are supported.
+ *
+ * Mode 2: (lpfc_enable_bg=0 lpfc_external_dif=1)
+ * If you don't want to have the extra overhead of the upper SCSI Layer
+ * supporting T10-DIF, but you still want to support External DIF devices.
+ * Normal T10 DIF devices are NOT supported.
+ * External DIF devices are supported.
+ *
+ * Mode 3: (lpfc_enable_bg=1 lpfc_external_dif=0)
+ * All normal T10 DIF devices are supported.
+ * External DIF devices are NOT supported.
+ *
+ * Mode 4: (lpfc_enable_bg=0 lpfc_external_dif=1)
+ * No normal T10-DIF and no external DIF devices supported,
+ * This would be the driver default values for these module parameters.
+ */
+
 /*
 # lpfc_enable_bg: Enable BlockGuard (Emulex's Implementation of T10-DIF)
 #       0  = BlockGuard disabled (default)
@@ -4690,6 +4727,15 @@ LPFC_ATTR_RW(XLanePriority, 0, 0x0, 0x7f, "CS_CTL for 
Express Lane Feature.");
 LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support");
 
 /*
+# lpfc_external_dif: Enable External DIF support on select devices
+#       0  = External DIF disabled (default)
+#       1  = External DIF enabled
+# Value range is [0,1]. Default value is 0.
+*/
+LPFC_ATTR_R(external_dif, 0, 0, 1,
+           "External T10-DIF Support, on select devices");
+
+/*
 # lpfc_fcp_look_ahead: Look ahead for completions in FCP start routine
 #       0  = disabled (default)
 #       1  = enabled
@@ -4703,7 +4749,7 @@ unsigned int lpfc_fcp_look_ahead = LPFC_LOOK_AHEAD_OFF;
 # lpfc_prot_mask: i
 #      - Bit mask of host protection capabilities used to register with the
 #        SCSI mid-layer
-#      - Only meaningful if BG is turned on (lpfc_enable_bg=1).
+#      - Only meaningful if BG is turned on, lpfc_enable_bg = 1
 #      - Allows you to ultimately specify which profiles to use
 #      - Default will result in registering capabilities for all profiles.
 #      - SHOST_DIF_TYPE1_PROTECTION    1
@@ -4726,6 +4772,7 @@ MODULE_PARM_DESC(lpfc_prot_mask, "host protection mask");
 #      - Bit mask of protection guard types to register with the SCSI mid-layer
 #      - Guard types are currently either 1) T10-DIF CRC 2) IP checksum
 #      - Allows you to ultimately specify which profiles to use
+#      - Only meaningful if BG is turned on, lpfc_enable_bg = 1
 #      - Default will result in registering capabilities for all guard types
 #
 */
@@ -4837,6 +4884,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_fcp_cpu_map,
        &dev_attr_lpfc_fcp_io_channel,
        &dev_attr_lpfc_enable_bg,
+       &dev_attr_lpfc_external_dif,
        &dev_attr_lpfc_soft_wwnn,
        &dev_attr_lpfc_soft_wwpn,
        &dev_attr_lpfc_soft_wwn_enable,
@@ -5839,6 +5887,11 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        phba->cfg_oas_lun_status = 0;
        phba->cfg_oas_flags = 0;
        lpfc_enable_bg_init(phba, lpfc_enable_bg);
+       lpfc_external_dif_init(phba, lpfc_external_dif);
+
+       if (phba->cfg_enable_bg || phba->cfg_external_dif)
+               phba->sli3_options |= LPFC_SLI3_BG_ENABLED;
+
        if (phba->sli_rev == LPFC_SLI_REV4)
                phba->cfg_poll = 0;
        else
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index dd01ea8..a7b4fc7 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -366,7 +366,8 @@ extern int lpfc_delay_discovery;
 int  lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
 int  lpfc_vport_symbolic_port_name(struct lpfc_vport *, char *,        size_t);
 void lpfc_terminate_rport_io(struct fc_rport *);
-void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport);
+void lpfc_dev_loss_tmo_callbk(struct fc_rport *);
+void lpfc_external_dif_cleanup(struct lpfc_vport *, struct lpfc_name *);
 
 struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct device *);
 int  lpfc_vport_disable(struct fc_vport *fc_vport, bool disable);
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 2a51df7..17da14e 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -143,6 +143,9 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
                return;
        }
 
+       /* Cleanup all External DIF devices that match this rports WWPN */
+       lpfc_external_dif_cleanup(vport, &ndlp->nlp_portname);
+
        if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
                return;
 
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index afaa45d..78345a8 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -154,8 +154,6 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
                       sizeof(phba->wwpn));
        }
 
-       phba->sli3_options = 0x0;
-
        /* Setup and issue mailbox READ REV command */
        lpfc_read_rev(phba, pmb);
        rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
@@ -2523,6 +2521,7 @@ lpfc_cleanup(struct lpfc_vport *vport)
 {
        struct lpfc_hba   *phba = vport->phba;
        struct lpfc_nodelist *ndlp, *next_ndlp;
+       struct lpfc_external_dif_support *dp, *next_dp;
        int i = 0;
 
        if (phba->link_state > LPFC_LINK_DOWN)
@@ -2600,6 +2599,15 @@ lpfc_cleanup(struct lpfc_vport *vport)
                msleep(10);
        }
        lpfc_cleanup_vports_rrqs(vport, NULL);
+
+       /* Cleanup any discovered External DIF devices for this vport */
+       list_for_each_entry_safe(dp, next_dp, &vport->external_dif_list,
+                                listentry) {
+               spin_lock_irq(&vport->external_dif_lock);
+               list_del(&dp->listentry);
+               spin_unlock_irq(&vport->external_dif_lock);
+               kfree(dp);
+       }
 }
 
 /**
@@ -3348,6 +3356,10 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, 
struct device *dev)
        if (error)
                goto out_put_shost;
 
+       /* Initialize objects used to discover External DIF devices */
+       INIT_LIST_HEAD(&vport->external_dif_list);
+       spin_lock_init(&vport->external_dif_lock);
+
        spin_lock_irq(&phba->hbalock);
        list_add_tail(&vport->listentry, &phba->port_list);
        spin_unlock_irq(&phba->hbalock);
@@ -4992,7 +5004,7 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
        lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt;
 
        /* There are going to be 2 reserved BDEs: 1 FCP cmnd + 1 FCP rsp */
-       if (phba->cfg_enable_bg) {
+       if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
                /*
                 * The scsi_buf for a T10-DIF I/O will hold the FCP cmnd,
                 * the FCP rsp, and a BDE for each. Sice we have no control
@@ -5185,7 +5197,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
         * used to create the sg_dma_buf_pool must be dynamically calculated.
         */
 
-       if (phba->cfg_enable_bg) {
+       if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
                /*
                 * The scsi_buf for a T10-DIF I/O will hold the FCP cmnd,
                 * the FCP rsp, and a SGE for each. Sice we have no control
@@ -6286,7 +6298,9 @@ lpfc_post_init_setup(struct lpfc_hba *phba)
         */
        shost = pci_get_drvdata(phba->pcidev);
        shost->can_queue = phba->cfg_hba_queue_depth - 10;
-       if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
+
+       /* Setup T10-DIF interface with SCSI Layer API */
+       if (phba->cfg_enable_bg)
                lpfc_setup_bg(phba, shost);
 
        lpfc_host_attrib_init(shost);
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 06241f5..702283e 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -1280,7 +1280,7 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        /* If HBA supports SLI=3 ask for it */
 
        if (phba->sli_rev == LPFC_SLI_REV3 && phba->vpd.sli3Feat.cerbm) {
-               if (phba->cfg_enable_bg)
+               if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
                        mb->un.varCfgPort.cbg = 1; /* configure BlockGuard */
                if (phba->cfg_enable_dss)
                        mb->un.varCfgPort.cdss = 1; /* Configure Security */
@@ -2071,7 +2071,7 @@ lpfc_request_features(struct lpfc_hba *phba, struct 
lpfcMboxq *mboxq)
        bf_set(lpfc_mbx_rq_ftr_rq_perfh, &mboxq->u.mqe.un.req_ftrs, 1);
 
        /* Enable DIF (block guard) only if configured to do so. */
-       if (phba->cfg_enable_bg)
+       if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
                bf_set(lpfc_mbx_rq_ftr_rq_dif, &mboxq->u.mqe.un.req_ftrs, 1);
 
        /* Enable NPIV only if configured to do so. */
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 5612ba6..9ed5f44 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -80,6 +80,9 @@ lpfc_rport_data_from_scsi_device(struct scsi_device *sdev)
 }
 
 static void
+lpfc_external_dif(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
+                 uint8_t *cdb_ptr);
+static void
 lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
 static void
 lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
@@ -564,7 +567,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
                &phba->sli4_hba.lpfc_abts_scsi_buf_list, list) {
                if (psb->cur_iocbq.sli4_xritag == xri) {
                        list_del(&psb->list);
-                       psb->exch_busy = 0;
+                       psb->flags &= ~LPFC_SBUF_XBUSY;
                        psb->status = IOSTAT_SUCCESS;
                        spin_unlock(
                                &phba->sli4_hba.abts_scsi_buf_list_lock);
@@ -596,7 +599,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
                if (iocbq->sli4_xritag != xri)
                        continue;
                psb = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq);
-               psb->exch_busy = 0;
+               psb->flags &= ~LPFC_SBUF_XBUSY;
                spin_unlock_irqrestore(&phba->hbalock, iflag);
                if (!list_empty(&pring->txq))
                        lpfc_worker_wake_up(phba);
@@ -683,10 +686,10 @@ lpfc_sli4_post_scsi_sgl_list(struct lpfc_hba *phba,
                                                psb->cur_iocbq.sli4_xritag);
                                if (status) {
                                        /* failure, put on abort scsi list */
-                                       psb->exch_busy = 1;
+                                       psb->flags |= LPFC_SBUF_XBUSY;
                                } else {
                                        /* success, put on SCSI buffer list */
-                                       psb->exch_busy = 0;
+                                       psb->flags &= ~LPFC_SBUF_XBUSY;
                                        psb->status = IOSTAT_SUCCESS;
                                        num_posted++;
                                }
@@ -716,10 +719,10 @@ lpfc_sli4_post_scsi_sgl_list(struct lpfc_hba *phba,
                                         struct lpfc_scsi_buf, list);
                        if (status) {
                                /* failure, put on abort scsi list */
-                               psb->exch_busy = 1;
+                               psb->flags |= LPFC_SBUF_XBUSY;
                        } else {
                                /* success, put on SCSI buffer list */
-                               psb->exch_busy = 0;
+                               psb->flags &= ~LPFC_SBUF_XBUSY;
                                psb->status = IOSTAT_SUCCESS;
                                num_posted++;
                        }
@@ -833,7 +836,8 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int 
num_to_alloc)
                 * 4K Page alignment is CRITICAL to BlockGuard, double check
                 * to be sure.
                 */
-               if (phba->cfg_enable_bg  && (((unsigned long)(psb->data) &
+               if ((phba->sli3_options & LPFC_SLI3_BG_ENABLED) &&
+                   (((unsigned long)(psb->data) &
                    (unsigned long)(SLI4_PAGE_SIZE - 1)) != 0)) {
                        pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
                                      psb->data, psb->dma_handle);
@@ -1097,7 +1101,7 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct 
lpfc_scsi_buf *psb)
        psb->nonsg_phys = 0;
        psb->prot_seg_cnt = 0;
 
-       if (psb->exch_busy) {
+       if (psb->flags & LPFC_SBUF_XBUSY) {
                spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock,
                                        iflag);
                psb->pCmd = NULL;
@@ -1125,7 +1129,7 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct 
lpfc_scsi_buf *psb)
 static void
 lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
 {
-
+       psb->flags &= ~(LPFC_SBUF_NORMAL_DIF | LPFC_SBUF_PASS_DIF);
        phba->lpfc_release_scsi_buf(phba, psb);
 }
 
@@ -1267,6 +1271,38 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct 
lpfc_scsi_buf *lpfc_cmd)
        return 0;
 }
 
+/**
+ * lpfc_scsi_get_prot_op - Gets the SCSI defined protection data operation
+ * @sc: The SCSI Layer structure for the IO in question.
+ *
+ * This routine calls the SCSI Layer to get the protectio data operation
+ * associated with the specified IO. Then, if this is an IO effected by an
+ * External DIF device, the protection operation is adjusted accordingly.
+ *
+ * Returns the SCSI defined protection data operation
+ **/
+uint32_t
+lpfc_scsi_get_prot_op(struct scsi_cmnd *sc)
+{
+       struct lpfc_scsi_buf *lpfc_cmd;
+       uint32_t op = scsi_get_prot_op(sc);
+
+       lpfc_cmd = (struct lpfc_scsi_buf *)sc->host_scribble;
+       if (lpfc_cmd->flags & LPFC_SBUF_NORMAL_DIF) {
+               if (sc->sc_data_direction == DMA_FROM_DEVICE)
+                       op = SCSI_PROT_READ_STRIP;
+               else if (sc->sc_data_direction == DMA_TO_DEVICE)
+                       op = SCSI_PROT_WRITE_INSERT;
+       } else if (lpfc_cmd->flags & LPFC_SBUF_PASS_DIF) {
+               if (sc->sc_data_direction == DMA_FROM_DEVICE)
+                       op = SCSI_PROT_READ_PASS;
+               else if (sc->sc_data_direction == DMA_TO_DEVICE)
+                       op = SCSI_PROT_WRITE_PASS;
+       }
+       return op;
+}
+
+
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
 
 /* Return if if error injection is detected by Initiator */
@@ -1298,7 +1334,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct 
scsi_cmnd *sc,
        struct scsi_dif_tuple *src = NULL;
        struct lpfc_nodelist *ndlp;
        struct lpfc_rport_data *rdata;
-       uint32_t op = scsi_get_prot_op(sc);
+       uint32_t op = lpfc_scsi_get_prot_op(sc);
        uint32_t blksize;
        uint32_t numblks;
        sector_t lba;
@@ -1702,7 +1738,7 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct 
scsi_cmnd *sc,
        uint8_t ret = 0;
 
        if (lpfc_cmd_guard_csum(sc)) {
-               switch (scsi_get_prot_op(sc)) {
+               switch (lpfc_scsi_get_prot_op(sc)) {
                case SCSI_PROT_READ_INSERT:
                case SCSI_PROT_WRITE_STRIP:
                        *rxop = BG_OP_IN_NODIF_OUT_CSUM;
@@ -1725,13 +1761,13 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct 
scsi_cmnd *sc,
                default:
                        lpfc_printf_log(phba, KERN_ERR, LOG_BG,
                                "9063 BLKGRD: Bad op/guard:%d/IP combination\n",
-                                       scsi_get_prot_op(sc));
+                                       lpfc_scsi_get_prot_op(sc));
                        ret = 1;
                        break;
 
                }
        } else {
-               switch (scsi_get_prot_op(sc)) {
+               switch (lpfc_scsi_get_prot_op(sc)) {
                case SCSI_PROT_READ_STRIP:
                case SCSI_PROT_WRITE_INSERT:
                        *rxop = BG_OP_IN_CRC_OUT_NODIF;
@@ -1754,7 +1790,7 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct 
scsi_cmnd *sc,
                default:
                        lpfc_printf_log(phba, KERN_ERR, LOG_BG,
                                "9075 BLKGRD: Bad op/guard:%d/CRC 
combination\n",
-                                       scsi_get_prot_op(sc));
+                                       lpfc_scsi_get_prot_op(sc));
                        ret = 1;
                        break;
                }
@@ -1782,7 +1818,7 @@ lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct 
scsi_cmnd *sc,
        uint8_t ret = 0;
 
        if (lpfc_cmd_guard_csum(sc)) {
-               switch (scsi_get_prot_op(sc)) {
+               switch (lpfc_scsi_get_prot_op(sc)) {
                case SCSI_PROT_READ_INSERT:
                case SCSI_PROT_WRITE_STRIP:
                        *rxop = BG_OP_IN_NODIF_OUT_CRC;
@@ -1807,7 +1843,7 @@ lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct 
scsi_cmnd *sc,
 
                }
        } else {
-               switch (scsi_get_prot_op(sc)) {
+               switch (lpfc_scsi_get_prot_op(sc)) {
                case SCSI_PROT_READ_STRIP:
                case SCSI_PROT_WRITE_INSERT:
                        *rxop = BG_OP_IN_CSUM_OUT_NODIF;
@@ -2628,7 +2664,7 @@ static int
 lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc)
 {
        int ret = LPFC_PG_TYPE_INVALID;
-       unsigned char op = scsi_get_prot_op(sc);
+       unsigned char op = lpfc_scsi_get_prot_op(sc);
 
        switch (op) {
        case SCSI_PROT_READ_STRIP:
@@ -2673,12 +2709,12 @@ lpfc_bg_scsi_adjust_dl(struct lpfc_hba *phba,
        /* Check if there is protection data on the wire */
        if (sc->sc_data_direction == DMA_FROM_DEVICE) {
                /* Read check for protection data */
-               if (scsi_get_prot_op(sc) ==  SCSI_PROT_READ_INSERT)
+               if (lpfc_scsi_get_prot_op(sc) ==  SCSI_PROT_READ_INSERT)
                        return fcpdl;
 
        } else {
                /* Write check for protection data */
-               if (scsi_get_prot_op(sc) ==  SCSI_PROT_WRITE_STRIP)
+               if (lpfc_scsi_get_prot_op(sc) ==  SCSI_PROT_WRITE_STRIP)
                        return fcpdl;
        }
 
@@ -2895,7 +2931,7 @@ lpfc_calc_bg_err(struct lpfc_hba *phba, struct 
lpfc_scsi_buf *lpfc_cmd)
        guard_tag = 0;
 
        /* First check to see if there is protection data to examine */
-       prot = scsi_get_prot_op(cmd);
+       prot = lpfc_scsi_get_prot_op(cmd);
        if ((prot == SCSI_PROT_READ_STRIP) ||
            (prot == SCSI_PROT_WRITE_INSERT) ||
            (prot == SCSI_PROT_NORMAL))
@@ -3177,7 +3213,7 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct 
lpfc_scsi_buf *lpfc_cmd,
                cmd->sense_buffer[10] = 0x80; /* Validity bit */
 
                /* bghm is a "on the wire" FC frame based count */
-               switch (scsi_get_prot_op(cmd)) {
+               switch (lpfc_scsi_get_prot_op(cmd)) {
                case SCSI_PROT_READ_INSERT:
                case SCSI_PROT_WRITE_STRIP:
                        bghm /= cmd->device->sector_size;
@@ -3459,7 +3495,7 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba,
                }
        }
 
-       switch (scsi_get_prot_op(scsi_cmnd)) {
+       switch (lpfc_scsi_get_prot_op(scsi_cmnd)) {
        case SCSI_PROT_WRITE_STRIP:
        case SCSI_PROT_READ_STRIP:
                lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_DIF_STRIP;
@@ -3693,6 +3729,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct 
lpfc_scsi_buf *lpfc_cmd,
        uint32_t host_status = DID_OK;
        uint32_t rsplen = 0;
        uint32_t logit = LOG_FCP | LOG_FCP_ERROR;
+       uint8_t  asc, ascq;
 

        /*
@@ -3840,7 +3877,16 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct 
lpfc_scsi_buf *lpfc_cmd,
                scsi_set_resid(cmnd, scsi_bufflen(cmnd));
        }
 
- out:
+out:
+       if (vport->phba->cfg_external_dif &&
+           (lpfc_cmd->flags & (LPFC_SBUF_NORMAL_DIF | LPFC_SBUF_PASS_DIF))) {
+               asc = cmnd->sense_buffer[12];
+               ascq = cmnd->sense_buffer[13];
+               /* Check for LOGICAL BLOCK GUARD CHECK / REF TAG failed */
+               if ((scsi_status == SAM_STAT_CHECK_CONDITION) &&
+                   (asc == 0x10) && ((ascq == 1) || (ascq == 3)))
+                       host_status = DID_ERROR; /* Convert to retryable err */
+       }
        cmnd->result = ScsiResult(host_status, scsi_status);
        lpfc_send_scsi_error_event(vport->phba, vport, lpfc_cmd, rsp_iocb);
 }
@@ -3882,7 +3928,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct 
lpfc_iocbq *pIocbIn,
        lpfc_cmd->result = (pIocbOut->iocb.un.ulpWord[4] & IOERR_PARAM_MASK);
        lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
        /* pick up SLI4 exhange busy status from HBA */
-       lpfc_cmd->exch_busy = pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY;
+       if (pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY)
+               lpfc_cmd->flags |= LPFC_SBUF_XBUSY;
+       else
+               lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY;
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
        if (lpfc_cmd->prot_data_type) {
@@ -4001,7 +4050,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct 
lpfc_iocbq *pIocbIn,
                        if ((lpfc_cmd->result == IOERR_RX_DMA_FAILED ||
                             lpfc_cmd->result == IOERR_TX_DMA_FAILED) &&
                             pIocbOut->iocb.unsli3.sli3_bg.bgstat) {
-                               if (scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
+                               if (lpfc_scsi_get_prot_op(cmd) !=
+                                   SCSI_PROT_NORMAL) {
                                        /*
                                         * This is a response for a BG enabled
                                         * cmd. Parse BG error
@@ -4184,6 +4234,10 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct 
lpfc_scsi_buf *lpfc_cmd,
                memset(ptr, 0, (LPFC_FCP_CDB_LEN - scsi_cmnd->cmd_len));
        }
 
+       /* Check if we want to make this IO an External DIF device */
+       if (vport->phba->cfg_external_dif)
+               lpfc_external_dif(vport, lpfc_cmd, &fcp_cmnd->fcpCdb[0]);
+
        fcp_cmnd->fcpCntl1 = SIMPLE_Q;
 
        sli4 = (phba->sli_rev == LPFC_SLI_REV4);
@@ -4241,7 +4295,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct 
lpfc_scsi_buf *lpfc_cmd,
 
        piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f);
        piocbq->context1  = lpfc_cmd;
-       piocbq->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl;
+       if (piocbq->iocb_cmpl == NULL)
+               piocbq->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl;
        piocbq->iocb.ulpTimeout = lpfc_cmd->timeout;
        piocbq->vport = vport;
 }
@@ -4481,6 +4536,296 @@ void lpfc_poll_timeout(unsigned long ptr)
 }
 
 /**
+ * lpfc_external_dif_cleanup - Clean up a specific External DIF device
+ * @vport: The virtual port for which this call is being executed.
+ * @pname WWPN to match
+ *
+ * This routine scans the discovered External DIF devices for the vport
+ * for a match using the targets WWPN. All luns matching that WWPN will be
+ * removed. This routine is called when dev_loss for a target is envoked.
+ **/
+void
+lpfc_external_dif_cleanup(struct lpfc_vport *vport, struct lpfc_name *pname)
+{
+       struct lpfc_external_dif_support *dp, *next_dp;
+       unsigned long flags;
+       uint8_t *name;
+
+       spin_lock_irqsave(&vport->external_dif_lock, flags);
+       list_for_each_entry_safe(dp, next_dp, &vport->external_dif_list,
+                                listentry) {
+               name = (uint8_t *)&dp->portName;
+               if (memcmp(name, (uint8_t *)pname,
+                          sizeof(struct lpfc_name)) == 0) {
+                       list_del(&dp->listentry);
+                       lpfc_printf_log(vport->phba, KERN_WARNING, LOG_BG,
+                                       "0701 Remove External DIF device "
+                                       "scsi_id x%x: lun_id x%llx: WWPN "
+                                       "%02x:%02x:%02x:%02x:"
+                                       "%02x:%02x:%02x:%02x\n",
+                                       dp->sid, dp->lun,
+                                       *name, *(name+1), *(name+2), *(name+3),
+                                       *(name+4), *(name+5), *(name+6),
+                                       *(name+7));
+                       kfree(dp);
+               }
+       }
+       spin_unlock_irqrestore(&vport->external_dif_lock, flags);
+}
+
+/**
+ * lpfc_external_dif_match - Look up a specific External DIF device
+ * @vport: The virtual port for which this call is being executed.
+ * @lun: lun id used to specify the desired External DIF device
+ * @sid: SCSI id used to specify the desired External DIF device
+ *
+ * This routine scans the discovered External DIF devices for the vport
+ * for a match using the lun/sid criteria.
+ *
+ * Return code :
+ *   NULL - device not found
+ *   dp   - struct lpfc_external_dif_support of matching device
+ **/
+struct lpfc_external_dif_support *
+lpfc_external_dif_match(struct lpfc_vport *vport, uint64_t lun, uint32_t sid)
+{
+       struct lpfc_external_dif_support *dp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vport->external_dif_lock, flags);
+       list_for_each_entry(dp, &vport->external_dif_list, listentry) {
+               if ((dp->sid == sid) && (dp->lun == lun)) {
+                       spin_unlock_irqrestore(&vport->external_dif_lock,
+                                              flags);
+                       return dp;
+               }
+       }
+       spin_unlock_irqrestore(&vport->external_dif_lock, flags);
+       return NULL;
+}
+
+/**
+ * lpfc_external_dif_cmpl - IOCB completion routine for a External DIF IO
+ * @phba: The Hba for which this call is being executed.
+ * @pIocbIn: The command IOCBQ for the scsi cmnd.
+ * @pIocbOut: The response IOCBQ for the scsi cmnd.
+ *
+ * This routine processes the External DIF SCSi command cmpl before calling the
+ * normal SCSI cmpl routine (lpfc_scsi_cmd_iocb_cmpl). There are 2 types of
+ * External DIF completions, INQUIRY and READ/WRITE SCSI commands.
+ *
+ * We use INQUIRY to discover External DIF devices. An External DIF device does
+ * not advertise itself as T10-DIF capable using standard bits in the INQUIRY
+ * and READ_CAPACITY commands. Instead, it uses some vendor specific
+ * information in the standard INQUIRY command to turn on this feature.
+ *
+ * For READ/WRITE IOs we convert the IO back into a normal IO so it can be
+ * completed to the SCSI layer. The SCSI layer is unaware the IO was actually
+ * transmitted on the wire in T10 DIF Type 1 format.
+ **/
+static void
+lpfc_external_dif_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
+                      struct lpfc_iocbq *pIocbOut)
+{
+       struct lpfc_scsi_buf *lpfc_cmd =
+               (struct lpfc_scsi_buf *)pIocbIn->context1;
+       struct lpfc_vport *vport = pIocbIn->vport;
+       struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
+       uint32_t resp_info = fcprsp->rspStatus2;
+       struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
+       uint32_t status = pIocbOut->iocb.ulpStatus;
+       struct lpfc_rport_data *rdata;
+       struct lpfc_nodelist *pnode;
+       struct lpfc_external_dif_support *dp;
+       struct lpfc_vendor_dif *vendor_dif_infop;
+       struct fcp_cmnd *fcpcmd;
+       struct scsi_device *sdev;
+       struct scatterlist *sgde;
+       unsigned long flags;
+       uint8_t *data_inq;
+       uint8_t *name;
+       uint32_t cnt;
+
+       if (status) {
+               if ((status != IOSTAT_FCP_RSP_ERROR) ||
+                   !(resp_info & RESID_UNDER))
+                       goto out;
+       }
+
+       /* Only success and RESID_UNDER make it here */
+       switch (cmnd->cmnd[0]) {
+       case INQUIRY:
+               fcpcmd = lpfc_cmd->fcp_cmnd;
+               sgde = scsi_sglist(cmnd);
+               data_inq = (uint8_t *)sg_virt(sgde);
+
+               /* Make sure the INQUIRY payload has our
+                * vendor specific info included.
+                */
+               cnt = be32_to_cpu(fcpcmd->fcpDl) -
+                       be32_to_cpu(fcprsp->rspResId);
+               if (cnt < LPFC_INQ_FDIF_SZ)
+                       break;
+
+               /* Jump to T10 Vendor Identification field */
+               data_inq += LPFC_INQ_VID_OFFSET;
+               if ((memcmp(data_inq, LPFC_INQ_FDIF_VENDOR,
+                           sizeof(LPFC_INQ_FDIF_VENDOR) != 0)))
+                       break;
+
+               sdev = cmnd->device;
+               if (lpfc_external_dif_match(vport, sdev->lun, sdev->id))
+                       break; /* device already exists */
+
+               /* Jump to Vendor specific DIF info */
+               vendor_dif_infop = (struct lpfc_vendor_dif *)(data_inq +
+                       (LPFC_INQ_VDIF_OFFSET - LPFC_INQ_VID_OFFSET));
+
+               /* Check to see if External DIF protection is enabled and we
+                * are version 1. Currently we only support DIF Type 1
+                * (GRD_CHK / REF_CHK)
+                */
+               if ((vendor_dif_infop->length != LPFC_INQ_FDIF_SIZE) ||
+                   (vendor_dif_infop->version != LPFC_INQ_FDIF_VERSION) ||
+                   (vendor_dif_infop->dif_info != (LPFC_FDIF_PROTECT |
+                   LPFC_FDIF_REFCHK |  LPFC_FDIF_GRDCHK))) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_BG,
+                                       "0709 External DIF Vendor info error "
+                                       "Data: %02x %02x %02x\n",
+                                       vendor_dif_infop->length,
+                                       vendor_dif_infop->version,
+                                       vendor_dif_infop->dif_info);
+                       break;
+               }
+
+               /* New External DIF device found */
+               dp = kmalloc(sizeof(struct lpfc_external_dif_support),
+                            GFP_ATOMIC);
+               if (!dp)
+                       break;
+               dp->lun = sdev->lun;
+               dp->sid = sdev->id;
+               dp->dif_info = vendor_dif_infop->dif_info;
+
+               rdata = lpfc_cmd->rdata;
+               pnode = rdata->pnode;
+               memcpy(&dp->portName, &pnode->nlp_portname,
+                      sizeof(struct lpfc_name));
+
+               spin_lock_irqsave(&vport->external_dif_lock, flags);
+               list_add_tail(&dp->listentry, &vport->external_dif_list);
+               spin_unlock_irqrestore(&vport->external_dif_lock, flags);
+
+               name = (uint8_t *)&pnode->nlp_portname;
+               lpfc_printf_log(phba, KERN_WARNING, LOG_BG,
+                               "0712 Discovered External DIF device NPortId "
+                               "x%x: scsi_id x%x: lun_id x%llx: WWPN "
+                               "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+                               pnode->nlp_DID, dp->sid, dp->lun,
+                               *name, *(name+1), *(name+2), *(name+3),
+                               *(name+4), *(name+5), *(name+6), *(name+7));
+               break;
+       case READ_10:
+       case READ_12:
+       case READ_16:
+       case WRITE_10:
+       case WRITE_12:
+       case WRITE_16:
+       case WRITE_SAME:
+       case WRITE_SAME_16:
+       case WRITE_VERIFY:
+               break;
+       default:
+               break;
+       }
+out:
+       lpfc_scsi_cmd_iocb_cmpl(phba, pIocbIn, pIocbOut);
+}
+
+/**
+ * lpfc_external_dif - Check to see if we want to process this IO as a 
External DIF
+ * @vport: The virtual port for which this call is being executed.
+ * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure.
+ *
+ * This routine will selectively force normal IOs to be processed as a
+ * READ_STRIP / WRITE_INSERT T10-DIF IO. The upper SCSI Layer will be unaware
+ * that the IO is going to be transmitted on the wire with T10-DIF protection
+ * data. This routine also diverts INQUIRY command cmpletions so they can be
+ * used to scan for External DIF devices.
+ **/
+static void
+lpfc_external_dif(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
+                 uint8_t *cdb_ptr)
+{
+       struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
+       struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq);
+       struct scsi_device *sdev;
+
+       switch (scsi_get_prot_op(cmnd)) {
+       case SCSI_PROT_NORMAL:
+       case SCSI_PROT_READ_INSERT:
+       case SCSI_PROT_WRITE_STRIP:
+               break;
+       default:
+               return;
+       }
+
+       switch (cdb_ptr[0]) {
+       case INQUIRY:
+               /* We are only interested in page 0 */
+               if ((cdb_ptr[1] != 0) || (cdb_ptr[2] != 0))
+                       return;
+
+               /* Divert cmpl to check for a External DIF device */
+               piocbq->iocb_cmpl = lpfc_external_dif_cmpl;
+               return;
+       case READ_10:
+       case READ_12:
+       case READ_16:
+               /* Is this a Force DIF device */
+               sdev = cmnd->device;
+               if (!lpfc_external_dif_match(vport, sdev->lun, sdev->id))
+                       return;
+
+               /* This is an IO for a External DIF device, so set the
+                * appropriate bits so we send protection data on the wire.
+                */
+               cdb_ptr[1] |= LPFC_FDIF_CDB_PROTECT; /* Set RDPROTECT = 001 */
+               piocbq->iocb_cmpl = lpfc_external_dif_cmpl;
+               break;
+       case WRITE_10:
+       case WRITE_12:
+       case WRITE_16:
+       case WRITE_SAME:
+       case WRITE_SAME_16:
+       case WRITE_VERIFY:
+               /* Is this a Force DIF device */
+               sdev = cmnd->device;
+               if (!lpfc_external_dif_match(vport, sdev->lun, sdev->id))
+                       return;
+
+               /* This is an IO for a External DIF device, so set the
+                * appropriate bits so we send protection data on the wire.
+                */
+               cdb_ptr[1] |= LPFC_FDIF_CDB_PROTECT; /* Set WRPROTECT = 001 */
+               piocbq->iocb_cmpl = lpfc_external_dif_cmpl;
+               break;
+       default:
+               return;
+       }
+
+       switch (scsi_get_prot_op(cmnd)) {
+       case SCSI_PROT_NORMAL:
+               lpfc_cmd->flags |= LPFC_SBUF_NORMAL_DIF;
+               break;
+       case SCSI_PROT_READ_INSERT:
+       case SCSI_PROT_WRITE_STRIP:
+               lpfc_cmd->flags |= LPFC_SBUF_PASS_DIF;
+               break;
+       }
+}
+
+/**
  * lpfc_queuecommand - scsi_host_template queuecommand entry point
  * @cmnd: Pointer to scsi_cmnd data structure.
  * @done: Pointer to done routine.
@@ -4551,10 +4896,13 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct 
scsi_cmnd *cmnd)
        lpfc_cmd->rdata = rdata;
        lpfc_cmd->timeout = 0;
        lpfc_cmd->start_time = jiffies;
+       lpfc_cmd->cur_iocbq.iocb_cmpl = NULL;
        cmnd->host_scribble = (unsigned char *)lpfc_cmd;
 
-       if (scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) {
-               if (vport->phba->cfg_enable_bg) {
+       lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);
+
+       if (lpfc_scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) {
+               if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
                        lpfc_printf_vlog(vport,
                                         KERN_INFO, LOG_SCSI_CMD,
                                         "9033 BLKGRD: rcvd %s cmd:x%x "
@@ -4567,7 +4915,7 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct 
scsi_cmnd *cmnd)
                }
                err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd);
        } else {
-               if (vport->phba->cfg_enable_bg) {
+               if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
                        lpfc_printf_vlog(vport,
                                         KERN_INFO, LOG_SCSI_CMD,
                                         "9038 BLKGRD: rcvd PROT_NORMAL cmd: "
@@ -4583,8 +4931,6 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct 
scsi_cmnd *cmnd)
        if (err)
                goto out_host_busy_free_buf;
 
-       lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);
-
        atomic_inc(&ndlp->cmd_pending);
        err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING,
                                  &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
@@ -5109,7 +5455,7 @@ static int
 lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
 {
        struct Scsi_Host  *shost = cmnd->device->host;
-       struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+       struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
        struct lpfc_rport_data *rdata;
        struct lpfc_nodelist *pnode;
        unsigned tgt_id = cmnd->device->id;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index 0389ac1..bb9a455 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -134,7 +134,12 @@ struct lpfc_scsi_buf {
 
        uint32_t timeout;
 
-       uint16_t exch_busy;     /* SLI4 hba reported XB on complete WCQE */
+       uint16_t flags;
+#define LPFC_SBUF_XBUSY                0x1     /* SLI4 hba reported XB on WCQE 
cmpl */
+                                       /* External DIF device IO conversions */
+#define LPFC_SBUF_NORMAL_DIF   0x2     /* normal mode to insert/strip */
+#define LPFC_SBUF_PASS_DIF     0x4     /* insert/strip mode to passthru */
+
        uint16_t status;        /* From IOCB Word 7- ulpStatus */
        uint32_t result;        /* From IOCB Word 4. */
 
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index c76c2a1..066428b 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -4526,7 +4526,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
                phba->sli3_options &= ~(LPFC_SLI3_NPIV_ENABLED |
                                        LPFC_SLI3_HBQ_ENABLED |
                                        LPFC_SLI3_CRP_ENABLED |
-                                       LPFC_SLI3_BG_ENABLED |
                                        LPFC_SLI3_DSS_ENABLED);
                if (rc != MBX_SUCCESS) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -4592,13 +4591,20 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int 
sli_mode)
                phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
                phba->port_gp = phba->mbox->us.s3_pgp.port;
 
-               if (phba->cfg_enable_bg) {
-                       if (pmb->u.mb.un.varCfgPort.gbg)
-                               phba->sli3_options |= LPFC_SLI3_BG_ENABLED;
-                       else
+               /*
+                * If the port cannot support the host's requested features
+                * then turn off the global config parameters to disable the
+                * feature in the driver.  This is not a fatal error.
+                */
+               if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
+                       if (pmb->u.mb.un.varCfgPort.gbg == 0) {
+                               phba->cfg_enable_bg = 0;
+                               phba->cfg_external_dif = 0;
+                               phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED;
                                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                                "0443 Adapter did not grant "
                                                "BlockGuard\n");
+                       }
                }
        } else {
                phba->hbq_get = NULL;
@@ -4689,7 +4695,6 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
        } else {
                phba->iocb_cmd_size = SLI2_IOCB_CMD_SIZE;
                phba->iocb_rsp_size = SLI2_IOCB_RSP_SIZE;
-               phba->sli3_options = 0;
        }
 
        lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
@@ -6407,12 +6412,13 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
         * then turn off the global config parameters to disable the
         * feature in the driver.  This is not a fatal error.
         */
-       phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED;
-       if (phba->cfg_enable_bg) {
-               if (bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs))
-                       phba->sli3_options |= LPFC_SLI3_BG_ENABLED;
-               else
+       if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
+               if (!(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs))) {
+                       phba->cfg_enable_bg = 0;
+                       phba->cfg_external_dif = 0;
+                       phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED;
                        ftr_rsp++;
+               }
        }
 
        if (phba->max_vpi && phba->cfg_enable_npiv &&
@@ -6425,8 +6431,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
                                "x%x x%x x%x\n", mqe->un.req_ftrs.word2,
                                mqe->un.req_ftrs.word3, phba->cfg_enable_bg,
                                phba->cfg_enable_npiv, phba->max_vpi);
-               if (!(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs)))
-                       phba->cfg_enable_bg = 0;
+
                if (!(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs)))
                        phba->cfg_enable_npiv = 0;
        }
@@ -10326,7 +10331,10 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
                !(cmdiocbq->iocb_flag & LPFC_IO_LIBDFC)) {
                lpfc_cmd = container_of(cmdiocbq, struct lpfc_scsi_buf,
                        cur_iocbq);
-               lpfc_cmd->exch_busy = rspiocbq->iocb_flag & LPFC_EXCHANGE_BUSY;
+               if (rspiocbq->iocb_flag & LPFC_EXCHANGE_BUSY)
+                       lpfc_cmd->flags |= LPFC_SBUF_XBUSY;
+               else
+                       lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY;
        }
 
        pdone_q = cmdiocbq->context_un.wait_queue;
-- 
1.7.11.7

Signed-off-by: James Smart <james.sm...@emulex.com>
Signed-off-by: Dick Kennedy <dick.kenn...@emulex.com>



--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to