mirror of
https://github.com/torvalds/linux.git
synced 2026-09-27 11:02:03 +02:00
scsi: fnic: Send NVMe LS requests through FDLS
Add the FC frame wrapper for NVMe LS requests and build LS request frames from the NVMe-FC transport callback. Allocate OXIDs, track outstanding LS requests on the target port, arm request timers, and register the LS request callback in the NVMe FC port template. Reported-by: kernel test robot <lkp@intel.com> Closes: https://lore.kernel.org/oe-kbuild-all/202605280619.pmobiDWp-lkp@intel.com/ Reviewed-by: Sesidhar Baddela <sebaddel@cisco.com> Reviewed-by: Arulprabhu Ponnusamy <arulponn@cisco.com> Reviewed-by: Gian Carlo Boffa <gcboffa@cisco.com> Reviewed-by: Arun Easi <aeasi@cisco.com> Reviewed-by: Hannes Reinecke <hare@kernel.org> Reviewed-by: Lee Duncan <lduncan@suse.com> Signed-off-by: Karan Tilak Kumar <kartilak@cisco.com> Co-developed-by: Hannes Reinecke <hare@kernel.org> Link: https://patch.msgid.link/20260724174811.5118-10-kartilak@cisco.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
021db11aba
commit
39bf075599
|
|
@ -30,6 +30,9 @@
|
|||
#include <linux/if_ether.h>
|
||||
#include <scsi/fc/fc_encaps.h>
|
||||
#include <scsi/fc/fc_fcoe.h>
|
||||
#include <linux/nvme.h>
|
||||
#include <linux/nvme-fc.h>
|
||||
#include <linux/nvme-fc-driver.h>
|
||||
|
||||
#define FDLS_MIN_FRAMES (32)
|
||||
#define FDLS_MIN_FRAME_ELEM (4)
|
||||
|
|
|
|||
|
|
@ -1337,6 +1337,129 @@ void nvfnic_ls_req_timeout(struct timer_list *t)
|
|||
ls_req->done(ls_req, -ETIMEDOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* nvfnic_ls_req_send - Send NVMe FC link service (LS) request
|
||||
* @lport: Pointer to local NVMe FC port structure
|
||||
* @rport: Pointer to remote NVMe FC port structure
|
||||
* @ls_req: Pointer to the link service request structure
|
||||
*
|
||||
* This function is used to send link service (LS) commands to an NVMe
|
||||
* Discovery Controller for discovery operations, as well as to regular
|
||||
* NVMe subsystems during association. It encapsulates the logic for
|
||||
* transmitting LS requests over the NVMe over Fabrics (NVMe-oF) FC
|
||||
* transport.
|
||||
*
|
||||
* Returns: 0 on success, or a negative error code on failure.
|
||||
*/
|
||||
int nvfnic_ls_req_send(struct nvme_fc_local_port *lport,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
struct nvmefc_ls_req *ls_req)
|
||||
{
|
||||
int timeout;
|
||||
uint8_t *frame;
|
||||
uint8_t fcid[3];
|
||||
unsigned long flags = 0;
|
||||
struct fnic_iport_s *iport = lport->private;
|
||||
uint8_t *ls_req_payload;
|
||||
struct fnic *fnic = iport->fnic;
|
||||
struct fc_frame_header *fchdr;
|
||||
struct nvfnic_ls_req *nvfnic_ls_req = ls_req->private;
|
||||
uint16_t frame_size = FNIC_ETH_FCOE_HDRS_OFFSET +
|
||||
sizeof(struct fc_frame_header) + ls_req->rqstlen;
|
||||
struct fnic_tport_s *tport;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&fnic->fnic_lock, flags);
|
||||
|
||||
tport = (struct fnic_tport_s *)rport->private;
|
||||
INIT_LIST_HEAD(&nvfnic_ls_req->list);
|
||||
|
||||
if (!nvfnic_transport_ready(iport, tport)) {
|
||||
if (tport != NULL)
|
||||
FNIC_NVME_DBG(KERN_INFO, fnic,
|
||||
"iport: 0x%x tport: 0x%x transport not ready\n",
|
||||
iport->fcid, tport->fcid);
|
||||
else
|
||||
FNIC_NVME_DBG(KERN_INFO, fnic,
|
||||
"iport: 0x%x transport not ready\n",
|
||||
iport->fcid);
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
return -ENOLINK;
|
||||
}
|
||||
|
||||
frame = fdls_alloc_frame(iport);
|
||||
if (frame == NULL) {
|
||||
FNIC_NVME_DBG(KERN_ERR, fnic,
|
||||
"Failed to allocate frame to send NVME LS REQ");
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (fdls_alloc_oxid(iport, FNIC_FRAME_TYPE_NVME_LS,
|
||||
&nvfnic_ls_req->oxid) == FNIC_UNASSIGNED_OXID) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"0x%x: Failed to allocate OXID to send NVME LS REQ",
|
||||
iport->fcid);
|
||||
mempool_free(frame, fnic->frame_pool);
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
timer_setup(&nvfnic_ls_req->ls_req_timer, nvfnic_ls_req_timeout,
|
||||
0UL);
|
||||
|
||||
nvfnic_ls_req->fnic = fnic;
|
||||
nvfnic_ls_req->tport = tport;
|
||||
nvfnic_ls_req->state = FNIC_LS_REQ_CMD_INIT;
|
||||
nvfnic_ls_req->ls_req = ls_req;
|
||||
|
||||
fchdr = (struct fc_frame_header *)(frame + FNIC_ETH_FCOE_HDRS_OFFSET);
|
||||
*fchdr = (struct fc_frame_header) {
|
||||
.fh_r_ctl = FC_RCTL_ELS4_REQ,
|
||||
.fh_type = FC_TYPE_NVME,
|
||||
.fh_f_ctl = {FNIC_ELS_REQ_FCTL, 0, 0},
|
||||
.fh_rx_id = cpu_to_be16(FNIC_UNASSIGNED_RXID)
|
||||
};
|
||||
|
||||
hton24(fcid, iport->fcid);
|
||||
FNIC_STD_SET_S_ID(*fchdr, fcid);
|
||||
|
||||
hton24(fcid, tport->fcid);
|
||||
FNIC_STD_SET_D_ID(*fchdr, fcid);
|
||||
|
||||
FNIC_STD_SET_OX_ID(*fchdr, nvfnic_ls_req->oxid);
|
||||
|
||||
ls_req_payload = frame + FNIC_ETH_FCOE_HDRS_OFFSET + sizeof(*fchdr);
|
||||
memcpy(ls_req_payload, ls_req->rqstaddr, ls_req->rqstlen);
|
||||
|
||||
FNIC_NVME_DBG(KERN_INFO, fnic,
|
||||
"0x%x: NVME send ls req with oxid: 0x%x type: 0x%02x len: %d",
|
||||
iport->fcid, nvfnic_ls_req->oxid, *((uint8_t *) ls_req->rqstaddr),
|
||||
ls_req->rqstlen);
|
||||
|
||||
list_add_tail(&nvfnic_ls_req->list, &tport->ls_req_list);
|
||||
nvfnic_ls_req->state = FNIC_LS_REQ_CMD_PENDING;
|
||||
|
||||
ret = fnic_send_fcoe_frame(iport, frame, frame_size);
|
||||
if (ret) {
|
||||
list_del(&nvfnic_ls_req->list);
|
||||
fdls_free_oxid(iport, nvfnic_ls_req->oxid,
|
||||
&nvfnic_ls_req->oxid);
|
||||
nvfnic_ls_req->state = FNIC_LS_REQ_CMD_COMPLETE;
|
||||
ls_req->private = NULL;
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
mempool_free(frame, fnic->frame_pool);
|
||||
return ret;
|
||||
}
|
||||
|
||||
timeout = FNIC_LS_REQ_TMO_MSECS(ls_req->timeout);
|
||||
mod_timer(&nvfnic_ls_req->ls_req_timer,
|
||||
round_jiffies(jiffies + msecs_to_jiffies(timeout)));
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nvfnic_local_port_delete(struct nvme_fc_local_port *lport)
|
||||
{
|
||||
struct fnic_iport_s *iport = (struct fnic_iport_s *) lport->private;
|
||||
|
|
@ -1662,7 +1785,7 @@ nvme_fc_port_template nvfnic_port = {
|
|||
.remoteport_delete = nvfnic_remote_port_delete,
|
||||
.create_queue = nvfnic_create_queue,
|
||||
.delete_queue = NULL,
|
||||
.ls_req = NULL,
|
||||
.ls_req = nvfnic_ls_req_send,
|
||||
.ls_abort = nvfnic_ls_req_abort,
|
||||
.fcp_io = nvfnic_fcpio_send,
|
||||
.fcp_abort = nvfnic_fcpio_abort,
|
||||
|
|
|
|||
|
|
@ -112,6 +112,9 @@ void nvfnic_ls_req_abort(struct nvme_fc_local_port *lport,
|
|||
struct nvmefc_ls_req *lsreq);
|
||||
int nvfnic_create_queue(struct nvme_fc_local_port *lport, unsigned int idx,
|
||||
u16 size, void **handle);
|
||||
int nvfnic_ls_req_send(struct nvme_fc_local_port *lport,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
struct nvmefc_ls_req *ls_req);
|
||||
void nvfnic_ls_req_timeout(struct timer_list *t);
|
||||
uint16_t nvfnic_alloc_ls_req_oxid(struct fnic_iport_s *iport);
|
||||
struct nvfnic_ls_req *nvfnic_find_ls_req(struct fnic_tport_s *tport,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user