scsi: qla2xxx: Enhance purex_entry handling for 29xx series

Update function signatures and internal logic across qla_edif.c,
qla_isr.c, and qla_os.c to accept a generic pointer for packet data and
differentiate between standard purex_entry_24xx and the extended
purex_entry_24xx_ext structures based on IS_QLA29XX().

This ensures proper initialization and processing of command and
response data for both 64-byte and 128-byte PUREX IOCBs across all ELS
paths including auth_els, RDP, copy_std_pkt, copy_multiple_pkt,
consume_iocb, and copy_purex_to_buffer.

Where the two layouts overlap at byte-identical offsets (entry_count,
frame_size, nport_handle, rx_xchg_addr, ox_id, status_flags,
trunc_frame_size, s_id, d_id, els_frame_payload base, and
response_t::signature), use a single struct purex_entry_24xx * view to
avoid duplicating read paths.  Branch only where field encoding differs:
vp_idx (u8 at offset 6 in 24xx vs __le16 at offsets 6-7 in 29xx) and
els_frame_payload[] array length (20 vs 84 bytes, handled via a
sizeof_field()-based payload_size local).

Signed-off-by: Nilesh Javali <njavali@marvell.com>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Link: https://patch.msgid.link/20260723050413.3897522-29-njavali@marvell.com
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
Nilesh Javali
2026-07-23 10:33:45 +05:30
committed by Martin K. Petersen (Oracle)
parent c454800348
commit 7db93e3c58
4 changed files with 139 additions and 41 deletions

View File

@@ -5001,6 +5001,7 @@ struct active_regions {
#define QLA_SET_DATA_RATE_LR 2 /* Set speed and initiate LR */
#define QLA_DEFAULT_PAYLOAD_SIZE 64
#define QLA_MAX_IOCB_SIZE 128
/*
* This item might be allocated with a size > sizeof(struct purex_item).
* The "size" variable gives the size of the payload (which
@@ -5015,7 +5016,7 @@ struct purex_item {
atomic_t in_use;
uint16_t size;
struct {
uint8_t iocb[64];
u8 iocb[QLA_MAX_IOCB_SIZE];
} iocb;
};

View File

@@ -2534,7 +2534,7 @@ qla24xx_sa_replace_iocb(srb_t *sp, struct sa_update_28xx *sa_update_iocb)
void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
{
struct purex_entry_24xx *p = *pkt;
struct qla_hw_data *ha = vha->hw;
struct enode *ptr;
int sid;
u16 totlen;
@@ -2544,26 +2544,55 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
struct fc_port *fcport;
struct qla_els_pt_arg a;
be_id_t beid;
__le16 nport_handle;
__le32 rx_xchg_addr;
__le16 ox_id;
__le16 frame_size, status_flags, trunc_frame_size;
uint8_t s_id[3], d_id[3];
uint8_t vp_idx;
struct purex_entry_24xx *p = *pkt;
memset(&a, 0, sizeof(a));
/*
* purex_entry_24xx_ext (29xx) overlays purex_entry_24xx for every
* field touched here -- nport_handle, rx_xchg_addr, ox_id, frame_size,
* status_flags, trunc_frame_size, s_id[3], d_id[3] -- with only
* vp_idx differing in width (u8 at offset 6 vs __le16 at offsets 6-7,
* with reserved2 at offset 7 in the 24xx layout). So all reads but
* vp_idx go through a single struct purex_entry_24xx * view.
*/
nport_handle = p->nport_handle;
rx_xchg_addr = p->rx_xchg_addr;
ox_id = p->ox_id;
frame_size = p->frame_size;
status_flags = p->status_flags;
trunc_frame_size = p->trunc_frame_size;
memcpy(s_id, p->s_id, sizeof(s_id));
memcpy(d_id, p->d_id, sizeof(d_id));
if (IS_QLA29XX(ha))
vp_idx = le16_to_cpu(((struct purex_entry_24xx_ext *)
*pkt)->vp_idx);
else
vp_idx = p->vp_idx;
a.els_opcode = ELS_AUTH_ELS;
a.nport_handle = p->nport_handle;
a.rx_xchg_address = p->rx_xchg_addr;
a.did.b.domain = p->s_id[2];
a.did.b.area = p->s_id[1];
a.did.b.al_pa = p->s_id[0];
a.nport_handle = nport_handle;
a.rx_xchg_address = rx_xchg_addr;
a.did.b.domain = s_id[2];
a.did.b.area = s_id[1];
a.did.b.al_pa = s_id[0];
a.tx_byte_count = a.tx_len = sizeof(struct fc_els_ls_rjt);
a.tx_addr = vha->hw->elsrej.cdma;
a.tx_addr = ha->elsrej.cdma;
a.vp_idx = vha->vp_idx;
a.control_flags = EPD_ELS_RJT;
a.ox_id = le16_to_cpu(p->ox_id);
a.ox_id = le16_to_cpu(ox_id);
sid = p->s_id[0] | (p->s_id[1] << 8) | (p->s_id[2] << 16);
sid = s_id[0] | (s_id[1] << 8) | (s_id[2] << 16);
totlen = (le16_to_cpu(p->frame_size) & 0x0fff) - PURX_ELS_HEADER_SIZE;
if (le16_to_cpu(p->status_flags) & 0x8000) {
totlen = le16_to_cpu(p->trunc_frame_size);
totlen = (le16_to_cpu(frame_size) & 0x0fff) - PURX_ELS_HEADER_SIZE;
if (le16_to_cpu(status_flags) & 0x8000) {
totlen = le16_to_cpu(trunc_frame_size);
qla_els_reject_iocb(vha, (*rsp)->qpair, &a);
__qla_consume_iocb(vha, pkt, rsp);
return;
@@ -2600,12 +2629,12 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
purex = &ptr->u.purexinfo;
purex->pur_info.pur_sid = a.did;
purex->pur_info.pur_bytes_rcvd = totlen;
purex->pur_info.pur_rx_xchg_address = le32_to_cpu(p->rx_xchg_addr);
purex->pur_info.pur_nphdl = le16_to_cpu(p->nport_handle);
purex->pur_info.pur_did.b.domain = p->d_id[2];
purex->pur_info.pur_did.b.area = p->d_id[1];
purex->pur_info.pur_did.b.al_pa = p->d_id[0];
purex->pur_info.vp_idx = p->vp_idx;
purex->pur_info.pur_rx_xchg_address = le32_to_cpu(rx_xchg_addr);
purex->pur_info.pur_nphdl = le16_to_cpu(nport_handle);
purex->pur_info.pur_did.b.domain = d_id[2];
purex->pur_info.pur_did.b.area = d_id[1];
purex->pur_info.pur_did.b.al_pa = d_id[0];
purex->pur_info.vp_idx = vp_idx;
a.sid = purex->pur_info.pur_did;

View File

@@ -202,6 +202,11 @@ void __qla_consume_iocb(struct scsi_qla_host *vha,
struct rsp_que *rsp_q = *rsp;
response_t *new_pkt;
uint16_t entry_count_remaining;
/*
* entry_count is u8 at offset 1 in both purex_entry_24xx and
* purex_entry_24xx_ext, so the 24xx view is layout-compatible with
* either stride.
*/
struct purex_entry_24xx *purex = *pkt;
entry_count_remaining = purex->entry_count;
@@ -230,6 +235,14 @@ void __qla_consume_iocb(struct scsi_qla_host *vha,
int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,
void **pkt, struct rsp_que **rsp, u8 *buf, u32 buf_len)
{
/*
* purex_entry_24xx_ext overlays purex_entry_24xx for entry_count
* (offset 1), frame_size (offset 12) and els_frame_payload (offset
* 44, base address only -- the array size grows from 20 to 84
* bytes). Header fields are read through the 24xx view; the
* initial payload memcpy uses a purex_entry_24xx_ext pointer on
* 29xx so that FORTIFY_SOURCE sees the correct 84-byte source.
*/
struct purex_entry_24xx *purex = *pkt;
struct qla_hw_data *ha = vha->hw;
struct rsp_que *rsp_q = *rsp;
@@ -244,8 +257,8 @@ int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,
u16 tpad;
entry_count_remaining = purex->entry_count;
total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF)
- PURX_ELS_HEADER_SIZE;
total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF) -
PURX_ELS_HEADER_SIZE;
/*
* end of payload may not end in 4bytes boundary. Need to
@@ -262,14 +275,24 @@ int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,
}
pending_bytes = total_bytes = tpad;
no_bytes = (pending_bytes > sizeof(purex->els_frame_payload)) ?
sizeof(purex->els_frame_payload) : pending_bytes;
no_bytes = (pending_bytes > payload_size) ?
payload_size : pending_bytes;
if (IS_QLA29XX(ha)) {
struct purex_entry_24xx_ext *purex_ext = *pkt;
memcpy(buf, &purex->els_frame_payload[0], no_bytes);
memcpy(buf, &purex_ext->els_frame_payload[0], no_bytes);
} else {
memcpy(buf, &purex->els_frame_payload[0], no_bytes);
}
buffer_copy_offset += no_bytes;
pending_bytes -= no_bytes;
--entry_count_remaining;
/*
* response_t::signature and struct response_ext::signature are both u32
* at offset 60 (handle:4 + data[52]:60), so the 24xx view writes
* the right slot regardless of stride.
*/
((response_t *)purex)->signature = RESPONSE_PROCESSED;
/* flush signature */
wmb();
@@ -849,6 +872,7 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
struct rsp_que **rsp, bool is_purls,
bool byte_order)
{
struct purex_entry_24xx_ext *purex_ext = NULL;
struct purex_entry_24xx *purex = NULL;
struct pt_ls4_rx_unsol *purls = NULL;
struct qla_hw_data *ha = vha->hw;
@@ -867,6 +891,13 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
PURX_ELS_HEADER_SIZE;
entry_count = entry_count_remaining = purls->entry_count;
payload_size = sizeof(purls->payload);
} else if (IS_QLA29XX(ha)) {
purex_ext = *pkt;
total_bytes = (le16_to_cpu(purex_ext->frame_size) & 0x0FFF) -
PURX_ELS_HEADER_SIZE;
entry_count = entry_count_remaining =
purex_ext->entry_count;
payload_size = sizeof(purex_ext->els_frame_payload);
} else {
purex = *pkt;
total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF) -
@@ -875,8 +906,8 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
payload_size = sizeof(purex->els_frame_payload);
}
if (total_bytes > sizeof(item->iocb.iocb))
total_bytes = sizeof(item->iocb.iocb);
if (total_bytes > QLA_MAX_IOCB_SIZE)
total_bytes = QLA_MAX_IOCB_SIZE;
pending_bytes = total_bytes;
no_bytes = (pending_bytes > payload_size) ? payload_size :
@@ -893,6 +924,8 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
if (is_purls)
memcpy(iocb_pkt, &purls->payload[0], no_bytes);
else if (IS_QLA29XX(ha))
memcpy(iocb_pkt, &purex_ext->els_frame_payload[0], no_bytes);
else
memcpy(iocb_pkt, &purex->els_frame_payload[0], no_bytes);
buffer_copy_offset += no_bytes;
@@ -901,6 +934,8 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
if (is_purls)
((response_t *)purls)->signature = RESPONSE_PROCESSED;
else if (IS_QLA29XX(ha))
((struct response_ext *)purex_ext)->signature = RESPONSE_PROCESSED;
else
((response_t *)purex)->signature = RESPONSE_PROCESSED;
wmb();
@@ -1075,9 +1110,9 @@ 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) {
if (size > QLA_MAX_IOCB_SIZE) {
item = kzalloc(item_hdr_size +
(size - QLA_DEFAULT_PAYLOAD_SIZE), GFP_ATOMIC);
(size - QLA_MAX_IOCB_SIZE), GFP_ATOMIC);
} else {
if (atomic_inc_return(&vha->default_item.in_use) == 1) {
item = &vha->default_item;
@@ -1126,14 +1161,20 @@ qla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt,
static struct purex_item
*qla24xx_copy_std_pkt(struct scsi_qla_host *vha, void *pkt)
{
struct qla_hw_data *ha = vha->hw;
struct purex_item *item;
u16 copy_sz;
item = qla24xx_alloc_purex_item(vha,
QLA_DEFAULT_PAYLOAD_SIZE);
if (IS_QLA29XX(ha))
copy_sz = sizeof(struct purex_entry_24xx_ext);
else
copy_sz = QLA_DEFAULT_PAYLOAD_SIZE;
item = qla24xx_alloc_purex_item(vha, copy_sz);
if (!item)
return item;
memcpy(&item->iocb, pkt, sizeof(item->iocb));
memcpy(&item->iocb, pkt, copy_sz);
return item;
}
@@ -1165,8 +1206,8 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF)
- PURX_ELS_HEADER_SIZE;
if (total_bytes > sizeof(item->iocb.iocb))
total_bytes = sizeof(item->iocb.iocb);
if (total_bytes > QLA_MAX_IOCB_SIZE)
total_bytes = QLA_MAX_IOCB_SIZE;
pending_bytes = total_bytes;
entry_count = entry_count_remaining = purex->entry_count;
@@ -3996,6 +4037,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
{
void *pkt;
struct qla_hw_data *ha = vha->hw;
struct purex_entry_24xx_ext *purex_entry_ext;
struct purex_entry_24xx *purex_entry;
struct purex_item *pure_item;
struct pt_ls4_rx_unsol *p;
@@ -4113,8 +4155,16 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
(struct vp_ctrl_entry_24xx *)pkt);
break;
case PUREX_IOCB_TYPE:
purex_entry = (void *)pkt;
switch (purex_entry->els_frame_payload[3]) {
if (IS_QLA29XX(ha)) {
purex_entry_ext = (void *)pkt;
purex_entry = NULL;
} else {
purex_entry = (void *)pkt;
purex_entry_ext = NULL;
}
switch (IS_QLA29XX(ha) ?
purex_entry_ext->els_frame_payload[3] :
purex_entry->els_frame_payload[3]) {
case ELS_RDP:
pure_item = qla24xx_copy_std_pkt(vha, pkt);
if (!pure_item)
@@ -4151,6 +4201,8 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
ql_dbg(ql_dbg_init, vha, 0x5091,
"Defer processing ELS opcode %#x...\n",
IS_QLA29XX(ha) ?
purex_entry_ext->els_frame_payload[3] :
purex_entry->els_frame_payload[3]);
return;
}
@@ -4158,7 +4210,9 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
break;
default:
ql_log(ql_log_warn, vha, 0x509c,
"Discarding ELS Request opcode 0x%x\n",
"Discarding ELS Request opcode 0x%x...\n",
IS_QLA29XX(ha) ?
purex_entry_ext->els_frame_payload[3] :
purex_entry->els_frame_payload[3]);
}
break;

View File

@@ -6138,13 +6138,15 @@ qla83xx_idc_lock(scsi_qla_host_t *base_vha, uint16_t requester_id)
}
static bool
qla25xx_rdp_rsp_reduce_size(struct scsi_qla_host *vha,
struct purex_entry_24xx *purex)
qla25xx_rdp_rsp_reduce_size(struct scsi_qla_host *vha, void *pkt)
{
struct purex_entry_24xx *purex = pkt;
char fwstr[16];
u32 sid = purex->s_id[2] << 16 | purex->s_id[1] << 8 | purex->s_id[0];
u32 sid;
struct port_database_24xx *pdb;
sid = purex->s_id[2] << 16 | purex->s_id[1] << 8 | purex->s_id[0];
/* Domain Controller is always logged-out. */
/* if RDP request is not from Domain Controller: */
if (sid != 0xfffc01)
@@ -6209,15 +6211,26 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
uint8_t *sfp = NULL;
uint16_t sfp_flags = 0;
uint rsp_payload_length = sizeof(*rsp_payload);
uint8_t vp_idx;
size_t purex_sz;
int rval;
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0180,
"%s: Enter\n", __func__);
if (IS_QLA29XX(ha)) {
vp_idx = le16_to_cpu(
((struct purex_entry_24xx_ext *)purex)->vp_idx);
purex_sz = sizeof(struct purex_entry_24xx_ext);
} else {
vp_idx = purex->vp_idx;
purex_sz = sizeof(*purex);
}
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0181,
"-------- ELS REQ -------\n");
ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0182,
purex, sizeof(*purex));
purex, purex_sz);
if (qla25xx_rdp_rsp_reduce_size(vha, purex)) {
rsp_payload_length =
@@ -6257,7 +6270,7 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
rsp_els->handle = 0;
rsp_els->nport_handle = purex->nport_handle;
rsp_els->tx_dsd_count = cpu_to_le16(1);
rsp_els->vp_index = purex->vp_idx;
rsp_els->vp_index = vp_idx;
rsp_els->sof_type = EST_SOFI3;
rsp_els->rx_xchg_address = purex->rx_xchg_addr;
rsp_els->rx_dsd_count = 0;
@@ -8378,6 +8391,7 @@ qla2x00_module_init(void)
BUILD_BUG_ON(sizeof(struct pt_ls4_request) != 64);
BUILD_BUG_ON(sizeof(struct pt_ls4_rx_unsol) != 64);
BUILD_BUG_ON(sizeof(struct purex_entry_24xx) != 64);
BUILD_BUG_ON(sizeof(struct purex_entry_24xx_ext) != 128);
BUILD_BUG_ON(sizeof(struct qla2100_fw_dump) != 123634);
BUILD_BUG_ON(sizeof(struct qla2300_fw_dump) != 136100);
BUILD_BUG_ON(sizeof(struct qla24xx_fw_dump) != 37976);