STRUCT NVME_FC_PORT_TEMPLATE(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

πŸ’… NAME πŸ’…

okay so welcome to the Kernel API Manual, bestie β€” this is the page for struct nvme_fc_port_template, and it's literally the structure containing all the static entrypoints and the operational parameters for an LLDD that supports NVME host behavior. 🫢

You pass it by reference in port registrations, and here's the part you cannot skip: the NVME-FC transport remembers the template reference and may access it during runtime operation. So no sneakily freeing it after registration, that's not the vibe. πŸ’€


✨ SYNOPSIS ✨

struct nvme_fc_port_template {
    void (*localport_delete)(struct nvme_fc_local_port *);
    void (*remoteport_delete)(struct nvme_fc_remote_port *);
    int (*create_queue)(struct nvme_fc_local_port *, unsigned int qidx,
u16 qsize, void **handle);
    void (*delete_queue)(struct nvme_fc_local_port *, unsigned int qidx,
void *handle);
    int (*ls_req)(struct nvme_fc_local_port *, struct
nvme_fc_remote_port *, struct nvmefc_ls_req *);
    int (*fcp_io)(struct nvme_fc_local_port *, struct
nvme_fc_remote_port *, void *hw_queue_handle, struct nvmefc_fcp_req *);
    void (*ls_abort)(struct nvme_fc_local_port *, struct
nvme_fc_remote_port *, struct nvmefc_ls_req *);
    void (*fcp_abort)(struct nvme_fc_local_port *, struct
nvme_fc_remote_port *, void *hw_queue_handle, struct nvmefc_fcp_req *);
    int (*xmt_ls_rsp)(struct nvme_fc_local_port *localport, struct
nvme_fc_remote_port *rport, struct nvmefc_ls_rsp *ls_rsp);
    void (*map_queues)(struct nvme_fc_local_port *localport, struct
blk_mq_queue_map *map);
    u32 max_hw_queues;
    u16 max_sgl_segments;
    u16 max_dif_sgl_segments;
    u64 dma_boundary;
    u32 local_priv_sz;
    u32 remote_priv_sz;
    u32 lsrqst_priv_sz;
    u32 fcprqst_priv_sz;
};

πŸŽ€ Members πŸŽ€

time for the member-by-member tour, bestie β€” grab a snack, there's a lot and every single one matters πŸ’–

  • localport_delete β€” so the LLDD kicks off deletion of a localport via nvme_fc_deregister_localport, right? But the teardown is asynchronous 😭. This routine gets called when that teardown finishes, to let the LLDD know the localport has officially been deleted. Entrypoint is Mandatory.
  • remoteport_delete β€” same energy for remote ports: the LLDD initiates deletion of a remoteport via nvme_fc_deregister_remoteport, the teardown is asynchronous, and this routine is called upon completion of the teardown to tell the LLDD the remoteport has been deleted. Entrypoint is Mandatory.
  • create_queue β€” when a host<->controller association is created, queues get made so they can be affinitized to cpus/cores. This is the callback into the LLDD saying "hey, a controller queue is being created." The LLDD may choose to allocate an associated hw queue or map it onto a shared hw queue. On return from the call, the LLDD specifies a handle that will be given back to it for any command posted to the controller queue β€” that handle lets the LLDD map quickly to the proper hw queue for command execution. The mask of cpu's that will map to this queue at the block-level is also passed in. The LLDD should use the queue id and/or cpu masks to make sure the controller queue is properly affinitized to the hw queue. Entrypoint is Optional.
  • delete_queue β€” the inverse of create_queue (the original page spells it "crete_queue", we don't gatekeep typos πŸ’…). During host<->controller association teardown, this routine is called when a controller queue is being terminated. Any association with a hw queue should be terminated. If there's a unique hw queue, that hw queue should be torn down. Entrypoint is Optional.
  • ls_req β€” called to issue a FC-NVME FC-4 LS service request. The nvme_fc_ls_req structure fully describes the buffers for the request payload and where to place the response payload. The LLDD is to allocate an exchange, issue the LS request, obtain the LS response, and call the "done" routine specified in the request structure (the argument to done is the ls request structure itself). Entrypoint is Mandatory.
  • fcp_io β€” called to issue a FC-NVME I/O request. The I/O may be for an admin queue or an i/o queue. The nvmefc_fcp_req structure fully describes the io: the buffer containing the FC-NVME CMD IU (which contains the SQE), the sg list for the payload if applicable, and the buffer to place the FC-NVME RSP IU into. The LLDD will complete the i/o, indicating the amount of data transferred or any transport error, and call the "done" routine specified in the request structure (the argument to done is the fcp request structure itself). Entrypoint is Mandatory.
  • ls_abort β€” called to ask the LLDD to abort the indicated ls request. The call may return before the abort has completed ⚠️. After aborting the request, the LLDD must still call the ls request done routine indicating an FC transport Aborted status. Entrypoint is Mandatory.
  • fcp_abort β€” called to ask the LLDD to abort the indicated fcp request. Again, the call may return before the abort has completed ⚠️. After aborting the request, the LLDD must still call the fcp request done routine indicating an FC transport Aborted status. Entrypoint is Mandatory.
  • xmt_ls_rsp β€” called to transmit the response to a FC-NVME FC-4 LS service. The nvmefc_ls_rsp structure is the same LLDD-supplied exchange structure specified in the nvme_fc_rcv_ls_req call made when the LS request was received. That structure fully describes the buffers for the response payload and the dma address of the payload. The LLDD is to transmit the response (or return a non-zero errno status), and upon completion of the transmit, call the "done" routine specified in the nvmefc_ls_rsp structure (the argument to done is the address of the nvmefc_ls_rsp structure itself). Once the done routine completes, the LLDD shall consider the LS handling complete and the nvmefc_ls_rsp structure may be freed/released. Entrypoint is mandatory if the LLDD calls the nvme_fc_rcv_ls_req entrypoint.
  • max_hw_queues β€” indicates the maximum number of hw queues the LLDD supports for cpu affinitization. Value is Mandatory. Must be at least 1.
  • max_sgl_segments β€” indicates the maximum number of sgl segments supported by the LLDD. Value is Mandatory. Must be at least 1. Recommend at least 256. πŸ‘‘
  • max_dif_sgl_segments β€” indicates the maximum number of sgl segments supported by the LLDD for DIF operations. Value is Mandatory. Must be at least 1. Recommend at least 256.
  • dma_boundary β€” indicates the dma address boundary where dma mappings will be split across. Value is Mandatory. Typical value is 0xFFFFFFFF to split across 4Gig address boundarys (their spelling, not mine, iykyk 🌸).
  • local_priv_sz β€” the LLDD sets this field to the amount of additional memory it would like the fc nvme layer to allocate on the LLDD's behalf whenever a localport is allocated. That extra memory area is solely for the LLDD, and its location is specified by the localport->private pointer. Value is Mandatory. Allowed to be zero.
  • remote_priv_sz β€” same deal, but whenever a remoteport is allocated. The extra memory area is solely for the LLDD and its location is specified by the remoteport->private pointer. Value is Mandatory. Allowed to be zero.
  • lsrqst_priv_sz β€” same deal, but whenever an ls request structure is allocated. The additional memory area is solely for use by the LLDD and its location is specified by the ls_request->private pointer. Value is Mandatory. Allowed to be zero.
  • fcprqst_priv_sz β€” same deal, but whenever a fcp request structure is allocated. The extra memory area is solely for the LLDD and its location is specified by the fcp_request->private pointer. Value is Mandatory. Allowed to be zero.
ngl bestie, map_queues shows up in the struct up top but it does not get its own member write-up here β€” I'm not gonna make up lore that isn't in the source, that's not slay behavior. πŸ™ˆ

πŸ¦‹ Description πŸ¦‹

Host/Initiator Transport Entrypoints/Parameters: β€” that's the whole description, short and iconic, periodt. ✨


πŸ’œ SEE ALSO πŸ’œ

Kernel file ./include/linux/nvme-fc-driver.h, plus the whole friend group:

  • struct nvmefc_ls_req(9)
  • struct nvmefc_ls_rsp(9)
  • struct nvme_fc_port_info(9)
  • struct nvmefc_fcp_req(9)
  • struct nvme_fc_local_port(9)
  • struct nvme_fc_remote_port(9)
  • struct nvmet_fc_port_info(9)
  • struct nvmefc_tgt_fcp_req(9)
  • struct nvmet_fc_target_port(9)
  • struct nvmet_fc_target_template(9)

that's the whole page, bestie β€” go forth and register your ports responsibly πŸ§šπŸ’–

mwah πŸ’‹ β€” this drop came straight out of ./include/linux in the October 2026 edition of the Kernel API Manual, and yes, the footer still calls it struct nvme_...ort_template(9) because we abbreviate when we're being cute. slay. πŸŽ€

πŸ“¦ where this page comes from