Commit b0f18eee authored by Andrew Vasquez's avatar Andrew Vasquez Committed by Martin K. Petersen

scsi: qla2xxx: Update BPM enablement semantics.

commit e4e3a2ce ("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.comSigned-off-by: default avatarHimanshu Madhani <hmadhani@marvell.com>
Signed-off-by: default avatarAndrew Vasquez <andrewv@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent ce1ee122
......@@ -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
......
......@@ -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
......
......@@ -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 *,
......
......@@ -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],
......
......@@ -960,10 +960,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
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 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
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:
......
......@@ -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)))
......
......@@ -3462,13 +3462,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment