Changeset View
Changeset View
Standalone View
Standalone View
sys/cam/ctl/ctl_io.h
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
#define _CTL_IO_H_ | #define _CTL_IO_H_ | ||||
#ifndef _KERNEL | #ifndef _KERNEL | ||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#endif | #endif | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <cam/scsi/scsi_all.h> | #include <cam/scsi/scsi_all.h> | ||||
#include <dev/nvme/nvme.h> | |||||
#define CTL_MAX_CDBLEN 32 | #define CTL_MAX_CDBLEN 32 | ||||
/* | /* | ||||
* Uncomment this next line to enable printing out times for I/Os | * Uncomment this next line to enable printing out times for I/Os | ||||
* that take longer than CTL_TIME_IO_SECS seconds to get to the datamove | * that take longer than CTL_TIME_IO_SECS seconds to get to the datamove | ||||
* and/or done stage. | * and/or done stage. | ||||
*/ | */ | ||||
#define CTL_TIME_IO | #define CTL_TIME_IO | ||||
Show All 11 Lines | |||||
typedef enum { | typedef enum { | ||||
CTL_STATUS_NONE, /* No status */ | CTL_STATUS_NONE, /* No status */ | ||||
CTL_SUCCESS, /* Transaction completed successfully */ | CTL_SUCCESS, /* Transaction completed successfully */ | ||||
CTL_CMD_TIMEOUT, /* Command timed out, shouldn't happen here */ | CTL_CMD_TIMEOUT, /* Command timed out, shouldn't happen here */ | ||||
CTL_SEL_TIMEOUT, /* Selection timeout, shouldn't happen here */ | CTL_SEL_TIMEOUT, /* Selection timeout, shouldn't happen here */ | ||||
CTL_ERROR, /* General CTL error XXX expand on this? */ | CTL_ERROR, /* General CTL error XXX expand on this? */ | ||||
CTL_SCSI_ERROR, /* SCSI error, look at status byte/sense data */ | CTL_SCSI_ERROR, /* SCSI error, look at status byte/sense data */ | ||||
CTL_NVME_ERROR, /* NVMe error, look at NVMe completion */ | |||||
CTL_CMD_ABORTED, /* Command aborted, don't return status */ | CTL_CMD_ABORTED, /* Command aborted, don't return status */ | ||||
CTL_STATUS_MASK = 0xfff,/* Mask off any status flags */ | CTL_STATUS_MASK = 0xfff,/* Mask off any status flags */ | ||||
CTL_AUTOSENSE = 0x1000 /* Autosense performed */ | CTL_AUTOSENSE = 0x1000 /* Autosense performed */ | ||||
} ctl_io_status; | } ctl_io_status; | ||||
/* | /* | ||||
* WARNING: Keep the data in/out/none flags where they are. They're used | * WARNING: Keep the data in/out/none flags where they are. They're used | ||||
* in conjunction with ctl_cmd_flags. See comment above ctl_cmd_flags | * in conjunction with ctl_cmd_flags. See comment above ctl_cmd_flags | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | struct ctl_sg_entry { | ||||
void *addr; | void *addr; | ||||
size_t len; | size_t len; | ||||
}; | }; | ||||
typedef enum { | typedef enum { | ||||
CTL_IO_NONE, | CTL_IO_NONE, | ||||
CTL_IO_SCSI, | CTL_IO_SCSI, | ||||
CTL_IO_TASK, | CTL_IO_TASK, | ||||
CTL_IO_NVME, | |||||
CTL_IO_NVME_ADMIN, | |||||
} ctl_io_type; | } ctl_io_type; | ||||
struct ctl_nexus { | struct ctl_nexus { | ||||
uint32_t initid; /* Initiator ID */ | uint32_t initid; /* Initiator ID */ | ||||
uint32_t targ_port; /* Target port, filled in by PORT */ | uint32_t targ_port; /* Target port, filled in by PORT */ | ||||
uint32_t targ_lun; /* Destination lun */ | uint32_t targ_lun; /* Destination lun */ | ||||
uint32_t targ_mapped_lun; /* Destination lun CTL-wide */ | uint32_t targ_mapped_lun; /* Destination lun CTL-wide */ | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | typedef enum { | ||||
CTL_TAG_ORDERED, | CTL_TAG_ORDERED, | ||||
CTL_TAG_HEAD_OF_QUEUE, | CTL_TAG_HEAD_OF_QUEUE, | ||||
CTL_TAG_ACA | CTL_TAG_ACA | ||||
} ctl_tag_type; | } ctl_tag_type; | ||||
union ctl_io; | union ctl_io; | ||||
typedef void (*ctl_ref)(void *arg, int diff); | typedef void (*ctl_ref)(void *arg, int diff); | ||||
typedef int (*ctl_be_move_done_t)(union ctl_io *io, bool samethr); | |||||
typedef int (*ctl_io_cont)(union ctl_io *io); | |||||
/* | /* | ||||
* SCSI passthrough I/O structure for the CAM Target Layer. Note | * SCSI passthrough I/O structure for the CAM Target Layer. Note | ||||
* that some of these fields are here for completeness, but they aren't | * that some of these fields are here for completeness, but they aren't | ||||
* used in the CTL implementation. e.g., timeout and retries won't be | * used in the CTL implementation. e.g., timeout and retries won't be | ||||
* used. | * used. | ||||
* | * | ||||
* Note: Make sure the io_hdr is *always* the first element in this | * Note: Make sure the io_hdr is *always* the first element in this | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | struct ctl_scsiio { | ||||
uint8_t sense_len; /* Returned sense length */ | uint8_t sense_len; /* Returned sense length */ | ||||
uint8_t scsi_status; /* SCSI status byte */ | uint8_t scsi_status; /* SCSI status byte */ | ||||
uint8_t seridx; /* Serialization index. */ | uint8_t seridx; /* Serialization index. */ | ||||
uint8_t priority; /* Command priority */ | uint8_t priority; /* Command priority */ | ||||
uint64_t tag_num; /* tag number */ | uint64_t tag_num; /* tag number */ | ||||
ctl_tag_type tag_type; /* simple, ordered, head of queue,etc.*/ | ctl_tag_type tag_type; /* simple, ordered, head of queue,etc.*/ | ||||
uint8_t cdb_len; /* CDB length */ | uint8_t cdb_len; /* CDB length */ | ||||
uint8_t cdb[CTL_MAX_CDBLEN]; /* CDB */ | uint8_t cdb[CTL_MAX_CDBLEN]; /* CDB */ | ||||
int (*be_move_done)(union ctl_io *io, bool samethr); /* called by fe */ | ctl_be_move_done_t be_move_done; /* called by fe */ | ||||
int (*io_cont)(union ctl_io *io); /* to continue processing */ | ctl_io_cont io_cont; /* to continue processing */ | ||||
ctl_ref kern_data_ref; /* Method to reference/release data */ | ctl_ref kern_data_ref; /* Method to reference/release data */ | ||||
void *kern_data_arg; /* Opaque argument for kern_data_ref() */ | void *kern_data_arg; /* Opaque argument for kern_data_ref() */ | ||||
}; | }; | ||||
typedef enum { | typedef enum { | ||||
CTL_TASK_ABORT_TASK, | CTL_TASK_ABORT_TASK, | ||||
CTL_TASK_ABORT_TASK_SET, | CTL_TASK_ABORT_TASK_SET, | ||||
CTL_TASK_CLEAR_ACA, | CTL_TASK_CLEAR_ACA, | ||||
Show All 29 Lines | struct ctl_taskio { | ||||
ctl_task_type task_action; /* Target Reset, Abort, etc. */ | ctl_task_type task_action; /* Target Reset, Abort, etc. */ | ||||
uint64_t tag_num; /* tag number */ | uint64_t tag_num; /* tag number */ | ||||
ctl_tag_type tag_type; /* simple, ordered, etc. */ | ctl_tag_type tag_type; /* simple, ordered, etc. */ | ||||
uint8_t task_status; /* Complete, Succeeded, etc. */ | uint8_t task_status; /* Complete, Succeeded, etc. */ | ||||
uint8_t task_resp[3];/* Response information */ | uint8_t task_resp[3];/* Response information */ | ||||
}; | }; | ||||
/* | /* | ||||
* NVME passthrough I/O structure for the CAM Target Layer. Note that | |||||
* this structure is used for both I/O and admin commands. | |||||
* | |||||
* Note: Make sure the io_hdr is *always* the first element in this | |||||
* structure. | |||||
*/ | |||||
struct ctl_nvmeio { | |||||
struct ctl_io_hdr io_hdr; /* common to all I/O types */ | |||||
/* | |||||
* The ext_* fields are generally intended for frontend use; CTL itself | |||||
* doesn't modify or use them. | |||||
*/ | |||||
uint32_t ext_sg_entries; /* 0 = no S/G list, > 0 = num entries */ | |||||
uint8_t *ext_data_ptr; /* data buffer or S/G list */ | |||||
uint32_t ext_data_len; /* Data transfer length */ | |||||
uint32_t ext_data_filled; /* Amount of data filled so far */ | |||||
/* | |||||
* The number of scatter/gather entries in the list pointed to | |||||
* by kern_data_ptr. 0 means there is no list, just a data pointer. | |||||
*/ | |||||
uint32_t kern_sg_entries; | |||||
/* | |||||
* The data pointer or a pointer to the scatter/gather list. | |||||
*/ | |||||
uint8_t *kern_data_ptr; | |||||
/* | |||||
* Length of the data buffer or scatter/gather list. It's also | |||||
* the length of this particular piece of the data transfer, | |||||
* ie. number of bytes expected to be transferred by the current | |||||
* invocation of frontend's datamove() callback. It's always | |||||
* less than or equal to kern_total_len. | |||||
*/ | |||||
uint32_t kern_data_len; | |||||
/* | |||||
* Total length of data to be transferred during this particular | |||||
* NVMe command, as decoded from the NVMe SQE. | |||||
*/ | |||||
uint32_t kern_total_len; | |||||
/* | |||||
* Amount of data left after the current data transfer. | |||||
*/ | |||||
uint32_t kern_data_resid; | |||||
/* | |||||
* Byte offset of this transfer, equal to the amount of data | |||||
* already transferred for this NVMe command during previous | |||||
* datamove() invocations. | |||||
*/ | |||||
uint32_t kern_rel_offset; | |||||
struct nvme_command cmd; /* SQE */ | |||||
struct nvme_completion cpl; /* CQE */ | |||||
bool success_sent; /* datamove already sent CQE */ | |||||
ctl_be_move_done_t be_move_done; /* called by fe */ | |||||
ctl_io_cont io_cont; /* to continue processing */ | |||||
ctl_ref kern_data_ref; /* Method to reference/release data */ | |||||
void *kern_data_arg; /* Opaque argument for kern_data_ref() */ | |||||
}; | |||||
/* | |||||
* HA link messages. | * HA link messages. | ||||
*/ | */ | ||||
#define CTL_HA_VERSION 4 | #define CTL_HA_VERSION 4 | ||||
/* | /* | ||||
* Used for CTL_MSG_LOGIN. | * Used for CTL_MSG_LOGIN. | ||||
*/ | */ | ||||
struct ctl_ha_msg_login { | struct ctl_ha_msg_login { | ||||
▲ Show 20 Lines • Show All 191 Lines • ▼ Show 20 Lines | struct ctl_prio { | ||||
struct ctl_io_hdr io_hdr; | struct ctl_io_hdr io_hdr; | ||||
struct ctl_ha_msg_pr pr_msg; | struct ctl_ha_msg_pr pr_msg; | ||||
}; | }; | ||||
union ctl_io { | union ctl_io { | ||||
struct ctl_io_hdr io_hdr; /* common to all I/O types */ | struct ctl_io_hdr io_hdr; /* common to all I/O types */ | ||||
struct ctl_scsiio scsiio; /* Normal SCSI commands */ | struct ctl_scsiio scsiio; /* Normal SCSI commands */ | ||||
struct ctl_taskio taskio; /* SCSI task management/reset */ | struct ctl_taskio taskio; /* SCSI task management/reset */ | ||||
struct ctl_nvmeio nvmeio; /* Normal and admin NVMe commands */ | |||||
struct ctl_prio presio; /* update per. res info on other SC */ | struct ctl_prio presio; /* update per. res info on other SC */ | ||||
}; | }; | ||||
#ifdef _KERNEL | #ifdef _KERNEL | ||||
static __inline uint32_t | |||||
ctl_kern_sg_entries(union ctl_io *io) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
return (io->scsiio.kern_sg_entries); | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
return (io->nvmeio.kern_sg_entries); | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline uint8_t * | |||||
ctl_kern_data_ptr(union ctl_io *io) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
return (io->scsiio.kern_data_ptr); | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
return (io->nvmeio.kern_data_ptr); | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline uint32_t | |||||
ctl_kern_data_len(union ctl_io *io) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
return (io->scsiio.kern_data_len); | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
return (io->nvmeio.kern_data_len); | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline uint32_t | |||||
ctl_kern_total_len(union ctl_io *io) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
return (io->scsiio.kern_total_len); | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
return (io->nvmeio.kern_total_len); | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline uint32_t | |||||
ctl_kern_data_resid(union ctl_io *io) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
return (io->scsiio.kern_data_resid); | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
return (io->nvmeio.kern_data_resid); | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline uint32_t | |||||
ctl_kern_rel_offset(union ctl_io *io) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
return (io->scsiio.kern_rel_offset); | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
return (io->nvmeio.kern_rel_offset); | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline void | |||||
ctl_add_kern_rel_offset(union ctl_io *io, uint32_t offset) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
io->scsiio.kern_rel_offset += offset; | |||||
break; | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
io->nvmeio.kern_rel_offset += offset; | |||||
break; | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline void | |||||
ctl_set_kern_sg_entries(union ctl_io *io, uint32_t kern_sg_entries) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
io->scsiio.kern_sg_entries = kern_sg_entries; | |||||
break; | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
io->nvmeio.kern_sg_entries = kern_sg_entries; | |||||
break; | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline void | |||||
ctl_set_kern_data_ptr(union ctl_io *io, void *kern_data_ptr) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
io->scsiio.kern_data_ptr = kern_data_ptr; | |||||
break; | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
io->nvmeio.kern_data_ptr = kern_data_ptr; | |||||
break; | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline void | |||||
ctl_set_kern_data_len(union ctl_io *io, uint32_t kern_data_len) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
io->scsiio.kern_data_len = kern_data_len; | |||||
break; | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
io->nvmeio.kern_data_len = kern_data_len; | |||||
break; | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline void | |||||
ctl_set_kern_total_len(union ctl_io *io, uint32_t kern_total_len) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
io->scsiio.kern_total_len = kern_total_len; | |||||
break; | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
io->nvmeio.kern_total_len = kern_total_len; | |||||
break; | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline void | |||||
ctl_set_kern_data_resid(union ctl_io *io, uint32_t kern_data_resid) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
io->scsiio.kern_data_resid = kern_data_resid; | |||||
break; | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
io->nvmeio.kern_data_resid = kern_data_resid; | |||||
break; | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline void | |||||
ctl_set_kern_rel_offset(union ctl_io *io, uint32_t kern_rel_offset) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
io->scsiio.kern_rel_offset = kern_rel_offset; | |||||
break; | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
io->nvmeio.kern_rel_offset = kern_rel_offset; | |||||
break; | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline void | |||||
ctl_set_be_move_done(union ctl_io *io, ctl_be_move_done_t be_move_done) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
io->scsiio.be_move_done = be_move_done; | |||||
break; | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
io->nvmeio.be_move_done = be_move_done; | |||||
break; | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline void | |||||
ctl_set_io_cont(union ctl_io *io, ctl_io_cont io_cont) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
io->scsiio.io_cont = io_cont; | |||||
break; | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
io->nvmeio.io_cont = io_cont; | |||||
break; | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline void | |||||
ctl_set_kern_data_ref(union ctl_io *io, ctl_ref kern_data_ref) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
io->scsiio.kern_data_ref = kern_data_ref; | |||||
break; | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
io->nvmeio.kern_data_ref = kern_data_ref; | |||||
break; | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
static __inline void | |||||
ctl_set_kern_data_arg(union ctl_io *io, void *kern_data_arg) | |||||
{ | |||||
switch (io->io_hdr.io_type) { | |||||
case CTL_IO_SCSI: | |||||
io->scsiio.kern_data_arg = kern_data_arg; | |||||
break; | |||||
case CTL_IO_NVME: | |||||
case CTL_IO_NVME_ADMIN: | |||||
io->nvmeio.kern_data_arg = kern_data_arg; | |||||
break; | |||||
default: | |||||
__assert_unreachable(); | |||||
} | |||||
} | |||||
union ctl_io *ctl_alloc_io(void *pool_ref); | union ctl_io *ctl_alloc_io(void *pool_ref); | ||||
union ctl_io *ctl_alloc_io_nowait(void *pool_ref); | union ctl_io *ctl_alloc_io_nowait(void *pool_ref); | ||||
void ctl_free_io(union ctl_io *io); | void ctl_free_io(union ctl_io *io); | ||||
void ctl_zero_io(union ctl_io *io); | void ctl_zero_io(union ctl_io *io); | ||||
#endif /* _KERNEL */ | #endif /* _KERNEL */ | ||||
#endif /* _CTL_IO_H_ */ | #endif /* _CTL_IO_H_ */ | ||||
/* | /* | ||||
* vim: ts=8 | * vim: ts=8 | ||||
*/ | */ |