Commit 9f2475fe authored by Shyam Sundar's avatar Shyam Sundar Committed by Martin K. Petersen

scsi: qla2xxx: SAN congestion management implementation

* Firmware Initialization with SCM enabled based on NVRAM setting and
  firmware support (About Firmware).

* Enable PUREX and add support for fabric performance impact
  notification (FPIN) handling.

* Allocate a default PUREX item for each vha to handle memory allocation
  failures in ISR.

Link: https://lore.kernel.org/r/20200630102229.29660-3-njavali@marvell.comReviewed-by: default avatarHimanshu Madhani <himanshu.madhani@oracle.com>
Reviewed-by: default avatarJames Smart <james.smart@broadcom.com>
Signed-off-by: default avatarShyam Sundar <ssundar@marvell.com>
Signed-off-by: default avatarArun Easi <aeasi@marvell.com>
Signed-off-by: default avatarNilesh Javali <njavali@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 62e9dd17
......@@ -11,10 +11,8 @@
* ----------------------------------------------------------------------
* | Level | Last Value Used | Holes |
* ----------------------------------------------------------------------
* | Module Init and Probe | 0x0193 | 0x0146 |
* | | | 0x015b-0x0160 |
* | | | 0x016e |
* | Mailbox commands | 0x1206 | 0x11a2-0x11ff |
* | Module Init and Probe | 0x0199 | |
* | Mailbox commands | 0x1206 | 0x11a5-0x11ff |
* | Device Discovery | 0x2134 | 0x210e-0x2116 |
* | | | 0x211a |
* | | | 0x211c-0x2128 |
......@@ -26,11 +24,7 @@
* | | | 0x3036,0x3038 |
* | | | 0x303a |
* | DPC Thread | 0x4023 | 0x4002,0x4013 |
* | Async Events | 0x5090 | 0x502b-0x502f |
* | | | 0x5047 |
* | | | 0x5084,0x5075 |
* | | | 0x503d,0x5044 |
* | | | 0x505f |
* | Async Events | 0x509c | |
* | Timer Routines | 0x6012 | |
* | User Space Interactions | 0x70e3 | 0x7018,0x702e |
* | | | 0x7020,0x7024 |
......@@ -2662,7 +2656,6 @@ ql_dump_regs(uint level, scsi_qla_host_t *vha, uint id)
"mbox[%d] %#04x\n", i, rd_reg_word(mbx_reg));
}
void
ql_dump_buffer(uint level, scsi_qla_host_t *vha, uint id, const void *buf,
uint size)
......
......@@ -1055,6 +1055,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs)
#define MBA_LIP_F8 0x8016 /* Received a LIP F8. */
#define MBA_LOOP_INIT_ERR 0x8017 /* Loop Initialization Error. */
#define MBA_FABRIC_AUTH_REQ 0x801b /* Fabric Authentication Required. */
#define MBA_CONGN_NOTI_RECV 0x801e /* Congestion Notification Received */
#define MBA_SCSI_COMPLETION 0x8020 /* SCSI Command Complete. */
#define MBA_CTIO_COMPLETION 0x8021 /* CTIO Complete. */
#define MBA_IP_COMPLETION 0x8022 /* IP Transmit Command Complete. */
......@@ -1510,6 +1511,25 @@ typedef struct {
uint8_t reserved_3[26];
} init_cb_t;
/* Special Features Control Block */
struct init_sf_cb {
uint8_t format;
uint8_t reserved0;
/*
* BIT 15-14 = Reserved
* BIT_13 = SAN Congestion Management (1 - Enabled, 0 - Disabled)
* BIT_12 = Remote Write Optimization (1 - Enabled, 0 - Disabled)
* BIT 11-0 = Reserved
*/
uint16_t flags;
uint8_t reserved1[32];
uint16_t discard_OHRB_timeout_value;
uint16_t remote_write_opt_queue_num;
uint8_t reserved2[40];
uint8_t scm_related_parameter[16];
uint8_t reserved3[32];
};
/*
* Get Link Status mailbox command return buffer.
*/
......@@ -2183,6 +2203,8 @@ typedef struct {
struct dsd64 rsp_dsd;
} ms_iocb_entry_t;
#define SCM_EDC_ACC_RECEIVED BIT_6
#define SCM_RDF_ACC_RECEIVED BIT_7
/*
* ISP queue - Mailbox Command entry structure definition.
......@@ -3852,6 +3874,12 @@ struct qla_hw_data {
uint32_t n2n_bigger:1;
uint32_t secure_adapter:1;
uint32_t secure_fw:1;
/* Supported by Adapter */
uint32_t scm_supported_a:1;
/* Supported by Firmware */
uint32_t scm_supported_f:1;
/* Enabled in Driver */
uint32_t scm_enabled:1;
} flags;
uint16_t max_exchg;
......@@ -4169,6 +4197,13 @@ struct qla_hw_data {
int init_cb_size;
dma_addr_t ex_init_cb_dma;
struct ex_init_cb_81xx *ex_init_cb;
dma_addr_t sf_init_cb_dma;
struct init_sf_cb *sf_init_cb;
void *scm_fpin_els_buff;
uint64_t scm_fpin_els_buff_size;
bool scm_fpin_valid;
bool scm_fpin_payload_size;
void *async_pd;
dma_addr_t async_pd_dma;
......@@ -4231,6 +4266,12 @@ struct qla_hw_data {
#define FW_ATTR_H_NVME BIT_10
#define FW_ATTR_H_NVME_UPDATED BIT_14
/* About firmware SCM support */
#define FW_ATTR_EXT0_SCM_SUPPORTED BIT_12
/* Brocade fabric attached */
#define FW_ATTR_EXT0_SCM_BROCADE 0x00001000
/* Cisco fabric attached */
#define FW_ATTR_EXT0_SCM_CISCO 0x00002000
uint16_t fw_attributes_ext[2];
uint32_t fw_memory_size;
uint32_t fw_transfer_size;
......@@ -4541,6 +4582,13 @@ struct purex_item {
} iocb;
};
#define SCM_FLAG_RDF_REJECT 0x00
#define SCM_FLAG_RDF_COMPLETED 0x01
#define QLA_CON_PRIMITIVE_RECEIVED 0x1
#define QLA_CONGESTION_ARB_WARNING 0x1
#define QLA_CONGESTION_ARB_ALARM 0X2
/*
* Qlogic scsi host structure
*/
......@@ -4749,6 +4797,7 @@ typedef struct scsi_qla_host {
__le16 dport_data[4];
struct list_head gpnid_list;
struct fab_scan scan;
uint8_t scm_fabric_connection_flags;
unsigned int irq_offset;
} scsi_qla_host_t;
......
......@@ -723,6 +723,8 @@ struct ct_entry_24xx {
struct dsd64 dsd[2];
};
#define PURX_ELS_HEADER_SIZE 0x18
/*
* ISP queue - PUREX IOCB entry structure definition
*/
......@@ -2020,7 +2022,9 @@ struct nvram_81xx {
* BIT 0 = Extended BB credits for LR
* BIT 1 = Virtual Fabric Enable
* BIT 2-5 = Distance Support if BIT 0 is on
* BIT 6-15 = Unused
* BIT 6 = Prefer FCP
* BIT 7 = SCM Disabled if BIT is set (1)
* BIT 8-15 = Unused
*/
uint16_t enhanced_features;
......
......@@ -127,6 +127,7 @@ int qla_post_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport);
void qla_do_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport);
int qla2x00_reserve_mgmt_server_loop_id(scsi_qla_host_t *);
void qla_rscn_replay(fc_port_t *fcport);
void qla24xx_free_purex_item(struct purex_item *item);
extern bool qla24xx_risc_firmware_invalid(uint32_t *);
/*
......
......@@ -3749,7 +3749,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
}
/* Enable PUREX PASSTHRU */
if (ql2xrdpenable)
if (ql2xrdpenable || ha->flags.scm_supported_f)
qla25xx_set_els_cmds_supported(vha);
} else
goto failed;
......@@ -3962,7 +3962,7 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
ha->fw_options[2] &= ~BIT_8;
}
if (ql2xrdpenable)
if (ql2xrdpenable || ha->flags.scm_supported_f)
ha->fw_options[1] |= ADD_FO1_ENABLE_PUREX_IOCB;
/* Enable Async 8130/8131 events -- transceiver insertion/removal */
......@@ -8519,6 +8519,11 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
icb->node_name[0] &= 0xF0;
}
if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) {
if ((nv->enhanced_features & BIT_7) == 0)
ha->flags.scm_supported_a = 1;
}
/* Set host adapter parameters. */
ha->flags.disable_risc_code_load = 0;
ha->flags.enable_lip_reset = 0;
......
......@@ -22,6 +22,31 @@ static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
static int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
sts_entry_t *);
static void qla27xx_process_purex_fpin(struct scsi_qla_host *vha,
struct purex_item *item);
static struct purex_item *qla24xx_alloc_purex_item(scsi_qla_host_t *vha,
uint16_t size);
static struct purex_item *qla24xx_copy_std_pkt(struct scsi_qla_host *vha,
void *pkt);
static struct purex_item *qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha,
void **pkt, struct rsp_que **rsp);
static void
qla27xx_process_purex_fpin(struct scsi_qla_host *vha, struct purex_item *item)
{
void *pkt = &item->iocb;
uint16_t pkt_size = item->size;
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x508d,
"%s: Enter\n", __func__);
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x508e,
"-------- ELS REQ -------\n");
ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x508f,
pkt, pkt_size);
fc_host_fpin_rcv(vha->host, pkt_size, (char *)pkt);
}
const char *const port_state_str[] = {
"Unknown",
......@@ -819,7 +844,7 @@ qla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt,
* @vha: SCSI driver HA context
* @pkt: ELS packet
*/
struct purex_item
static struct purex_item
*qla24xx_copy_std_pkt(struct scsi_qla_host *vha, void *pkt)
{
struct purex_item *item;
......@@ -833,6 +858,111 @@ struct purex_item
return item;
}
/**
* qla27xx_copy_fpin_pkt() - Copy over fpin packets that can
* span over multiple IOCBs.
* @vha: SCSI driver HA context
* @pkt: ELS packet
* @rsp: Response queue
*/
static struct purex_item *
qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
struct rsp_que **rsp)
{
struct purex_entry_24xx *purex = *pkt;
struct rsp_que *rsp_q = *rsp;
sts_cont_entry_t *new_pkt;
uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0;
uint16_t buffer_copy_offset = 0;
uint16_t entry_count, entry_count_remaining;
struct purex_item *item;
void *fpin_pkt = NULL;
total_bytes = le16_to_cpu(purex->frame_size & 0x0FFF)
- PURX_ELS_HEADER_SIZE;
pending_bytes = total_bytes;
entry_count = entry_count_remaining = purex->entry_count;
no_bytes = (pending_bytes > sizeof(purex->els_frame_payload)) ?
sizeof(purex->els_frame_payload) : pending_bytes;
ql_log(ql_log_info, vha, 0x509a,
"FPIN ELS, frame_size 0x%x, entry count %d\n",
total_bytes, entry_count);
item = qla24xx_alloc_purex_item(vha, total_bytes);
if (!item)
return item;
fpin_pkt = &item->iocb;
memcpy(fpin_pkt, &purex->els_frame_payload[0], no_bytes);
buffer_copy_offset += no_bytes;
pending_bytes -= no_bytes;
--entry_count_remaining;
((response_t *)purex)->signature = RESPONSE_PROCESSED;
wmb();
do {
while ((total_bytes > 0) && (entry_count_remaining > 0)) {
if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) {
ql_dbg(ql_dbg_async, vha, 0x5084,
"Ran out of IOCBs, partial data 0x%x\n",
buffer_copy_offset);
cpu_relax();
continue;
}
new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
*pkt = new_pkt;
if (new_pkt->entry_type != STATUS_CONT_TYPE) {
ql_log(ql_log_warn, vha, 0x507a,
"Unexpected IOCB type, partial data 0x%x\n",
buffer_copy_offset);
break;
}
rsp_q->ring_index++;
if (rsp_q->ring_index == rsp_q->length) {
rsp_q->ring_index = 0;
rsp_q->ring_ptr = rsp_q->ring;
} else {
rsp_q->ring_ptr++;
}
no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
sizeof(new_pkt->data) : pending_bytes;
if ((buffer_copy_offset + no_bytes) <= total_bytes) {
memcpy(((uint8_t *)fpin_pkt +
buffer_copy_offset), new_pkt->data,
no_bytes);
buffer_copy_offset += no_bytes;
pending_bytes -= no_bytes;
--entry_count_remaining;
} else {
ql_log(ql_log_warn, vha, 0x5044,
"Attempt to copy more that we got, optimizing..%x\n",
buffer_copy_offset);
memcpy(((uint8_t *)fpin_pkt +
buffer_copy_offset), new_pkt->data,
total_bytes - buffer_copy_offset);
}
((response_t *)new_pkt)->signature = RESPONSE_PROCESSED;
wmb();
}
if (pending_bytes != 0 || entry_count_remaining != 0) {
ql_log(ql_log_fatal, vha, 0x508b,
"Dropping partial FPIN, underrun bytes = 0x%x, entry cnts 0x%x\n",
total_bytes, entry_count_remaining);
qla24xx_free_purex_item(item);
return NULL;
}
} while (entry_count_remaining > 0);
host_to_fcp_swap((uint8_t *)&item->iocb, total_bytes);
return item;
}
/**
* qla2x00_async_event() - Process aynchronous events.
* @vha: SCSI driver HA context
......@@ -1346,6 +1476,19 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
qla2x00_post_aen_work(vha, FCH_EVT_RSCN, rscn_entry);
}
break;
case MBA_CONGN_NOTI_RECV:
if (!ha->flags.scm_enabled ||
mb[1] != QLA_CON_PRIMITIVE_RECEIVED)
break;
if (mb[2] == QLA_CONGESTION_ARB_WARNING) {
ql_dbg(ql_dbg_async, vha, 0x509b,
"Congestion Warning %04x %04x.\n", mb[1], mb[2]);
} else if (mb[2] == QLA_CONGESTION_ARB_ALARM) {
ql_log(ql_log_warn, vha, 0x509b,
"Congestion Alarm %04x %04x.\n", mb[1], mb[2]);
}
break;
/* case MBA_RIO_RESPONSE: */
case MBA_ZIO_RESPONSE:
ql_dbg(ql_dbg_async, vha, 0x5015,
......@@ -3273,6 +3416,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
{
struct sts_entry_24xx *pkt;
struct qla_hw_data *ha = vha->hw;
struct purex_entry_24xx *purex_entry;
struct purex_item *pure_item;
if (!ha->flags.fw_started)
......@@ -3328,7 +3472,6 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
pure_item = qla24xx_copy_std_pkt(vha, pkt);
if (!pure_item)
break;
qla24xx_queue_purex_item(vha, pure_item,
qla24xx_process_abts);
break;
......@@ -3378,29 +3521,40 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
(struct vp_ctrl_entry_24xx *)pkt);
break;
case PUREX_IOCB_TYPE:
{
struct purex_entry_24xx *purex = (void *)pkt;
if (purex->els_frame_payload[3] != ELS_RDP) {
ql_dbg(ql_dbg_init, vha, 0x5091,
"Discarding ELS Request opcode %#x...\n",
purex->els_frame_payload[3]);
purex_entry = (void *)pkt;
switch (purex_entry->els_frame_payload[3]) {
case ELS_RDP:
pure_item = qla24xx_copy_std_pkt(vha, pkt);
if (!pure_item)
break;
qla24xx_queue_purex_item(vha, pure_item,
qla24xx_process_purex_rdp);
break;
}
pure_item = qla24xx_copy_std_pkt(vha, pkt);
if (!pure_item)
case ELS_FPIN:
if (!vha->hw->flags.scm_enabled) {
ql_log(ql_log_warn, vha, 0x5094,
"SCM not active for this port\n");
break;
}
pure_item = qla27xx_copy_fpin_pkt(vha,
(void **)&pkt, &rsp);
if (!pure_item)
break;
qla24xx_queue_purex_item(vha, pure_item,
qla27xx_process_purex_fpin);
break;
qla24xx_queue_purex_item(vha, pure_item,
qla24xx_process_purex_rdp);
default:
ql_log(ql_log_warn, vha, 0x509c,
"Discarding ELS Request opcode 0x%x\n",
purex_entry->els_frame_payload[3]);
}
break;
}
default:
/* Type Not Supported. */
ql_dbg(ql_dbg_async, vha, 0x5042,
"Received unknown response pkt type %x "
"entry status=%x.\n",
pkt->entry_type, pkt->entry_status);
"Received unknown response pkt type 0x%x entry status=%x.\n",
pkt->entry_type, pkt->entry_status);
break;
}
((response_t *)pkt)->signature = RESPONSE_PROCESSED;
......
......@@ -1125,6 +1125,16 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
(ha->flags.secure_fw) ? "Supported" :
"Not Supported");
}
if (ha->flags.scm_supported_a &&
(ha->fw_attributes_ext[0] & FW_ATTR_EXT0_SCM_SUPPORTED)) {
ha->flags.scm_supported_f = 1;
memset(ha->sf_init_cb, 0, sizeof(struct init_sf_cb));
ha->sf_init_cb->flags |= BIT_13;
}
ql_log(ql_log_info, vha, 0x11a3, "SCM in FW: %s\n",
(ha->flags.scm_supported_f) ? "Supported" :
"Not Supported");
}
failed:
......@@ -1634,8 +1644,11 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;
if (IS_FWI2_CAPABLE(vha->hw))
mcp->in_mb |= MBX_19|MBX_18|MBX_17|MBX_16;
if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw))
if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw)) {
mcp->in_mb |= MBX_15;
mcp->out_mb |= MBX_7|MBX_21|MBX_22|MBX_23;
}
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
rval = qla2x00_mailbox_command(vha, mcp);
......@@ -1688,8 +1701,22 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
}
}
if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw))
if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw)) {
vha->bbcr = mcp->mb[15];
if (mcp->mb[7] & SCM_EDC_ACC_RECEIVED) {
ql_log(ql_log_info, vha, 0x11a4,
"SCM: EDC ELS completed, flags 0x%x\n",
mcp->mb[21]);
}
if (mcp->mb[7] & SCM_RDF_ACC_RECEIVED) {
vha->hw->flags.scm_enabled = 1;
vha->scm_fabric_connection_flags |=
SCM_FLAG_RDF_COMPLETED;
ql_log(ql_log_info, vha, 0x11a5,
"SCM: RDF ELS completed, flags 0x%x\n",
mcp->mb[23]);
}
}
}
return rval;
......@@ -1802,6 +1829,17 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
mcp->mb[14] = sizeof(*ha->ex_init_cb);
mcp->out_mb |= MBX_14|MBX_13|MBX_12|MBX_11|MBX_10;
}
if (ha->flags.scm_supported_f) {
mcp->mb[1] |= BIT_1;
mcp->mb[16] = MSW(ha->sf_init_cb_dma);
mcp->mb[17] = LSW(ha->sf_init_cb_dma);
mcp->mb[18] = MSW(MSD(ha->sf_init_cb_dma));
mcp->mb[19] = LSW(MSD(ha->sf_init_cb_dma));
mcp->mb[15] = sizeof(*ha->sf_init_cb);
mcp->out_mb |= MBX_19|MBX_18|MBX_17|MBX_16|MBX_15;
}
/* 1 and 2 should normally be captured. */
mcp->in_mb = MBX_2|MBX_1|MBX_0;
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
......
......@@ -4218,6 +4218,16 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
"ex_init_cb=%p.\n", ha->ex_init_cb);
}
/* Get consistent memory allocated for Special Features-CB. */
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
ha->sf_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
&ha->sf_init_cb_dma);
if (!ha->sf_init_cb)
goto fail_sf_init_cb;
ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0199,
"sf_init_cb=%p.\n", ha->sf_init_cb);
}
INIT_LIST_HEAD(&ha->gbl_dsd_list);
/* Get consistent memory allocated for Async Port-Database. */
......@@ -4271,6 +4281,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
fail_loop_id_map:
dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma);
fail_async_pd:
dma_pool_free(ha->s_dma_pool, ha->sf_init_cb, ha->sf_init_cb_dma);
fail_sf_init_cb:
dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma);
fail_ex_init_cb:
kfree(ha->npiv_info);
......@@ -4693,6 +4705,10 @@ qla2x00_mem_free(struct qla_hw_data *ha)
ha->ms_iocb = NULL;
ha->ms_iocb_dma = 0;
if (ha->sf_init_cb)
dma_pool_free(ha->s_dma_pool,
ha->sf_init_cb, ha->sf_init_cb_dma);
if (ha->ex_init_cb)
dma_pool_free(ha->s_dma_pool,
ha->ex_init_cb, ha->ex_init_cb_dma);
......@@ -4780,6 +4796,8 @@ qla2x00_mem_free(struct qla_hw_data *ha)
kfree(ha->swl);
ha->swl = NULL;
kfree(ha->loop_id_map);
ha->sf_init_cb = NULL;
ha->sf_init_cb_dma = 0;
ha->loop_id_map = NULL;
}
......
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