scsi: qla2xxx: Add Unsolicited LS Request and Response Support for NVMe
Introduce infrastructure in the driver to support the processing of unsolicited LS (Link Service) requests. This will involve the utilization of a new pass-up of unsolicited FC-NVMe request IOCB interface. Unsolicited requests will be submitted to the NVMe transport layer through nvme_fc_rcv_ls_req(). Any received LS responses, which are sent using xmt_ls_rsp(), will be forwarded to the firmware through the existing Pass-Through IOCB interface, responsible for sending FC-NVMe Link Service requests and responses. Signed-off-by: Manish Rangankar <mrangankar@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Link: https://lore.kernel.org/r/20230821130045.34850-2-njavali@marvell.com Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
ae25f65a35
commit
875386b988
11 changed files with 642 additions and 34 deletions
|
@ -12,9 +12,8 @@
|
||||||
* ----------------------------------------------------------------------
|
* ----------------------------------------------------------------------
|
||||||
* | Module Init and Probe | 0x0199 | |
|
* | Module Init and Probe | 0x0199 | |
|
||||||
* | Mailbox commands | 0x1206 | 0x11a5-0x11ff |
|
* | Mailbox commands | 0x1206 | 0x11a5-0x11ff |
|
||||||
* | Device Discovery | 0x2134 | 0x210e-0x2115 |
|
* | Device Discovery | 0x2134 | 0x2112-0x2115 |
|
||||||
* | | | 0x211c-0x2128 |
|
* | | | 0x2127-0x2128 |
|
||||||
* | | | 0x212c-0x2134 |
|
|
||||||
* | Queue Command and IO tracing | 0x3074 | 0x300b |
|
* | Queue Command and IO tracing | 0x3074 | 0x300b |
|
||||||
* | | | 0x3027-0x3028 |
|
* | | | 0x3027-0x3028 |
|
||||||
* | | | 0x303d-0x3041 |
|
* | | | 0x303d-0x3041 |
|
||||||
|
|
|
@ -368,6 +368,7 @@ ql_log_qp(uint32_t, struct qla_qpair *, int32_t, const char *fmt, ...);
|
||||||
#define ql_dbg_tgt_tmr 0x00001000 /* Target mode task management */
|
#define ql_dbg_tgt_tmr 0x00001000 /* Target mode task management */
|
||||||
#define ql_dbg_tgt_dif 0x00000800 /* Target mode dif */
|
#define ql_dbg_tgt_dif 0x00000800 /* Target mode dif */
|
||||||
#define ql_dbg_edif 0x00000400 /* edif and purex debug */
|
#define ql_dbg_edif 0x00000400 /* edif and purex debug */
|
||||||
|
#define ql_dbg_unsol 0x00000100 /* Unsolicited path debug */
|
||||||
|
|
||||||
extern int qla27xx_dump_mpi_ram(struct qla_hw_data *, uint32_t, uint32_t *,
|
extern int qla27xx_dump_mpi_ram(struct qla_hw_data *, uint32_t, uint32_t *,
|
||||||
uint32_t, void **);
|
uint32_t, void **);
|
||||||
|
|
|
@ -346,6 +346,12 @@ struct name_list_extended {
|
||||||
u8 sent;
|
u8 sent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct qla_nvme_fc_rjt {
|
||||||
|
struct fcnvme_ls_rjt *c;
|
||||||
|
dma_addr_t cdma;
|
||||||
|
u16 size;
|
||||||
|
};
|
||||||
|
|
||||||
struct els_reject {
|
struct els_reject {
|
||||||
struct fc_els_ls_rjt *c;
|
struct fc_els_ls_rjt *c;
|
||||||
dma_addr_t cdma;
|
dma_addr_t cdma;
|
||||||
|
@ -503,6 +509,20 @@ struct ct_arg {
|
||||||
port_id_t id;
|
port_id_t id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct qla_nvme_lsrjt_pt_arg {
|
||||||
|
struct fc_port *fcport;
|
||||||
|
u8 opcode;
|
||||||
|
u8 vp_idx;
|
||||||
|
u8 reason;
|
||||||
|
u8 explanation;
|
||||||
|
__le16 nport_handle;
|
||||||
|
u16 control_flags;
|
||||||
|
__le16 ox_id;
|
||||||
|
__le32 xchg_address;
|
||||||
|
u32 tx_byte_count, rx_byte_count;
|
||||||
|
dma_addr_t tx_addr, rx_addr;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SRB extensions.
|
* SRB extensions.
|
||||||
*/
|
*/
|
||||||
|
@ -611,13 +631,16 @@ struct srb_iocb {
|
||||||
void *desc;
|
void *desc;
|
||||||
|
|
||||||
/* These are only used with ls4 requests */
|
/* These are only used with ls4 requests */
|
||||||
int cmd_len;
|
__le32 cmd_len;
|
||||||
int rsp_len;
|
__le32 rsp_len;
|
||||||
dma_addr_t cmd_dma;
|
dma_addr_t cmd_dma;
|
||||||
dma_addr_t rsp_dma;
|
dma_addr_t rsp_dma;
|
||||||
enum nvmefc_fcp_datadir dir;
|
enum nvmefc_fcp_datadir dir;
|
||||||
uint32_t dl;
|
uint32_t dl;
|
||||||
uint32_t timeout_sec;
|
uint32_t timeout_sec;
|
||||||
|
__le32 exchange_address;
|
||||||
|
__le16 nport_handle;
|
||||||
|
__le16 ox_id;
|
||||||
struct list_head entry;
|
struct list_head entry;
|
||||||
} nvme;
|
} nvme;
|
||||||
struct {
|
struct {
|
||||||
|
@ -707,6 +730,10 @@ typedef struct srb {
|
||||||
struct fc_port *fcport;
|
struct fc_port *fcport;
|
||||||
struct scsi_qla_host *vha;
|
struct scsi_qla_host *vha;
|
||||||
unsigned int start_timer:1;
|
unsigned int start_timer:1;
|
||||||
|
unsigned int abort:1;
|
||||||
|
unsigned int aborted:1;
|
||||||
|
unsigned int completed:1;
|
||||||
|
unsigned int unsol_rsp:1;
|
||||||
|
|
||||||
uint32_t handle;
|
uint32_t handle;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
|
@ -2542,6 +2569,7 @@ enum rscn_addr_format {
|
||||||
typedef struct fc_port {
|
typedef struct fc_port {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct scsi_qla_host *vha;
|
struct scsi_qla_host *vha;
|
||||||
|
struct list_head unsol_ctx_head;
|
||||||
|
|
||||||
unsigned int conf_compl_supported:1;
|
unsigned int conf_compl_supported:1;
|
||||||
unsigned int deleted:2;
|
unsigned int deleted:2;
|
||||||
|
@ -4802,6 +4830,7 @@ struct qla_hw_data {
|
||||||
struct els_reject elsrej;
|
struct els_reject elsrej;
|
||||||
u8 edif_post_stop_cnt_down;
|
u8 edif_post_stop_cnt_down;
|
||||||
struct qla_vp_map *vp_map;
|
struct qla_vp_map *vp_map;
|
||||||
|
struct qla_nvme_fc_rjt lsrjt;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RX_ELS_SIZE (roundup(sizeof(struct enode) + ELS_MAX_PAYLOAD, SMP_CACHE_BYTES))
|
#define RX_ELS_SIZE (roundup(sizeof(struct enode) + ELS_MAX_PAYLOAD, SMP_CACHE_BYTES))
|
||||||
|
@ -4834,6 +4863,7 @@ struct active_regions {
|
||||||
* is variable) starting at "iocb".
|
* is variable) starting at "iocb".
|
||||||
*/
|
*/
|
||||||
struct purex_item {
|
struct purex_item {
|
||||||
|
void *purls_context;
|
||||||
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 (*process_item)(struct scsi_qla_host *vha,
|
||||||
|
|
|
@ -611,7 +611,11 @@ qla2xxx_msix_rsp_q_hs(int irq, void *dev_id);
|
||||||
fc_port_t *qla2x00_find_fcport_by_loopid(scsi_qla_host_t *, uint16_t);
|
fc_port_t *qla2x00_find_fcport_by_loopid(scsi_qla_host_t *, uint16_t);
|
||||||
fc_port_t *qla2x00_find_fcport_by_wwpn(scsi_qla_host_t *, u8 *, u8);
|
fc_port_t *qla2x00_find_fcport_by_wwpn(scsi_qla_host_t *, u8 *, u8);
|
||||||
fc_port_t *qla2x00_find_fcport_by_nportid(scsi_qla_host_t *, port_id_t *, u8);
|
fc_port_t *qla2x00_find_fcport_by_nportid(scsi_qla_host_t *, port_id_t *, u8);
|
||||||
void __qla_consume_iocb(struct scsi_qla_host *vha, void **pkt, struct rsp_que **rsp);
|
void qla24xx_queue_purex_item(scsi_qla_host_t *, struct purex_item *,
|
||||||
|
void (*process_item)(struct scsi_qla_host *,
|
||||||
|
struct purex_item *));
|
||||||
|
void __qla_consume_iocb(struct scsi_qla_host *, void **, struct rsp_que **);
|
||||||
|
void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global Function Prototypes in qla_sup.c source file.
|
* Global Function Prototypes in qla_sup.c source file.
|
||||||
|
@ -674,9 +678,11 @@ extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);
|
||||||
extern void qla2xxx_flash_npiv_conf(scsi_qla_host_t *);
|
extern void qla2xxx_flash_npiv_conf(scsi_qla_host_t *);
|
||||||
extern int qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *);
|
extern int qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *);
|
||||||
extern int qla2x00_mailbox_passthru(struct bsg_job *bsg_job);
|
extern int qla2x00_mailbox_passthru(struct bsg_job *bsg_job);
|
||||||
int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha, void **pkt,
|
int qla2x00_sys_ld_info(struct bsg_job *bsg_job);
|
||||||
struct rsp_que **rsp, u8 *buf, u32 buf_len);
|
int __qla_copy_purex_to_buffer(struct scsi_qla_host *, void **,
|
||||||
|
struct rsp_que **, u8 *, u32);
|
||||||
|
struct purex_item *qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha,
|
||||||
|
void **pkt, struct rsp_que **rsp, bool is_purls, bool byte_order);
|
||||||
int qla_mailbox_passthru(scsi_qla_host_t *vha, uint16_t *mbx_in,
|
int qla_mailbox_passthru(scsi_qla_host_t *vha, uint16_t *mbx_in,
|
||||||
uint16_t *mbx_out);
|
uint16_t *mbx_out);
|
||||||
|
|
||||||
|
|
|
@ -5554,6 +5554,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
|
||||||
INIT_WORK(&fcport->reg_work, qla_register_fcport_fn);
|
INIT_WORK(&fcport->reg_work, qla_register_fcport_fn);
|
||||||
INIT_LIST_HEAD(&fcport->gnl_entry);
|
INIT_LIST_HEAD(&fcport->gnl_entry);
|
||||||
INIT_LIST_HEAD(&fcport->list);
|
INIT_LIST_HEAD(&fcport->list);
|
||||||
|
INIT_LIST_HEAD(&fcport->unsol_ctx_head);
|
||||||
|
|
||||||
INIT_LIST_HEAD(&fcport->sess_cmd_list);
|
INIT_LIST_HEAD(&fcport->sess_cmd_list);
|
||||||
spin_lock_init(&fcport->sess_cmd_lock);
|
spin_lock_init(&fcport->sess_cmd_lock);
|
||||||
|
|
|
@ -3771,23 +3771,30 @@ qla_nvme_ls(srb_t *sp, struct pt_ls4_request *cmd_pkt)
|
||||||
nvme = &sp->u.iocb_cmd;
|
nvme = &sp->u.iocb_cmd;
|
||||||
cmd_pkt->entry_type = PT_LS4_REQUEST;
|
cmd_pkt->entry_type = PT_LS4_REQUEST;
|
||||||
cmd_pkt->entry_count = 1;
|
cmd_pkt->entry_count = 1;
|
||||||
cmd_pkt->control_flags = cpu_to_le16(CF_LS4_ORIGINATOR << CF_LS4_SHIFT);
|
|
||||||
|
|
||||||
cmd_pkt->timeout = cpu_to_le16(nvme->u.nvme.timeout_sec);
|
cmd_pkt->timeout = cpu_to_le16(nvme->u.nvme.timeout_sec);
|
||||||
cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
|
|
||||||
cmd_pkt->vp_index = sp->fcport->vha->vp_idx;
|
cmd_pkt->vp_index = sp->fcport->vha->vp_idx;
|
||||||
|
|
||||||
cmd_pkt->tx_dseg_count = cpu_to_le16(1);
|
if (sp->unsol_rsp) {
|
||||||
cmd_pkt->tx_byte_count = cpu_to_le32(nvme->u.nvme.cmd_len);
|
cmd_pkt->control_flags =
|
||||||
cmd_pkt->dsd[0].length = cpu_to_le32(nvme->u.nvme.cmd_len);
|
cpu_to_le16(CF_LS4_RESPONDER << CF_LS4_SHIFT);
|
||||||
put_unaligned_le64(nvme->u.nvme.cmd_dma, &cmd_pkt->dsd[0].address);
|
cmd_pkt->nport_handle = nvme->u.nvme.nport_handle;
|
||||||
|
cmd_pkt->exchange_address = nvme->u.nvme.exchange_address;
|
||||||
|
} else {
|
||||||
|
cmd_pkt->control_flags =
|
||||||
|
cpu_to_le16(CF_LS4_ORIGINATOR << CF_LS4_SHIFT);
|
||||||
|
cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
|
||||||
cmd_pkt->rx_dseg_count = cpu_to_le16(1);
|
cmd_pkt->rx_dseg_count = cpu_to_le16(1);
|
||||||
cmd_pkt->rx_byte_count = cpu_to_le32(nvme->u.nvme.rsp_len);
|
cmd_pkt->rx_byte_count = nvme->u.nvme.rsp_len;
|
||||||
cmd_pkt->dsd[1].length = cpu_to_le32(nvme->u.nvme.rsp_len);
|
cmd_pkt->dsd[1].length = nvme->u.nvme.rsp_len;
|
||||||
put_unaligned_le64(nvme->u.nvme.rsp_dma, &cmd_pkt->dsd[1].address);
|
put_unaligned_le64(nvme->u.nvme.rsp_dma, &cmd_pkt->dsd[1].address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd_pkt->tx_dseg_count = cpu_to_le16(1);
|
||||||
|
cmd_pkt->tx_byte_count = nvme->u.nvme.cmd_len;
|
||||||
|
cmd_pkt->dsd[0].length = nvme->u.nvme.cmd_len;
|
||||||
|
put_unaligned_le64(nvme->u.nvme.cmd_dma, &cmd_pkt->dsd[0].address);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
qla25xx_ctrlvp_iocb(srb_t *sp, struct vp_ctrl_entry_24xx *vce)
|
qla25xx_ctrlvp_iocb(srb_t *sp, struct vp_ctrl_entry_24xx *vce)
|
||||||
{
|
{
|
||||||
|
|
|
@ -823,6 +823,135 @@ qla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qla27xx_copy_multiple_pkt() - Copy over purex/purls packets that can
|
||||||
|
* span over multiple IOCBs.
|
||||||
|
* @vha: SCSI driver HA context
|
||||||
|
* @pkt: ELS packet
|
||||||
|
* @rsp: Response queue
|
||||||
|
* @is_purls: True, for Unsolicited Received FC-NVMe LS rsp IOCB
|
||||||
|
* false, for Unsolicited Received ELS IOCB
|
||||||
|
* @byte_order: True, to change the byte ordering of iocb payload
|
||||||
|
*/
|
||||||
|
struct purex_item *
|
||||||
|
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 *purex = NULL;
|
||||||
|
struct pt_ls4_rx_unsol *purls = NULL;
|
||||||
|
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, payload_size = 0;
|
||||||
|
uint16_t entry_count, entry_count_remaining;
|
||||||
|
struct purex_item *item;
|
||||||
|
void *iocb_pkt = NULL;
|
||||||
|
|
||||||
|
if (is_purls) {
|
||||||
|
purls = *pkt;
|
||||||
|
total_bytes = (le16_to_cpu(purls->frame_size) & 0x0FFF) -
|
||||||
|
PURX_ELS_HEADER_SIZE;
|
||||||
|
entry_count = entry_count_remaining = purls->entry_count;
|
||||||
|
payload_size = sizeof(purls->payload);
|
||||||
|
} else {
|
||||||
|
purex = *pkt;
|
||||||
|
total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF) -
|
||||||
|
PURX_ELS_HEADER_SIZE;
|
||||||
|
entry_count = entry_count_remaining = purex->entry_count;
|
||||||
|
payload_size = sizeof(purex->els_frame_payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
pending_bytes = total_bytes;
|
||||||
|
no_bytes = (pending_bytes > payload_size) ? payload_size :
|
||||||
|
pending_bytes;
|
||||||
|
ql_dbg(ql_dbg_async, vha, 0x509a,
|
||||||
|
"%s LS, frame_size 0x%x, entry count %d\n",
|
||||||
|
(is_purls ? "PURLS" : "FPIN"), total_bytes, entry_count);
|
||||||
|
|
||||||
|
item = qla24xx_alloc_purex_item(vha, total_bytes);
|
||||||
|
if (!item)
|
||||||
|
return item;
|
||||||
|
|
||||||
|
iocb_pkt = &item->iocb;
|
||||||
|
|
||||||
|
if (is_purls)
|
||||||
|
memcpy(iocb_pkt, &purls->payload[0], no_bytes);
|
||||||
|
else
|
||||||
|
memcpy(iocb_pkt, &purex->els_frame_payload[0], no_bytes);
|
||||||
|
buffer_copy_offset += no_bytes;
|
||||||
|
pending_bytes -= no_bytes;
|
||||||
|
--entry_count_remaining;
|
||||||
|
|
||||||
|
if (is_purls)
|
||||||
|
((response_t *)purls)->signature = RESPONSE_PROCESSED;
|
||||||
|
else
|
||||||
|
((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 *)iocb_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 *)iocb_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);
|
||||||
|
|
||||||
|
if (byte_order)
|
||||||
|
host_to_fcp_swap((uint8_t *)&item->iocb, total_bytes);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
qla2x00_is_a_vp_did(scsi_qla_host_t *vha, uint32_t rscn_entry)
|
qla2x00_is_a_vp_did(scsi_qla_host_t *vha, uint32_t rscn_entry)
|
||||||
{
|
{
|
||||||
|
@ -958,7 +1087,7 @@ initialize_purex_header:
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
qla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt,
|
qla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt,
|
||||||
void (*process_item)(struct scsi_qla_host *vha,
|
void (*process_item)(struct scsi_qla_host *vha,
|
||||||
struct purex_item *pkt))
|
struct purex_item *pkt))
|
||||||
|
@ -3811,6 +3940,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
|
||||||
struct qla_hw_data *ha = vha->hw;
|
struct qla_hw_data *ha = vha->hw;
|
||||||
struct purex_entry_24xx *purex_entry;
|
struct purex_entry_24xx *purex_entry;
|
||||||
struct purex_item *pure_item;
|
struct purex_item *pure_item;
|
||||||
|
struct pt_ls4_rx_unsol *p;
|
||||||
u16 rsp_in = 0, cur_ring_index;
|
u16 rsp_in = 0, cur_ring_index;
|
||||||
int is_shadow_hba;
|
int is_shadow_hba;
|
||||||
|
|
||||||
|
@ -3983,7 +4113,19 @@ process_err:
|
||||||
qla28xx_sa_update_iocb_entry(vha, rsp->req,
|
qla28xx_sa_update_iocb_entry(vha, rsp->req,
|
||||||
(struct sa_update_28xx *)pkt);
|
(struct sa_update_28xx *)pkt);
|
||||||
break;
|
break;
|
||||||
|
case PT_LS4_UNSOL:
|
||||||
|
p = (void *)pkt;
|
||||||
|
if (qla_chk_cont_iocb_avail(vha, rsp, (response_t *)pkt, rsp_in)) {
|
||||||
|
rsp->ring_ptr = (response_t *)pkt;
|
||||||
|
rsp->ring_index = cur_ring_index;
|
||||||
|
|
||||||
|
ql_dbg(ql_dbg_init, vha, 0x2124,
|
||||||
|
"Defer processing UNSOL LS req opcode %#x...\n",
|
||||||
|
p->payload[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qla2xxx_process_purls_iocb((void **)&pkt, &rsp);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* Type Not Supported. */
|
/* Type Not Supported. */
|
||||||
ql_dbg(ql_dbg_async, vha, 0x5042,
|
ql_dbg(ql_dbg_async, vha, 0x5042,
|
||||||
|
|
|
@ -12,6 +12,26 @@
|
||||||
#include <linux/blk-mq.h>
|
#include <linux/blk-mq.h>
|
||||||
|
|
||||||
static struct nvme_fc_port_template qla_nvme_fc_transport;
|
static struct nvme_fc_port_template qla_nvme_fc_transport;
|
||||||
|
static int qla_nvme_ls_reject_iocb(struct scsi_qla_host *vha,
|
||||||
|
struct qla_qpair *qp,
|
||||||
|
struct qla_nvme_lsrjt_pt_arg *a,
|
||||||
|
bool is_xchg_terminate);
|
||||||
|
|
||||||
|
struct qla_nvme_unsol_ctx {
|
||||||
|
struct list_head elem;
|
||||||
|
struct scsi_qla_host *vha;
|
||||||
|
struct fc_port *fcport;
|
||||||
|
struct srb *sp;
|
||||||
|
struct nvmefc_ls_rsp lsrsp;
|
||||||
|
struct nvmefc_ls_rsp *fd_rsp;
|
||||||
|
struct work_struct lsrsp_work;
|
||||||
|
struct work_struct abort_work;
|
||||||
|
__le32 exchange_address;
|
||||||
|
__le16 nport_handle;
|
||||||
|
__le16 ox_id;
|
||||||
|
int comp_status;
|
||||||
|
spinlock_t cmd_lock;
|
||||||
|
};
|
||||||
|
|
||||||
int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
|
int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
|
||||||
{
|
{
|
||||||
|
@ -216,6 +236,55 @@ static void qla_nvme_sp_ls_done(srb_t *sp, int res)
|
||||||
schedule_work(&priv->ls_work);
|
schedule_work(&priv->ls_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qla_nvme_release_lsrsp_cmd_kref(struct kref *kref)
|
||||||
|
{
|
||||||
|
struct srb *sp = container_of(kref, struct srb, cmd_kref);
|
||||||
|
struct qla_nvme_unsol_ctx *uctx = sp->priv;
|
||||||
|
struct nvmefc_ls_rsp *fd_rsp;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (!uctx) {
|
||||||
|
qla2x00_rel_sp(sp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&uctx->cmd_lock, flags);
|
||||||
|
uctx->sp = NULL;
|
||||||
|
sp->priv = NULL;
|
||||||
|
spin_unlock_irqrestore(&uctx->cmd_lock, flags);
|
||||||
|
|
||||||
|
fd_rsp = uctx->fd_rsp;
|
||||||
|
|
||||||
|
list_del(&uctx->elem);
|
||||||
|
|
||||||
|
fd_rsp->done(fd_rsp);
|
||||||
|
kfree(uctx);
|
||||||
|
qla2x00_rel_sp(sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qla_nvme_lsrsp_complete(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct qla_nvme_unsol_ctx *uctx =
|
||||||
|
container_of(work, struct qla_nvme_unsol_ctx, lsrsp_work);
|
||||||
|
|
||||||
|
kref_put(&uctx->sp->cmd_kref, qla_nvme_release_lsrsp_cmd_kref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qla_nvme_sp_lsrsp_done(srb_t *sp, int res)
|
||||||
|
{
|
||||||
|
struct qla_nvme_unsol_ctx *uctx = sp->priv;
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(kref_read(&sp->cmd_kref) == 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
res = -EINVAL;
|
||||||
|
|
||||||
|
uctx->comp_status = res;
|
||||||
|
INIT_WORK(&uctx->lsrsp_work, qla_nvme_lsrsp_complete);
|
||||||
|
schedule_work(&uctx->lsrsp_work);
|
||||||
|
}
|
||||||
|
|
||||||
/* it assumed that QPair lock is held. */
|
/* it assumed that QPair lock is held. */
|
||||||
static void qla_nvme_sp_done(srb_t *sp, int res)
|
static void qla_nvme_sp_done(srb_t *sp, int res)
|
||||||
{
|
{
|
||||||
|
@ -288,6 +357,92 @@ out:
|
||||||
kref_put(&sp->cmd_kref, sp->put_fn);
|
kref_put(&sp->cmd_kref, sp->put_fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport,
|
||||||
|
struct nvme_fc_remote_port *rport,
|
||||||
|
struct nvmefc_ls_rsp *fd_resp)
|
||||||
|
{
|
||||||
|
struct qla_nvme_unsol_ctx *uctx = container_of(fd_resp,
|
||||||
|
struct qla_nvme_unsol_ctx, lsrsp);
|
||||||
|
struct qla_nvme_rport *qla_rport = rport->private;
|
||||||
|
fc_port_t *fcport = qla_rport->fcport;
|
||||||
|
struct scsi_qla_host *vha = uctx->vha;
|
||||||
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
struct qla_nvme_lsrjt_pt_arg a;
|
||||||
|
struct srb_iocb *nvme;
|
||||||
|
srb_t *sp;
|
||||||
|
int rval = QLA_FUNCTION_FAILED;
|
||||||
|
uint8_t cnt = 0;
|
||||||
|
|
||||||
|
if (!fcport || fcport->deleted)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!ha->flags.fw_started)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Alloc SRB structure */
|
||||||
|
sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
|
||||||
|
if (!sp)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
sp->type = SRB_NVME_LS;
|
||||||
|
sp->name = "nvme_ls";
|
||||||
|
sp->done = qla_nvme_sp_lsrsp_done;
|
||||||
|
sp->put_fn = qla_nvme_release_lsrsp_cmd_kref;
|
||||||
|
sp->priv = (void *)uctx;
|
||||||
|
sp->unsol_rsp = 1;
|
||||||
|
uctx->sp = sp;
|
||||||
|
spin_lock_init(&uctx->cmd_lock);
|
||||||
|
nvme = &sp->u.iocb_cmd;
|
||||||
|
uctx->fd_rsp = fd_resp;
|
||||||
|
nvme->u.nvme.desc = fd_resp;
|
||||||
|
nvme->u.nvme.dir = 0;
|
||||||
|
nvme->u.nvme.dl = 0;
|
||||||
|
nvme->u.nvme.timeout_sec = 0;
|
||||||
|
nvme->u.nvme.cmd_dma = fd_resp->rspdma;
|
||||||
|
nvme->u.nvme.cmd_len = fd_resp->rsplen;
|
||||||
|
nvme->u.nvme.rsp_len = 0;
|
||||||
|
nvme->u.nvme.rsp_dma = 0;
|
||||||
|
nvme->u.nvme.exchange_address = uctx->exchange_address;
|
||||||
|
nvme->u.nvme.nport_handle = uctx->nport_handle;
|
||||||
|
nvme->u.nvme.ox_id = uctx->ox_id;
|
||||||
|
dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma,
|
||||||
|
le32_to_cpu(fd_resp->rsplen), DMA_TO_DEVICE);
|
||||||
|
|
||||||
|
ql_dbg(ql_dbg_unsol, vha, 0x2122,
|
||||||
|
"Unsol lsreq portid=%06x %8phC exchange_address 0x%x ox_id 0x%x hdl 0x%x\n",
|
||||||
|
fcport->d_id.b24, fcport->port_name, uctx->exchange_address,
|
||||||
|
uctx->ox_id, uctx->nport_handle);
|
||||||
|
retry:
|
||||||
|
rval = qla2x00_start_sp(sp);
|
||||||
|
switch (rval) {
|
||||||
|
case QLA_SUCCESS:
|
||||||
|
break;
|
||||||
|
case EAGAIN:
|
||||||
|
msleep(PURLS_MSLEEP_INTERVAL);
|
||||||
|
cnt++;
|
||||||
|
if (cnt < PURLS_RETRY_COUNT)
|
||||||
|
goto retry;
|
||||||
|
|
||||||
|
fallthrough;
|
||||||
|
default:
|
||||||
|
ql_dbg(ql_log_warn, vha, 0x2123,
|
||||||
|
"Failed to xmit Unsol ls response = %d\n", rval);
|
||||||
|
rval = -EIO;
|
||||||
|
qla2x00_rel_sp(sp);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
out:
|
||||||
|
memset((void *)&a, 0, sizeof(a));
|
||||||
|
a.vp_idx = vha->vp_idx;
|
||||||
|
a.nport_handle = uctx->nport_handle;
|
||||||
|
a.xchg_address = uctx->exchange_address;
|
||||||
|
qla_nvme_ls_reject_iocb(vha, ha->base_qpair, &a, true);
|
||||||
|
kfree(uctx);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport,
|
static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport,
|
||||||
struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd)
|
struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd)
|
||||||
{
|
{
|
||||||
|
@ -355,7 +510,7 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
|
||||||
nvme->u.nvme.timeout_sec = fd->timeout;
|
nvme->u.nvme.timeout_sec = fd->timeout;
|
||||||
nvme->u.nvme.cmd_dma = fd->rqstdma;
|
nvme->u.nvme.cmd_dma = fd->rqstdma;
|
||||||
dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma,
|
dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma,
|
||||||
fd->rqstlen, DMA_TO_DEVICE);
|
le32_to_cpu(fd->rqstlen), DMA_TO_DEVICE);
|
||||||
|
|
||||||
rval = qla2x00_start_sp(sp);
|
rval = qla2x00_start_sp(sp);
|
||||||
if (rval != QLA_SUCCESS) {
|
if (rval != QLA_SUCCESS) {
|
||||||
|
@ -720,6 +875,7 @@ static struct nvme_fc_port_template qla_nvme_fc_transport = {
|
||||||
.ls_abort = qla_nvme_ls_abort,
|
.ls_abort = qla_nvme_ls_abort,
|
||||||
.fcp_io = qla_nvme_post_cmd,
|
.fcp_io = qla_nvme_post_cmd,
|
||||||
.fcp_abort = qla_nvme_fcp_abort,
|
.fcp_abort = qla_nvme_fcp_abort,
|
||||||
|
.xmt_ls_rsp = qla_nvme_xmt_ls_rsp,
|
||||||
.map_queues = qla_nvme_map_queues,
|
.map_queues = qla_nvme_map_queues,
|
||||||
.max_hw_queues = DEF_NVME_HW_QUEUES,
|
.max_hw_queues = DEF_NVME_HW_QUEUES,
|
||||||
.max_sgl_segments = 1024,
|
.max_sgl_segments = 1024,
|
||||||
|
@ -924,3 +1080,246 @@ inline void qla_wait_nvme_release_cmd_kref(srb_t *orig_sp)
|
||||||
return;
|
return;
|
||||||
kref_put(&orig_sp->cmd_kref, orig_sp->put_fn);
|
kref_put(&orig_sp->cmd_kref, orig_sp->put_fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qla_nvme_fc_format_rjt(void *buf, u8 ls_cmd, u8 reason,
|
||||||
|
u8 explanation, u8 vendor)
|
||||||
|
{
|
||||||
|
struct fcnvme_ls_rjt *rjt = buf;
|
||||||
|
|
||||||
|
rjt->w0.ls_cmd = FCNVME_LSDESC_RQST;
|
||||||
|
rjt->desc_list_len = fcnvme_lsdesc_len(sizeof(struct fcnvme_ls_rjt));
|
||||||
|
rjt->rqst.desc_tag = cpu_to_be32(FCNVME_LSDESC_RQST);
|
||||||
|
rjt->rqst.desc_len =
|
||||||
|
fcnvme_lsdesc_len(sizeof(struct fcnvme_lsdesc_rqst));
|
||||||
|
rjt->rqst.w0.ls_cmd = ls_cmd;
|
||||||
|
rjt->rjt.desc_tag = cpu_to_be32(FCNVME_LSDESC_RJT);
|
||||||
|
rjt->rjt.desc_len = fcnvme_lsdesc_len(sizeof(struct fcnvme_lsdesc_rjt));
|
||||||
|
rjt->rjt.reason_code = reason;
|
||||||
|
rjt->rjt.reason_explanation = explanation;
|
||||||
|
rjt->rjt.vendor = vendor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qla_nvme_lsrjt_pt_iocb(struct scsi_qla_host *vha,
|
||||||
|
struct pt_ls4_request *lsrjt_iocb,
|
||||||
|
struct qla_nvme_lsrjt_pt_arg *a)
|
||||||
|
{
|
||||||
|
lsrjt_iocb->entry_type = PT_LS4_REQUEST;
|
||||||
|
lsrjt_iocb->entry_count = 1;
|
||||||
|
lsrjt_iocb->sys_define = 0;
|
||||||
|
lsrjt_iocb->entry_status = 0;
|
||||||
|
lsrjt_iocb->handle = QLA_SKIP_HANDLE;
|
||||||
|
lsrjt_iocb->nport_handle = a->nport_handle;
|
||||||
|
lsrjt_iocb->exchange_address = a->xchg_address;
|
||||||
|
lsrjt_iocb->vp_index = a->vp_idx;
|
||||||
|
|
||||||
|
lsrjt_iocb->control_flags = cpu_to_le16(a->control_flags);
|
||||||
|
|
||||||
|
put_unaligned_le64(a->tx_addr, &lsrjt_iocb->dsd[0].address);
|
||||||
|
lsrjt_iocb->dsd[0].length = cpu_to_le32(a->tx_byte_count);
|
||||||
|
lsrjt_iocb->tx_dseg_count = cpu_to_le16(1);
|
||||||
|
lsrjt_iocb->tx_byte_count = cpu_to_le32(a->tx_byte_count);
|
||||||
|
|
||||||
|
put_unaligned_le64(a->rx_addr, &lsrjt_iocb->dsd[1].address);
|
||||||
|
lsrjt_iocb->dsd[1].length = 0;
|
||||||
|
lsrjt_iocb->rx_dseg_count = 0;
|
||||||
|
lsrjt_iocb->rx_byte_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qla_nvme_ls_reject_iocb(struct scsi_qla_host *vha, struct qla_qpair *qp,
|
||||||
|
struct qla_nvme_lsrjt_pt_arg *a, bool is_xchg_terminate)
|
||||||
|
{
|
||||||
|
struct pt_ls4_request *lsrjt_iocb;
|
||||||
|
|
||||||
|
lsrjt_iocb = __qla2x00_alloc_iocbs(qp, NULL);
|
||||||
|
if (!lsrjt_iocb) {
|
||||||
|
ql_log(ql_log_warn, vha, 0x210e,
|
||||||
|
"qla2x00_alloc_iocbs failed.\n");
|
||||||
|
return QLA_FUNCTION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_xchg_terminate) {
|
||||||
|
qla_nvme_fc_format_rjt((void *)vha->hw->lsrjt.c, a->opcode,
|
||||||
|
a->reason, a->explanation, 0);
|
||||||
|
|
||||||
|
a->tx_byte_count = sizeof(struct fcnvme_ls_rjt);
|
||||||
|
a->tx_addr = vha->hw->lsrjt.cdma;
|
||||||
|
a->control_flags = CF_LS4_RESPONDER << CF_LS4_SHIFT;
|
||||||
|
|
||||||
|
ql_dbg(ql_dbg_unsol, vha, 0x211f,
|
||||||
|
"Sending nvme fc ls reject ox_id %04x op %04x\n",
|
||||||
|
a->ox_id, a->opcode);
|
||||||
|
ql_dump_buffer(ql_dbg_unsol + ql_dbg_verbose, vha, 0x210f,
|
||||||
|
vha->hw->lsrjt.c, sizeof(*vha->hw->lsrjt.c));
|
||||||
|
} else {
|
||||||
|
a->tx_byte_count = 0;
|
||||||
|
a->control_flags = CF_LS4_RESPONDER_TERM << CF_LS4_SHIFT;
|
||||||
|
ql_dbg(ql_dbg_unsol, vha, 0x2110,
|
||||||
|
"Terminate nvme ls xchg 0x%x\n", a->xchg_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
qla_nvme_lsrjt_pt_iocb(vha, lsrjt_iocb, a);
|
||||||
|
/* flush iocb to mem before notifying hw doorbell */
|
||||||
|
wmb();
|
||||||
|
qla2x00_start_iocbs(vha, qp->req);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* qla2xxx_process_purls_pkt() - Pass-up Unsolicited
|
||||||
|
* Received FC-NVMe Link Service pkt to nvme_fc_rcv_ls_req().
|
||||||
|
* LLDD need to provide memory for response buffer, which
|
||||||
|
* will be used to reference the exchange corresponding
|
||||||
|
* to the LS when issuing an ls response. LLDD will have to free
|
||||||
|
* response buffer in lport->ops->xmt_ls_rsp().
|
||||||
|
*
|
||||||
|
* @vha: SCSI qla host
|
||||||
|
* @item: ptr to purex_item
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
qla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item)
|
||||||
|
{
|
||||||
|
struct qla_nvme_unsol_ctx *uctx = item->purls_context;
|
||||||
|
fc_port_t *fcport = uctx->fcport;
|
||||||
|
struct qla_nvme_lsrjt_pt_arg a;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = nvme_fc_rcv_ls_req(fcport->nvme_remote_port, &uctx->lsrsp,
|
||||||
|
&item->iocb, item->size);
|
||||||
|
if (ret) {
|
||||||
|
ql_dbg(ql_dbg_unsol, vha, 0x2125, "NVMe tranport ls_req failed\n");
|
||||||
|
memset((void *)&a, 0, sizeof(a));
|
||||||
|
a.vp_idx = vha->vp_idx;
|
||||||
|
a.nport_handle = uctx->nport_handle;
|
||||||
|
a.xchg_address = uctx->exchange_address;
|
||||||
|
qla_nvme_ls_reject_iocb(vha, vha->hw->base_qpair, &a, true);
|
||||||
|
list_del(&uctx->elem);
|
||||||
|
kfree(uctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static scsi_qla_host_t *
|
||||||
|
qla2xxx_get_vha_from_vp_idx(struct qla_hw_data *ha, uint16_t vp_index)
|
||||||
|
{
|
||||||
|
scsi_qla_host_t *base_vha, *vha, *tvp;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
base_vha = pci_get_drvdata(ha->pdev);
|
||||||
|
|
||||||
|
if (!vp_index && !ha->num_vhosts)
|
||||||
|
return base_vha;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ha->vport_slock, flags);
|
||||||
|
list_for_each_entry_safe(vha, tvp, &ha->vp_list, list) {
|
||||||
|
if (vha->vp_idx == vp_index) {
|
||||||
|
spin_unlock_irqrestore(&ha->vport_slock, flags);
|
||||||
|
return vha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&ha->vport_slock, flags);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp)
|
||||||
|
{
|
||||||
|
struct nvme_fc_remote_port *rport;
|
||||||
|
struct qla_nvme_rport *qla_rport;
|
||||||
|
struct qla_nvme_lsrjt_pt_arg a;
|
||||||
|
struct pt_ls4_rx_unsol *p = *pkt;
|
||||||
|
struct qla_nvme_unsol_ctx *uctx;
|
||||||
|
struct rsp_que *rsp_q = *rsp;
|
||||||
|
struct qla_hw_data *ha;
|
||||||
|
scsi_qla_host_t *vha;
|
||||||
|
fc_port_t *fcport = NULL;
|
||||||
|
struct purex_item *item;
|
||||||
|
port_id_t d_id = {0};
|
||||||
|
port_id_t id = {0};
|
||||||
|
u8 *opcode;
|
||||||
|
bool xmt_reject = false;
|
||||||
|
|
||||||
|
ha = rsp_q->hw;
|
||||||
|
|
||||||
|
vha = qla2xxx_get_vha_from_vp_idx(ha, p->vp_index);
|
||||||
|
if (!vha) {
|
||||||
|
ql_log(ql_log_warn, NULL, 0x2110, "Invalid vp index %d\n", p->vp_index);
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset((void *)&a, 0, sizeof(a));
|
||||||
|
opcode = (u8 *)&p->payload[0];
|
||||||
|
a.opcode = opcode[3];
|
||||||
|
a.vp_idx = p->vp_index;
|
||||||
|
a.nport_handle = p->nport_handle;
|
||||||
|
a.ox_id = p->ox_id;
|
||||||
|
a.xchg_address = p->exchange_address;
|
||||||
|
|
||||||
|
id.b.domain = p->s_id.domain;
|
||||||
|
id.b.area = p->s_id.area;
|
||||||
|
id.b.al_pa = p->s_id.al_pa;
|
||||||
|
d_id.b.domain = p->d_id[2];
|
||||||
|
d_id.b.area = p->d_id[1];
|
||||||
|
d_id.b.al_pa = p->d_id[0];
|
||||||
|
|
||||||
|
fcport = qla2x00_find_fcport_by_nportid(vha, &id, 0);
|
||||||
|
if (!fcport) {
|
||||||
|
ql_dbg(ql_dbg_unsol, vha, 0x211e,
|
||||||
|
"Failed to find sid=%06x did=%06x\n",
|
||||||
|
id.b24, d_id.b24);
|
||||||
|
a.reason = FCNVME_RJT_RC_INV_ASSOC;
|
||||||
|
a.explanation = FCNVME_RJT_EXP_NONE;
|
||||||
|
xmt_reject = true;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rport = fcport->nvme_remote_port;
|
||||||
|
qla_rport = rport->private;
|
||||||
|
|
||||||
|
item = qla27xx_copy_multiple_pkt(vha, pkt, rsp, true, false);
|
||||||
|
if (!item) {
|
||||||
|
a.reason = FCNVME_RJT_RC_LOGIC;
|
||||||
|
a.explanation = FCNVME_RJT_EXP_NONE;
|
||||||
|
xmt_reject = true;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
uctx = kzalloc(sizeof(*uctx), GFP_ATOMIC);
|
||||||
|
if (!uctx) {
|
||||||
|
ql_log(ql_log_info, vha, 0x2126, "Failed allocate memory\n");
|
||||||
|
a.reason = FCNVME_RJT_RC_LOGIC;
|
||||||
|
a.explanation = FCNVME_RJT_EXP_NONE;
|
||||||
|
xmt_reject = true;
|
||||||
|
kfree(item);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
uctx->vha = vha;
|
||||||
|
uctx->fcport = fcport;
|
||||||
|
uctx->exchange_address = p->exchange_address;
|
||||||
|
uctx->nport_handle = p->nport_handle;
|
||||||
|
uctx->ox_id = p->ox_id;
|
||||||
|
qla_rport->uctx = uctx;
|
||||||
|
INIT_LIST_HEAD(&uctx->elem);
|
||||||
|
list_add_tail(&uctx->elem, &fcport->unsol_ctx_head);
|
||||||
|
item->purls_context = (void *)uctx;
|
||||||
|
|
||||||
|
ql_dbg(ql_dbg_unsol, vha, 0x2121,
|
||||||
|
"PURLS OP[%01x] size %d xchg addr 0x%x portid %06x\n",
|
||||||
|
item->iocb.iocb[3], item->size, uctx->exchange_address,
|
||||||
|
fcport->d_id.b24);
|
||||||
|
/* +48 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||||
|
* ----- -----------------------------------------------
|
||||||
|
* 0000: 00 00 00 05 28 00 00 00 07 00 00 00 08 00 00 00
|
||||||
|
* 0010: ab ec 0f cc 00 00 8d 7d 05 00 00 00 10 00 00 00
|
||||||
|
* 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
*/
|
||||||
|
ql_dump_buffer(ql_dbg_unsol + ql_dbg_verbose, vha, 0x2120,
|
||||||
|
&item->iocb, item->size);
|
||||||
|
|
||||||
|
qla24xx_queue_purex_item(vha, item, qla2xxx_process_purls_pkt);
|
||||||
|
out:
|
||||||
|
if (xmt_reject) {
|
||||||
|
qla_nvme_ls_reject_iocb(vha, (*rsp)->qpair, &a, false);
|
||||||
|
__qla_consume_iocb(vha, pkt, rsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define Q2T_NVME_NUM_TAGS 2048
|
#define Q2T_NVME_NUM_TAGS 2048
|
||||||
#define QLA_MAX_FC_SEGMENTS 64
|
#define QLA_MAX_FC_SEGMENTS 64
|
||||||
|
|
||||||
|
struct qla_nvme_unsol_ctx;
|
||||||
struct scsi_qla_host;
|
struct scsi_qla_host;
|
||||||
struct qla_hw_data;
|
struct qla_hw_data;
|
||||||
struct req_que;
|
struct req_que;
|
||||||
|
@ -37,6 +38,7 @@ struct nvme_private {
|
||||||
|
|
||||||
struct qla_nvme_rport {
|
struct qla_nvme_rport {
|
||||||
struct fc_port *fcport;
|
struct fc_port *fcport;
|
||||||
|
struct qla_nvme_unsol_ctx *uctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define COMMAND_NVME 0x88 /* Command Type FC-NVMe IOCB */
|
#define COMMAND_NVME 0x88 /* Command Type FC-NVMe IOCB */
|
||||||
|
@ -75,6 +77,9 @@ struct cmd_nvme {
|
||||||
struct dsd64 nvme_dsd;
|
struct dsd64 nvme_dsd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define PURLS_MSLEEP_INTERVAL 1
|
||||||
|
#define PURLS_RETRY_COUNT 5
|
||||||
|
|
||||||
#define PT_LS4_REQUEST 0x89 /* Link Service pass-through IOCB (request) */
|
#define PT_LS4_REQUEST 0x89 /* Link Service pass-through IOCB (request) */
|
||||||
struct pt_ls4_request {
|
struct pt_ls4_request {
|
||||||
uint8_t entry_type;
|
uint8_t entry_type;
|
||||||
|
@ -118,7 +123,7 @@ struct pt_ls4_rx_unsol {
|
||||||
__le32 exchange_address;
|
__le32 exchange_address;
|
||||||
uint8_t d_id[3];
|
uint8_t d_id[3];
|
||||||
uint8_t r_ctl;
|
uint8_t r_ctl;
|
||||||
be_id_t s_id;
|
le_id_t s_id;
|
||||||
uint8_t cs_ctl;
|
uint8_t cs_ctl;
|
||||||
uint8_t f_ctl[3];
|
uint8_t f_ctl[3];
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
|
@ -127,12 +132,10 @@ struct pt_ls4_rx_unsol {
|
||||||
uint8_t seq_id;
|
uint8_t seq_id;
|
||||||
__le16 rx_id;
|
__le16 rx_id;
|
||||||
__le16 ox_id;
|
__le16 ox_id;
|
||||||
__le32 param;
|
|
||||||
__le32 desc0;
|
__le32 desc0;
|
||||||
#define PT_LS4_PAYLOAD_OFFSET 0x2c
|
#define PT_LS4_PAYLOAD_OFFSET 0x2c
|
||||||
#define PT_LS4_FIRST_PACKET_LEN 20
|
#define PT_LS4_FIRST_PACKET_LEN 20
|
||||||
__le32 desc_len;
|
__le32 payload[5];
|
||||||
__le32 payload[3];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -4457,8 +4457,9 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||||
|
|
||||||
ha->elsrej.size = sizeof(struct fc_els_ls_rjt) + 16;
|
ha->elsrej.size = sizeof(struct fc_els_ls_rjt) + 16;
|
||||||
ha->elsrej.c = dma_alloc_coherent(&ha->pdev->dev,
|
ha->elsrej.c = dma_alloc_coherent(&ha->pdev->dev,
|
||||||
ha->elsrej.size, &ha->elsrej.cdma, GFP_KERNEL);
|
ha->elsrej.size,
|
||||||
|
&ha->elsrej.cdma,
|
||||||
|
GFP_KERNEL);
|
||||||
if (!ha->elsrej.c) {
|
if (!ha->elsrej.c) {
|
||||||
ql_dbg_pci(ql_dbg_init, ha->pdev, 0xffff,
|
ql_dbg_pci(ql_dbg_init, ha->pdev, 0xffff,
|
||||||
"Alloc failed for els reject cmd.\n");
|
"Alloc failed for els reject cmd.\n");
|
||||||
|
@ -4467,8 +4468,21 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||||
ha->elsrej.c->er_cmd = ELS_LS_RJT;
|
ha->elsrej.c->er_cmd = ELS_LS_RJT;
|
||||||
ha->elsrej.c->er_reason = ELS_RJT_LOGIC;
|
ha->elsrej.c->er_reason = ELS_RJT_LOGIC;
|
||||||
ha->elsrej.c->er_explan = ELS_EXPL_UNAB_DATA;
|
ha->elsrej.c->er_explan = ELS_EXPL_UNAB_DATA;
|
||||||
|
|
||||||
|
ha->lsrjt.size = sizeof(struct fcnvme_ls_rjt);
|
||||||
|
ha->lsrjt.c = dma_alloc_coherent(&ha->pdev->dev, ha->lsrjt.size,
|
||||||
|
&ha->lsrjt.cdma, GFP_KERNEL);
|
||||||
|
if (!ha->lsrjt.c) {
|
||||||
|
ql_dbg_pci(ql_dbg_init, ha->pdev, 0xffff,
|
||||||
|
"Alloc failed for nvme fc reject cmd.\n");
|
||||||
|
goto fail_lsrjt;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail_lsrjt:
|
||||||
|
dma_free_coherent(&ha->pdev->dev, ha->elsrej.size,
|
||||||
|
ha->elsrej.c, ha->elsrej.cdma);
|
||||||
fail_elsrej:
|
fail_elsrej:
|
||||||
dma_pool_destroy(ha->purex_dma_pool);
|
dma_pool_destroy(ha->purex_dma_pool);
|
||||||
fail_flt:
|
fail_flt:
|
||||||
|
@ -4998,6 +5012,12 @@ qla2x00_mem_free(struct qla_hw_data *ha)
|
||||||
ha->elsrej.c = NULL;
|
ha->elsrej.c = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ha->lsrjt.c) {
|
||||||
|
dma_free_coherent(&ha->pdev->dev, ha->lsrjt.size, ha->lsrjt.c,
|
||||||
|
ha->lsrjt.cdma);
|
||||||
|
ha->lsrjt.c = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
ha->init_cb = NULL;
|
ha->init_cb = NULL;
|
||||||
ha->init_cb_dma = 0;
|
ha->init_cb_dma = 0;
|
||||||
|
|
||||||
|
|
|
@ -53,10 +53,10 @@
|
||||||
struct nvmefc_ls_req {
|
struct nvmefc_ls_req {
|
||||||
void *rqstaddr;
|
void *rqstaddr;
|
||||||
dma_addr_t rqstdma;
|
dma_addr_t rqstdma;
|
||||||
u32 rqstlen;
|
__le32 rqstlen;
|
||||||
void *rspaddr;
|
void *rspaddr;
|
||||||
dma_addr_t rspdma;
|
dma_addr_t rspdma;
|
||||||
u32 rsplen;
|
__le32 rsplen;
|
||||||
u32 timeout;
|
u32 timeout;
|
||||||
|
|
||||||
void *private;
|
void *private;
|
||||||
|
@ -120,7 +120,7 @@ struct nvmefc_ls_req {
|
||||||
struct nvmefc_ls_rsp {
|
struct nvmefc_ls_rsp {
|
||||||
void *rspbuf;
|
void *rspbuf;
|
||||||
dma_addr_t rspdma;
|
dma_addr_t rspdma;
|
||||||
u16 rsplen;
|
__le32 rsplen;
|
||||||
|
|
||||||
void (*done)(struct nvmefc_ls_rsp *rsp);
|
void (*done)(struct nvmefc_ls_rsp *rsp);
|
||||||
void *nvme_fc_private; /* LLDD is not to access !! */
|
void *nvme_fc_private; /* LLDD is not to access !! */
|
||||||
|
|
Loading…
Add table
Reference in a new issue