scsi: qla2xxx: Update BPM enablement semantics.
authorAndrew Vasquez <andrewv@marvell.com>
Wed, 26 Feb 2020 22:40:13 +0000 (14:40 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sat, 29 Feb 2020 01:32:33 +0000 (20:32 -0500)
commit e4e3a2ce9556 ("scsi: qla2xxx: Add ability to autodetect SFP
type") takes a heavy handed approach to BPM (Buffer Plus Management)
enablement:

1) During hardware initialization, if an LR-capable transceiver is
   recognized, the driver schedules a disruptive post-initialization
   chip-reset (ISP-ABORT) to allow the BPM settings to be sent to the
   firmware.  This chip-reset will result in (short-term) path-loss to
   all fc-rports and their attached SCSI devices.

2) LR-detection is triggered during any link-up event, resulting in a
   refresh and potential chip-reset

Based on firmware-team guidance, upon LR-capable transceiver
recognition, the driver's hardware initialization code will now
re-execute firmware with the new BPM settings, then continue on with
driver initialization.  To address the second issue, the driver
performs LR-capable detection upon the driver receiving a
transceiver-insertion asynchronous event from firmware.  No short-term
path loss is needed with this new semantic.

Link: https://lore.kernel.org/r/20200226224022.24518-10-hmadhani@marvell.com
Signed-off-by: Himanshu Madhani <hmadhani@marvell.com>
Signed-off-by: Andrew Vasquez <andrewv@marvell.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c

index 5182749..47c7a56 100644 (file)
@@ -1049,6 +1049,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs)
 #define MBA_TEMPERATURE_ALERT  0x8070  /* Temperature Alert */
 #define MBA_DPORT_DIAGNOSTICS  0x8080  /* D-port Diagnostics */
 #define MBA_TRANS_INSERT       0x8130  /* Transceiver Insertion */
+#define MBA_TRANS_REMOVE       0x8131  /* Transceiver Removal */
 #define MBA_FW_INIT_FAILURE    0x8401  /* Firmware initialization failure */
 #define MBA_MIRROR_LUN_CHANGE  0x8402  /* Mirror LUN State Change
                                           Notification */
@@ -3802,8 +3803,8 @@ struct qla_hw_data {
                uint32_t        fw_started:1;
                uint32_t        fw_init_done:1;
 
-               uint32_t        detected_lr_sfp:1;
-               uint32_t        using_lr_setting:1;
+               uint32_t        lr_detected:1;
+
                uint32_t        rida_fmt2:1;
                uint32_t        purge_mbox:1;
                uint32_t        n2n_bigger:1;
@@ -3812,7 +3813,7 @@ struct qla_hw_data {
        } flags;
 
        uint16_t max_exchg;
-       uint16_t long_range_distance;   /* 32G & above */
+       uint16_t lr_distance;   /* 32G & above */
 #define LR_DISTANCE_5K  1
 #define LR_DISTANCE_10K 0
 
@@ -4971,11 +4972,14 @@ struct sff_8247_a0 {
        u8 resv2[128];
 };
 
-#define AUTO_DETECT_SFP_SUPPORT(_vha)\
-       (ql2xautodetectsfp && !_vha->vp_idx &&          \
-       (IS_QLA25XX(_vha->hw) || IS_QLA81XX(_vha->hw) ||\
-       IS_QLA83XX(_vha->hw) || IS_QLA27XX(_vha->hw) || \
-        IS_QLA28XX(_vha->hw)))
+/* BPM -- Buffer Plus Management support. */
+#define IS_BPM_CAPABLE(ha) \
+       (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
+        IS_QLA27XX(ha) || IS_QLA28XX(ha))
+#define IS_BPM_RANGE_CAPABLE(ha) \
+       (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
+#define IS_BPM_ENABLED(vha) \
+       (ql2xautodetectsfp && !vha->vp_idx && IS_BPM_CAPABLE(vha->hw))
 
 #define FLASH_SEMAPHORE_REGISTER_ADDR   0x00101016
 
index 8af5bc4..f9bad5b 100644 (file)
@@ -1867,9 +1867,8 @@ struct access_chip_rsp_84xx {
 
 /* LR Distance bit positions */
 #define LR_DIST_NV_POS         2
+#define LR_DIST_NV_MASK                0xf
 #define LR_DIST_FW_POS         12
-#define LR_DIST_FW_SHIFT       (LR_DIST_FW_POS - LR_DIST_NV_POS)
-#define LR_DIST_FW_FIELD(x)    ((x) << LR_DIST_FW_SHIFT & 0xf000)
 
 /* FAC semaphore defines */
 #define FAC_SEMAPHORE_UNLOCK    0
index 33ea791..1b93f5b 100644 (file)
@@ -109,7 +109,7 @@ int qla24xx_async_notify_ack(scsi_qla_host_t *, fc_port_t *,
 int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *, u8*,
     void *, u8);
 int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *);
-int qla24xx_detect_sfp(scsi_qla_host_t *vha);
+int qla24xx_detect_sfp(scsi_qla_host_t *);
 int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8);
 
 extern void qla28xx_get_aux_images(struct scsi_qla_host *,
index 87b2d62..3d615cc 100644 (file)
@@ -3550,53 +3550,77 @@ static void qla2xxx_print_sfp_info(struct scsi_qla_host *vha)
 }
 
 
-/*
- * Return Code:
- *   QLA_SUCCESS: no action
- *   QLA_INTERFACE_ERROR: SFP is not there.
- *   QLA_FUNCTION_FAILED: detected New SFP
+/**
+ * qla24xx_detect_sfp()
+ *
+ * @vha: adapter state pointer.
+ *
+ * @return
+ *     0 -- Configure firmware to use short-range settings -- normal
+ *          buffer-to-buffer credits.
+ *
+ *     1 -- Configure firmware to use long-range settings -- extra
+ *          buffer-to-buffer credits should be allocated with
+ *          ha->lr_distance containing distance settings from NVRAM or SFP
+ *          (if supported).
  */
 int
 qla24xx_detect_sfp(scsi_qla_host_t *vha)
 {
-       int rc = QLA_SUCCESS;
+       int rc, used_nvram;
        struct sff_8247_a0 *a;
        struct qla_hw_data *ha = vha->hw;
-
-       if (!AUTO_DETECT_SFP_SUPPORT(vha))
+       struct nvram_81xx *nv = ha->nvram;
+#define LR_DISTANCE_UNKNOWN    2
+       static const char * const types[] = { "Short", "Long" };
+       static const char * const lengths[] = { "(10km)", "(5km)", "" };
+       u8 ll = 0;
+
+       /* Seed with NVRAM settings. */
+       used_nvram = 0;
+       ha->flags.lr_detected = 0;
+       if (IS_BPM_RANGE_CAPABLE(ha) &&
+           (nv->enhanced_features & NEF_LR_DIST_ENABLE)) {
+               used_nvram = 1;
+               ha->flags.lr_detected = 1;
+               ha->lr_distance =
+                   (nv->enhanced_features >> LR_DIST_NV_POS)
+                    & LR_DIST_NV_MASK;
+       }
+
+       if (!IS_BPM_ENABLED(vha))
                goto out;
-
+       /* Determine SR/LR capabilities of SFP/Transceiver. */
        rc = qla2x00_read_sfp_dev(vha, NULL, 0);
        if (rc)
                goto out;
 
+       used_nvram = 0;
        a = (struct sff_8247_a0 *)vha->hw->sfp_data;
        qla2xxx_print_sfp_info(vha);
 
-       if (a->fc_ll_cc7 & FC_LL_VL || a->fc_ll_cc7 & FC_LL_L) {
-               /* long range */
-               ha->flags.detected_lr_sfp = 1;
+       ha->flags.lr_detected = 0;
+       ll = a->fc_ll_cc7;
+       if (ll & FC_LL_VL || ll & FC_LL_L) {
+               /* Long range, track length. */
+               ha->flags.lr_detected = 1;
 
                if (a->length_km > 5 || a->length_100m > 50)
-                       ha->long_range_distance = LR_DISTANCE_10K;
+                       ha->lr_distance = LR_DISTANCE_10K;
                else
-                       ha->long_range_distance = LR_DISTANCE_5K;
-
-               if (ha->flags.detected_lr_sfp != ha->flags.using_lr_setting)
-                       ql_dbg(ql_dbg_async, vha, 0x507b,
-                           "Detected Long Range SFP.\n");
-       } else {
-               /* short range */
-               ha->flags.detected_lr_sfp = 0;
-               if (ha->flags.using_lr_setting)
-                       ql_dbg(ql_dbg_async, vha, 0x5084,
-                           "Detected Short Range SFP.\n");
+                       ha->lr_distance = LR_DISTANCE_5K;
        }
 
        if (!vha->flags.init_done)
                rc = QLA_SUCCESS;
 out:
-       return rc;
+       ql_dbg(ql_dbg_async, vha, 0x507b,
+           "SFP detect: %s-Range SFP %s (nvr=%x ll=%x lr=%x lrd=%x).\n",
+           types[ha->flags.lr_detected],
+           ha->flags.lr_detected ? lengths[ha->lr_distance] :
+              lengths[LR_DISTANCE_UNKNOWN],
+           used_nvram, ll, ha->flags.lr_detected, ha->lr_distance);
+       return ha->flags.lr_detected;
 }
 
 /**
@@ -3614,6 +3638,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
        unsigned long flags;
        uint16_t fw_major_version;
+       int done_once = 0;
 
        if (IS_P3P_TYPE(ha)) {
                rval = ha->isp_ops->load_risc(vha, &srisc_address);
@@ -3634,6 +3659,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
 
        qla81xx_mpi_sync(vha);
 
+execute_fw_with_lr:
        /* Load firmware sequences */
        rval = ha->isp_ops->load_risc(vha, &srisc_address);
        if (rval == QLA_SUCCESS) {
@@ -3655,7 +3681,15 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
                        rval = qla2x00_execute_fw(vha, srisc_address);
                        /* Retrieve firmware information. */
                        if (rval == QLA_SUCCESS) {
-                               qla24xx_detect_sfp(vha);
+                               /* Enable BPM support? */
+                               if (!done_once++ && qla24xx_detect_sfp(vha)) {
+                                       ql_dbg(ql_dbg_init, vha, 0x00ca,
+                                           "Re-starting firmware -- BPM.\n");
+                                       /* Best-effort - re-init. */
+                                       ha->isp_ops->reset_chip(vha);
+                                       ha->isp_ops->chip_diag(vha);
+                                       goto execute_fw_with_lr;
+                               }
 
                                if ((IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
                                    IS_QLA28XX(ha)) &&
@@ -3932,6 +3966,10 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
        if (ql2xrdpenable)
                ha->fw_options[1] |= ADD_FO1_ENABLE_PUREX_IOCB;
 
+       /* Enable Async 8130/8131 events -- transceiver insertion/removal */
+       if (IS_BPM_RANGE_CAPABLE(ha))
+               ha->fw_options[3] |= BIT_10;
+
        ql_dbg(ql_dbg_init, vha, 0x00e8,
            "%s, add FW options 1-3 = 0x%04x 0x%04x 0x%04x mode %x\n",
            __func__, ha->fw_options[1], ha->fw_options[2],
index 2918bb0..9a14349 100644 (file)
@@ -960,10 +960,6 @@ skip_rio:
                vha->flags.management_server_logged_in = 0;
                qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
 
-               if (AUTO_DETECT_SFP_SUPPORT(vha)) {
-                       set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags);
-                       qla2xxx_wake_dpc(vha);
-               }
                break;
 
        case MBA_LOOP_DOWN:             /* Loop Down Event */
@@ -1436,6 +1432,11 @@ global_port_update:
        case MBA_TRANS_INSERT:
                ql_dbg(ql_dbg_async, vha, 0x5091,
                    "Transceiver Insertion: %04x\n", mb[1]);
+               set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags);
+               break;
+
+       case MBA_TRANS_REMOVE:
+               ql_dbg(ql_dbg_async, vha, 0x5091, "Transceiver Removal\n");
                break;
 
        default:
index 938b4e4..11a60fb 100644 (file)
@@ -643,28 +643,6 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr,
 }
 
 #define        NVME_ENABLE_FLAG        BIT_3
-static inline uint16_t qla25xx_set_sfp_lr_dist(struct qla_hw_data *ha)
-{
-       uint16_t mb4 = BIT_0;
-
-       if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
-               mb4 |= ha->long_range_distance << LR_DIST_FW_POS;
-
-       return mb4;
-}
-
-static inline uint16_t qla25xx_set_nvr_lr_dist(struct qla_hw_data *ha)
-{
-       uint16_t mb4 = BIT_0;
-
-       if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
-               struct nvram_81xx *nv = ha->nvram;
-
-               mb4 |= LR_DIST_FW_FIELD(nv->enhanced_features);
-       }
-
-       return mb4;
-}
 
 /*
  * qla2x00_execute_fw
@@ -701,25 +679,13 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
                mcp->mb[3] = 0;
                mcp->mb[4] = 0;
                mcp->mb[11] = 0;
-               ha->flags.using_lr_setting = 0;
-               if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
-                   IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
-                       if (ql2xautodetectsfp) {
-                               if (ha->flags.detected_lr_sfp) {
-                                       mcp->mb[4] |=
-                                           qla25xx_set_sfp_lr_dist(ha);
-                                       ha->flags.using_lr_setting = 1;
-                               }
-                       } else {
-                               struct nvram_81xx *nv = ha->nvram;
-                               /* set LR distance if specified in nvram */
-                               if (nv->enhanced_features &
-                                   NEF_LR_DIST_ENABLE) {
-                                       mcp->mb[4] |=
-                                           qla25xx_set_nvr_lr_dist(ha);
-                                       ha->flags.using_lr_setting = 1;
-                               }
-                       }
+
+               /* Enable BPM? */
+               if (ha->flags.lr_detected) {
+                       mcp->mb[4] = BIT_0;
+                       if (IS_BPM_RANGE_CAPABLE(ha))
+                               mcp->mb[4] |=
+                                   ha->lr_distance << LR_DIST_FW_POS;
                }
 
                if (ql2xnvmeenable && (IS_QLA27XX(ha) || IS_QLA28XX(ha)))
index dddb86d..7db32f9 100644 (file)
@@ -3462,13 +3462,6 @@ skip_dpc:
        if (test_bit(UNLOADING, &base_vha->dpc_flags))
                return -ENODEV;
 
-       if (ha->flags.detected_lr_sfp) {
-               ql_log(ql_log_info, base_vha, 0xffff,
-                   "Reset chip to pick up LR SFP setting\n");
-               set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
-               qla2xxx_wake_dpc(base_vha);
-       }
-
        return 0;
 
 probe_failed:
@@ -6881,13 +6874,14 @@ qla2x00_do_dpc(void *data)
                }
 
                if (test_and_clear_bit(DETECT_SFP_CHANGE,
-                       &base_vha->dpc_flags) &&
-                   !test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) {
-                       qla24xx_detect_sfp(base_vha);
-
-                       if (ha->flags.detected_lr_sfp !=
-                           ha->flags.using_lr_setting)
-                               set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
+                   &base_vha->dpc_flags)) {
+                       /* Semantic:
+                        *  - NO-OP -- await next ISP-ABORT. Preferred method
+                        *             to minimize disruptions that will occur
+                        *             when a forced chip-reset occurs.
+                        *  - Force -- ISP-ABORT scheduled.
+                        */
+                       /* set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); */
                }
 
                if (test_and_clear_bit