Commit 62e9dd17 authored by Shyam Sundar's avatar Shyam Sundar Committed by Martin K. Petersen

scsi: qla2xxx: Change in PUREX to handle FPIN ELS requests

SAN Congestion Management generates ELS pkts whose size can vary and be >
64 bytes. Change the PUREX handling code to support non-standard ELS pkt
size.

Link: https://lore.kernel.org/r/20200630102229.29660-2-njavali@marvell.comReviewed-by: default avatarHimanshu Madhani <himanshu.madhani@oracle.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 e7019c95
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#include <scsi/scsi_transport_fc.h> #include <scsi/scsi_transport_fc.h>
#include <scsi/scsi_bsg_fc.h> #include <scsi/scsi_bsg_fc.h>
#include <uapi/scsi/fc/fc_els.h>
/* Big endian Fibre Channel S_ID (source ID) or D_ID (destination ID). */ /* Big endian Fibre Channel S_ID (source ID) or D_ID (destination ID). */
typedef struct { typedef struct {
uint8_t domain; uint8_t domain;
...@@ -1304,7 +1306,6 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) ...@@ -1304,7 +1306,6 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs)
#define RNID_TYPE_ASIC_TEMP 0xC #define RNID_TYPE_ASIC_TEMP 0xC
#define ELS_CMD_MAP_SIZE 32 #define ELS_CMD_MAP_SIZE 32
#define ELS_COMMAND_RDP 0x18
/* /*
* Firmware state codes from get firmware state mailbox command * Firmware state codes from get firmware state mailbox command
...@@ -4522,10 +4523,19 @@ struct active_regions { ...@@ -4522,10 +4523,19 @@ struct active_regions {
#define QLA_SET_DATA_RATE_NOLR 1 #define QLA_SET_DATA_RATE_NOLR 1
#define QLA_SET_DATA_RATE_LR 2 /* Set speed and initiate LR */ #define QLA_SET_DATA_RATE_LR 2 /* Set speed and initiate LR */
#define QLA_DEFAULT_PAYLOAD_SIZE 64
/*
* This item might be allocated with a size > sizeof(struct purex_item).
* The "size" variable gives the size of the payload (which
* is variable) starting at "iocb".
*/
struct purex_item { struct purex_item {
struct list_head list; struct list_head list;
struct scsi_qla_host *vha; struct scsi_qla_host *vha;
void (*process_item)(struct scsi_qla_host *vha, void *pkt); void (*process_item)(struct scsi_qla_host *vha,
struct purex_item *pkt);
atomic_t in_use;
uint16_t size;
struct { struct {
uint8_t iocb[64]; uint8_t iocb[64];
} iocb; } iocb;
...@@ -4725,6 +4735,7 @@ typedef struct scsi_qla_host { ...@@ -4725,6 +4735,7 @@ typedef struct scsi_qla_host {
struct list_head head; struct list_head head;
spinlock_t lock; spinlock_t lock;
} purex_list; } purex_list;
struct purex_item default_item;
struct name_list_extended gnl; struct name_list_extended gnl;
/* Count of active session/fcport */ /* Count of active session/fcport */
......
...@@ -229,7 +229,8 @@ void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *, ...@@ -229,7 +229,8 @@ void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *,
int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *); int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *);
int qla24xx_post_relogin_work(struct scsi_qla_host *vha); int qla24xx_post_relogin_work(struct scsi_qla_host *vha);
void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *); void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *);
void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, void *pkt); void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
struct purex_item *pkt);
/* /*
* Global Functions in qla_mid.c source file. * Global Functions in qla_mid.c source file.
......
...@@ -31,35 +31,11 @@ const char *const port_state_str[] = { ...@@ -31,35 +31,11 @@ const char *const port_state_str[] = {
"ONLINE" "ONLINE"
}; };
static void qla24xx_purex_iocb(scsi_qla_host_t *vha, void *pkt,
void (*process_item)(struct scsi_qla_host *vha, void *pkt))
{
struct purex_list *list = &vha->purex_list;
struct purex_item *item;
ulong flags;
item = kzalloc(sizeof(*item), GFP_KERNEL);
if (!item) {
ql_log(ql_log_warn, vha, 0x5092,
">> Failed allocate purex list item.\n");
return;
}
item->vha = vha;
item->process_item = process_item;
memcpy(&item->iocb, pkt, sizeof(item->iocb));
spin_lock_irqsave(&list->lock, flags);
list_add_tail(&item->list, &list->head);
spin_unlock_irqrestore(&list->lock, flags);
set_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags);
}
static void static void
qla24xx_process_abts(struct scsi_qla_host *vha, void *pkt) qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
{ {
struct abts_entry_24xx *abts = pkt; struct abts_entry_24xx *abts =
(struct abts_entry_24xx *)&pkt->iocb;
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
struct els_entry_24xx *rsp_els; struct els_entry_24xx *rsp_els;
struct abts_entry_24xx *abts_rsp; struct abts_entry_24xx *abts_rsp;
...@@ -789,6 +765,74 @@ qla27xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb) ...@@ -789,6 +765,74 @@ qla27xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
} }
} }
struct purex_item *
qla24xx_alloc_purex_item(scsi_qla_host_t *vha, uint16_t size)
{
struct purex_item *item = NULL;
uint8_t item_hdr_size = sizeof(*item);
if (size > QLA_DEFAULT_PAYLOAD_SIZE) {
item = kzalloc(item_hdr_size +
(size - QLA_DEFAULT_PAYLOAD_SIZE), GFP_ATOMIC);
} else {
if (atomic_inc_return(&vha->default_item.in_use) == 1) {
item = &vha->default_item;
goto initialize_purex_header;
} else {
item = kzalloc(item_hdr_size, GFP_ATOMIC);
}
}
if (!item) {
ql_log(ql_log_warn, vha, 0x5092,
">> Failed allocate purex list item.\n");
return NULL;
}
initialize_purex_header:
item->vha = vha;
item->size = size;
return item;
}
static void
qla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt,
void (*process_item)(struct scsi_qla_host *vha,
struct purex_item *pkt))
{
struct purex_list *list = &vha->purex_list;
ulong flags;
pkt->process_item = process_item;
spin_lock_irqsave(&list->lock, flags);
list_add_tail(&pkt->list, &list->head);
spin_unlock_irqrestore(&list->lock, flags);
set_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags);
}
/**
* qla24xx_copy_std_pkt() - Copy over purex ELS which is
* contained in a single IOCB.
* purex packet.
* @vha: SCSI driver HA context
* @pkt: ELS packet
*/
struct purex_item
*qla24xx_copy_std_pkt(struct scsi_qla_host *vha, void *pkt)
{
struct purex_item *item;
item = qla24xx_alloc_purex_item(vha,
QLA_DEFAULT_PAYLOAD_SIZE);
if (!item)
return item;
memcpy(&item->iocb, pkt, sizeof(item->iocb));
return item;
}
/** /**
* qla2x00_async_event() - Process aynchronous events. * qla2x00_async_event() - Process aynchronous events.
* @vha: SCSI driver HA context * @vha: SCSI driver HA context
...@@ -3229,6 +3273,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, ...@@ -3229,6 +3273,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
{ {
struct sts_entry_24xx *pkt; struct sts_entry_24xx *pkt;
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
struct purex_item *pure_item;
if (!ha->flags.fw_started) if (!ha->flags.fw_started)
return; return;
...@@ -3280,8 +3325,12 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, ...@@ -3280,8 +3325,12 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
break; break;
case ABTS_RECV_24XX: case ABTS_RECV_24XX:
if (qla_ini_mode_enabled(vha)) { if (qla_ini_mode_enabled(vha)) {
qla24xx_purex_iocb(vha, pkt, pure_item = qla24xx_copy_std_pkt(vha, pkt);
qla24xx_process_abts); if (!pure_item)
break;
qla24xx_queue_purex_item(vha, pure_item,
qla24xx_process_abts);
break; break;
} }
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || if (IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
...@@ -3332,13 +3381,18 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, ...@@ -3332,13 +3381,18 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
{ {
struct purex_entry_24xx *purex = (void *)pkt; struct purex_entry_24xx *purex = (void *)pkt;
if (purex->els_frame_payload[3] != ELS_COMMAND_RDP) { if (purex->els_frame_payload[3] != ELS_RDP) {
ql_dbg(ql_dbg_init, vha, 0x5091, ql_dbg(ql_dbg_init, vha, 0x5091,
"Discarding ELS Request opcode %#x...\n", "Discarding ELS Request opcode %#x...\n",
purex->els_frame_payload[3]); purex->els_frame_payload[3]);
break; break;
} }
qla24xx_purex_iocb(vha, pkt, qla24xx_process_purex_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; break;
} }
default: default:
......
...@@ -59,6 +59,7 @@ static struct rom_cmd { ...@@ -59,6 +59,7 @@ static struct rom_cmd {
{ MBC_IOCB_COMMAND_A64 }, { MBC_IOCB_COMMAND_A64 },
{ MBC_GET_ADAPTER_LOOP_ID }, { MBC_GET_ADAPTER_LOOP_ID },
{ MBC_READ_SFP }, { MBC_READ_SFP },
{ MBC_SET_RNID_PARAMS },
{ MBC_GET_RNID_PARAMS }, { MBC_GET_RNID_PARAMS },
{ MBC_GET_SET_ZIO_THRESHOLD }, { MBC_GET_SET_ZIO_THRESHOLD },
}; };
...@@ -4866,6 +4867,7 @@ qla24xx_get_port_login_templ(scsi_qla_host_t *vha, dma_addr_t buf_dma, ...@@ -4866,6 +4867,7 @@ qla24xx_get_port_login_templ(scsi_qla_host_t *vha, dma_addr_t buf_dma,
return rval; return rval;
} }
#define PUREX_CMD_COUNT 2
int int
qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha) qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha)
{ {
...@@ -4874,12 +4876,12 @@ qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha) ...@@ -4874,12 +4876,12 @@ qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha)
mbx_cmd_t *mcp = &mc; mbx_cmd_t *mcp = &mc;
uint8_t *els_cmd_map; uint8_t *els_cmd_map;
dma_addr_t els_cmd_map_dma; dma_addr_t els_cmd_map_dma;
uint cmd_opcode = ELS_COMMAND_RDP; uint8_t cmd_opcode[PUREX_CMD_COUNT];
uint index = cmd_opcode / 8; uint8_t i, index, purex_bit;
uint bit = cmd_opcode % 8;
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
if (!IS_QLA25XX(ha) && !IS_QLA2031(ha) && !IS_QLA27XX(ha)) if (!IS_QLA25XX(ha) && !IS_QLA2031(ha) &&
!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return QLA_SUCCESS; return QLA_SUCCESS;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1197, ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1197,
...@@ -4893,7 +4895,17 @@ qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha) ...@@ -4893,7 +4895,17 @@ qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha)
return QLA_MEMORY_ALLOC_FAILED; return QLA_MEMORY_ALLOC_FAILED;
} }
els_cmd_map[index] |= 1 << bit; memset(els_cmd_map, 0, ELS_CMD_MAP_SIZE);
/* List of Purex ELS */
cmd_opcode[0] = ELS_FPIN;
cmd_opcode[1] = ELS_RDP;
for (i = 0; i < PUREX_CMD_COUNT; i++) {
index = cmd_opcode[i] / 8;
purex_bit = cmd_opcode[i] % 8;
els_cmd_map[index] |= 1 << purex_bit;
}
mcp->mb[0] = MBC_SET_RNID_PARAMS; mcp->mb[0] = MBC_SET_RNID_PARAMS;
mcp->mb[1] = RNID_TYPE_ELS_CMD << 8; mcp->mb[1] = RNID_TYPE_ELS_CMD << 8;
......
...@@ -5893,10 +5893,12 @@ qla25xx_rdp_port_speed_currently(struct qla_hw_data *ha) ...@@ -5893,10 +5893,12 @@ qla25xx_rdp_port_speed_currently(struct qla_hw_data *ha)
* vha: SCSI qla host * vha: SCSI qla host
* purex: RDP request received by HBA * purex: RDP request received by HBA
*/ */
void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, void *pkt) void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
struct purex_item *item)
{ {
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
struct purex_entry_24xx *purex = pkt; struct purex_entry_24xx *purex =
(struct purex_entry_24xx *)&item->iocb;
dma_addr_t rsp_els_dma; dma_addr_t rsp_els_dma;
dma_addr_t rsp_payload_dma; dma_addr_t rsp_payload_dma;
dma_addr_t stat_dma; dma_addr_t stat_dma;
...@@ -6306,6 +6308,15 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, void *pkt) ...@@ -6306,6 +6308,15 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, void *pkt)
rsp_els, rsp_els_dma); rsp_els, rsp_els_dma);
} }
void
qla24xx_free_purex_item(struct purex_item *item)
{
if (item == &item->vha->default_item)
memset(&item->vha->default_item, 0, sizeof(struct purex_item));
else
kfree(item);
}
void qla24xx_process_purex_list(struct purex_list *list) void qla24xx_process_purex_list(struct purex_list *list)
{ {
struct list_head head = LIST_HEAD_INIT(head); struct list_head head = LIST_HEAD_INIT(head);
...@@ -6318,8 +6329,8 @@ void qla24xx_process_purex_list(struct purex_list *list) ...@@ -6318,8 +6329,8 @@ void qla24xx_process_purex_list(struct purex_list *list)
list_for_each_entry_safe(item, next, &head, list) { list_for_each_entry_safe(item, next, &head, list) {
list_del(&item->list); list_del(&item->list);
item->process_item(item->vha, &item->iocb); item->process_item(item->vha, item);
kfree(item); qla24xx_free_purex_item(item);
} }
} }
......
...@@ -41,6 +41,7 @@ enum fc_els_cmd { ...@@ -41,6 +41,7 @@ enum fc_els_cmd {
ELS_REC = 0x13, /* read exchange concise */ ELS_REC = 0x13, /* read exchange concise */
ELS_SRR = 0x14, /* sequence retransmission request */ ELS_SRR = 0x14, /* sequence retransmission request */
ELS_FPIN = 0x16, /* Fabric Performance Impact Notification */ ELS_FPIN = 0x16, /* Fabric Performance Impact Notification */
ELS_RDP = 0x18, /* Read Diagnostic Parameters */
ELS_RDF = 0x19, /* Register Diagnostic Functions */ ELS_RDF = 0x19, /* Register Diagnostic Functions */
ELS_PRLI = 0x20, /* process login */ ELS_PRLI = 0x20, /* process login */
ELS_PRLO = 0x21, /* process logout */ ELS_PRLO = 0x21, /* process logout */
...@@ -110,6 +111,7 @@ enum fc_els_cmd { ...@@ -110,6 +111,7 @@ enum fc_els_cmd {
[ELS_REC] = "REC", \ [ELS_REC] = "REC", \
[ELS_SRR] = "SRR", \ [ELS_SRR] = "SRR", \
[ELS_FPIN] = "FPIN", \ [ELS_FPIN] = "FPIN", \
[ELS_RDP] = "RDP", \
[ELS_RDF] = "RDF", \ [ELS_RDF] = "RDF", \
[ELS_PRLI] = "PRLI", \ [ELS_PRLI] = "PRLI", \
[ELS_PRLO] = "PRLO", \ [ELS_PRLO] = "PRLO", \
......
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