49 #define frame_printf(ocs, hdr, fmt, ...) \
52 ocs_node_fcid_display(fc_be24toh((hdr)->s_id), s_id_text, sizeof(s_id_text)); \
53 ocs_log_debug(ocs, "[%06x.%s] %02x/%04x/%04x: " fmt, fc_be24toh((hdr)->d_id), s_id_text, \
54 (hdr)->r_ctl, ocs_be16toh((hdr)->ox_id), ocs_be16toh((hdr)->rx_id), ##__VA_ARGS__); \
67 static int32_t
ocs_purge_pending(ocs_t *ocs, ocs_list_t *pend_list, ocs_lock_t *list_lock);
71 #define OCS_MAX_FRAMES_BEFORE_YEILDING 10000
84 ocs_t *ocs = thread_data->
ocs;
88 ocs_log_debug(ocs,
"%s running\n", mythread->name);
89 while (!ocs_thread_terminate_requested(mythread)) {
93 ocs_thread_yield(&thread_data->
thread);
101 if (--yield_count == 0) {
102 ocs_thread_yield(&thread_data->
thread);
106 ocs_log_debug(ocs,
"%s exiting\n", mythread->name);
119 ocs_unsol_abort_cb (ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t len, int32_t status, uint32_t ext,
void *arg)
124 ocs_log_debug(ocs,
"xri=0x%x tag=0x%x\n", hio->indicator, hio->reqtag);
143 ocs_log_debug(ocs,
"already aborted XRI 0x%x\n", hio->indicator);
145 ocs_log_debug(ocs,
"Error aborting XRI 0x%x status %d\n",
146 hio->indicator, hal_rc);
167 ocs_xport_t *xport = ocs->xport;
172 if (ocs->rq_threads == 0) {
177 uint32_t ox_id = ocs_be16toh(hdr->
ox_id);
178 uint32_t thr_index = ox_id % ocs->rq_threads;
180 rc =
ocs_cbuf_put(xport->rq_thread_info[thr_index].seq_cbuf, seq);
206 ocs_domain_t *domain;
207 uint8_t seq_fcfi = seq->
fcfi;
210 if (ocs->hal.workaround.override_fcfi) {
211 if (ocs->hal.first_domain_idx > -1) {
212 seq_fcfi = ocs->hal.first_domain_idx;
217 if (seq_fcfi < ARRAY_SIZE(ocs->xport->fcfi)) {
218 xport_fcfi = &ocs->xport->fcfi[seq_fcfi];
222 if (xport_fcfi == NULL) {
223 ocs_log_test(ocs,
"FCFI %d is not valid, dropping frame\n", seq->
fcfi);
224 if (seq->
hio != NULL) {
238 if (domain == NULL ||
245 if (domain != NULL) {
255 if (seq->
hio != NULL) {
280 ocs_t *ocs = node->ocs;
282 uint32_t pend_frames_processed = 0;
294 ocs_lock(&node->pend_frames_lock);
297 pend_frames_processed = node->pend_frames_processed;
298 node->pend_frames_processed = 0;
299 ocs_unlock(&node->pend_frames_lock);
302 node->pend_frames_processed++;
303 ocs_unlock(&node->pend_frames_lock);
307 if (seq->
hio != NULL) {
314 if (pend_frames_processed != 0) {
315 ocs_log_debug(ocs,
"%u node frames held and processed\n", pend_frames_processed);
338 ocs_t *ocs = domain->ocs;
341 uint32_t pend_frames_processed = 0;
344 xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
369 if (seq->
hio != NULL) {
375 if (pend_frames_processed != 0) {
376 ocs_log_debug(ocs,
"%u domain frames held and processed\n", pend_frames_processed);
408 if (frame->
hio != NULL) {
433 return ocs_purge_pending(node->ocs, &node->pend_frames, &node->pend_frames_lock);
452 ocs_t *ocs = domain->ocs;
456 xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
476 ocs_node_t *node = (ocs_node_t *)arg;
477 return node->hold_frames;
494 ocs_domain_t *domain = (ocs_domain_t *)arg;
495 ocs_t *ocs = domain->ocs;
500 xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
520 ocs_t *ocs = domain->ocs;
524 xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
526 ocs_log_debug(domain->ocs,
"hold frames set for FCFI %d\n",
527 domain->fcf_indicator);
548 ocs_t *ocs = domain->ocs;
552 xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
554 ocs_log_debug(domain->ocs,
"hold frames cleared for FCFI %d\n",
555 domain->fcf_indicator);
577 static __inline int32_t
580 ocs_domain_t *domain = (ocs_domain_t *)arg;
581 ocs_t *ocs = domain->ocs;
585 ocs_node_t *node = NULL;
586 ocs_sport_t *sport = NULL;
598 sport = domain->sport;
600 frame_printf(ocs, hdr,
"phy sport for FC ID 0x%06x is NULL, dropping frame\n", d_id);
604 if (sport->fc_id != d_id) {
610 ocs_log_warn(ocs,
"unsolicited FCP frame with invalid d_id x%x, dropping\n",
615 sport = domain->sport;
630 ocs_log_debug(ocs,
"solicited data/ctrl frame without node, dropping\n");
635 ocs_log_err(ocs,
"ocs_node_alloc() failed\n");
656 ocs_lock(&node->pend_frames_lock);
658 ocs_unlock(&node->pend_frames_lock);
686 ocs_node_t *node = (ocs_node_t *)arg;
698 switch (hdr->
r_ctl) {
717 if (node->fcp_enabled) {
743 node_printf(node,
"Dropping frame hdr = %08x %08x %08x %08x %08x %08x\n",
744 ocs_htobe32(((uint32_t *)hdr)[0]),
745 ocs_htobe32(((uint32_t *)hdr)[1]),
746 ocs_htobe32(((uint32_t *)hdr)[2]),
747 ocs_htobe32(((uint32_t *)hdr)[3]),
748 ocs_htobe32(((uint32_t *)hdr)[4]),
749 ocs_htobe32(((uint32_t *)hdr)[5]));
785 io->exp_xfer_len = 0;
787 for (i = 0; i < ARRAY_SIZE(tmflist); i ++) {
788 if (tmflist[i].mask & task_management_flags) {
789 io->tmf_cmd = tmflist[i].cmd;
790 ocs_log_info(io->ocs,
"Process Unsol TMF cmd %d lun %d\n", tmflist[i].cmd, lun);
795 if (i == ARRAY_SIZE(tmflist)) {
797 node_printf(node,
"TMF x%x rejected\n", task_management_flags);
805 size_t exp_payload_len = 0;
814 if (seq->
payload->
dma.len < exp_payload_len) {
816 ocs_log_debug(ocs,
"dropping ox_id %04x with payload length (%zd) less than expected (%zd)\n",
829 io->init_task_tag = ocs_be16toh(fchdr->
ox_id);
833 io->exp_xfer_len = ocs_be32toh(*fcp_dl);
842 io->cs_ctl = fchdr->
cs_ctl;
896 ocs_t *ocs = node->ocs;
902 uint32_t lun = UINT32_MAX;
914 if (lun == UINT32_MAX) {
920 uint32_t send_frame_capable;
924 if ((rc == 0) && send_frame_capable) {
927 ocs_log_test(ocs,
"ocs_sframe_send_task_set_full_or_busy failed: %d\n", rc);
932 ocs_log_err(ocs,
"IO allocation failed ox_id %04x\n", ocs_be16toh(fchdr->
ox_id));
941 uint32_t vmhdr_offset = 0;
945 ocs_log_err(ocs,
"ESP Header present. Fix ESP Size.\n");
952 io->app_id = ocs_be32toh(vhdr->
src_vmid);
993 ocs_t *ocs = node->ocs;
997 uint32_t lun = UINT32_MAX;
1010 node_printf(node,
"IO is not optimized write assisted, dropping FCP_CMND\n");
1020 uint32_t send_frame_capable;
1024 if ((rc == 0) && send_frame_capable) {
1027 ocs_log_test(ocs,
"ocs_sframe_send_task_set_full_or_busy failed: %d\n", rc);
1032 ocs_log_err(ocs,
"IO allocation failed ox_id %04x\n", ocs_be16toh(fchdr->
ox_id));
1051 seq->
hio->ul_io = io;
1052 io->tgt_task_tag = seq->
hio->indicator;
1084 ocs_t *ocs = node->ocs;
1085 ocs_hal_t *hal = &ocs->hal;
1086 ocs_hal_io_t *hio = seq->
hio;
1088 ocs_dma_t fburst[1];
1095 ocs_log_err(ocs,
"data received for NULL io, xri=0x%x\n",
1105 ocs_log_err(ocs,
"data received for host owned XRI, xri=0x%x\n",
1112 ocs_log_err(ocs,
"data with status 0x%x received, xri=0x%x\n",
1113 seq->
status, hio->indicator);
1139 fburst, io->transferred)) {
1140 ocs_log_err(ocs,
"error passing first burst, xri=0x%x, oxid=0x%x\n",
1141 hio->indicator, io->init_task_tag);
1190 uint32_t lun = UINT32_MAX;
1191 uint8_t address_method = -1;
1195 switch (address_method) {
1200 if (0 == bus_identifier) {
1203 ocs_log_test(NULL,
"unsupported bus identifier %#02x (LU %02x %02x %02x %02x ...\n",
1204 bus_identifier, lu[0], lu[1], lu[2], lu[3]);
1215 uint8_t length, extended_address_method;
1217 length = (lu[0] & 0x30) >> 4;
1218 extended_address_method = lu[0] & 0xf;
1220 if ((1 == length) && (2 == extended_address_method)) {
1221 lun = (lu[1] << 16) | (lu[2] << 8) | lu[3];
1223 ocs_log_test(NULL,
"unsupported extended addressing method (length=%#x method=%#x)\n",
1224 length, extended_address_method);
1229 ocs_log_test(NULL,
"unsupported LU address method %#02x\n", address_method);
1252 ocs_lock(list_lock);
1254 ocs_unlock(list_lock);
1274 ocs_hal_t *hal = ctx->
hal;
1304 uint8_t type,
void *payload, uint32_t payload_len)
1306 ocs_t *ocs = node->ocs;
1307 ocs_hal_t *hal = &ocs->hal;
1313 uint16_t ox_id = ocs_be16toh(behdr->
ox_id);
1314 uint16_t rx_id = ocs_be16toh(behdr->
rx_id);
1318 uintptr_t heap_phys_base = seq->
payload->
dma.phys;
1319 uint8_t *heap_virt_base = seq->
payload->
dma.virt;
1320 uint32_t heap_offset = 0;
1323 ocs_memset(&hdr, 0,
sizeof(hdr));
1338 hdr.
seq_id = (uint8_t) ocs_atomic_add_return(&hal->send_frame_seq_id, 1);
1345 ctx = (
void*)(heap_virt_base + heap_offset);
1346 heap_offset +=
sizeof(*ctx);
1348 ocs_memset(ctx, 0,
sizeof(*ctx));
1354 ctx->
payload.phys = heap_phys_base + heap_offset;
1355 ctx->
payload.virt = heap_virt_base + heap_offset;
1356 ctx->
payload.size = payload_len;
1357 ctx->
payload.len = payload_len;
1358 heap_offset += payload_len;
1362 ocs_memcpy(ctx->
payload.virt, payload, payload_len);
1368 ocs_log_test(ocs,
"ocs_hal_send_frame failed: %d\n", rc);
1415 uint32_t *fcp_dl_ptr;
1422 fcp_dl = ocs_be32toh(*fcp_dl_ptr);
1425 ocs_memset(&fcprsp, 0,
sizeof(fcprsp));
1426 ocs_lock(&node->active_ios_lock);
1428 ocs_unlock(&node->active_ios_lock);
1429 *((uint32_t*)&fcprsp.
fcp_resid) = fcp_dl;
1434 ocs_log_test(node->ocs,
"ocs_sframe_send_fcp_rsp failed: %d\n", rc);
1453 uint16_t ox_id = ocs_be16toh(behdr->
ox_id);
1454 uint16_t rx_id = ocs_be16toh(behdr->
rx_id);
1457 acc.
ox_id = ocs_htobe16(ox_id);
1458 acc.
rx_id = ocs_htobe16(rx_id);
void ocs_domain_accept_frames(ocs_domain_t *domain)
Clear hold on unsolicited frames.
uint8_t additional_fcp_cdb_length
#define OCS_SCSI_FIRST_BURST_ERR
int32_t ocs_hal_io_free(ocs_hal_t *hal, ocs_hal_io_t *io)
Free a previously-allocated HAL IO object.
static int32_t ocs_sframe_send_task_set_full_or_busy(ocs_node_t *node, ocs_hal_sequence_t *seq)
Send task set full response.
#define OCS_MAX_FRAMES_BEFORE_YEILDING
ocs_sport_t * ocs_sport_find(ocs_domain_t *domain, uint32_t d_id)
Find a SLI port object, given an FC_ID.
int32_t ocs_scsi_recv_tmf(ocs_io_t *tmfio, uint32_t lun, ocs_scsi_tmf_cmd_e cmd, ocs_io_t *abortio, uint32_t flags)
Receive a TMF command IO.
int32_t ocs_node_recv_bls_no_sit(ocs_node_t *node, ocs_hal_sequence_t *seq)
Stub handler for non-ABTS BLS frames.
uint8_t ocs_hal_is_io_port_owned(ocs_hal_t *hal, ocs_hal_io_t *io)
Determine if HAL IO is owned by the port.
void ocs_hal_reqtag_free(ocs_hal_t *hal, hal_wq_callback_t *wqcb)
Free a WQ request tag.
#define OCS_SCSI_CMD_HEAD_OF_QUEUE
int32_t ocs_node_recv_abts_frame(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch a ABTS frame (RQ Pair/sequence coalescing).
uint32_t pend_frames_processed
int32_t ocs_domain_purge_pending(ocs_domain_t *domain)
Purge xport's pending (queued) frames.
ocs_hal_rq_buffer_t * header
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
int32_t ocs_node_recv_ct_frame(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch a CT frame.
#define FC_RCTL_INFO_UNSOL_DATA
#define FC_FCTL_SEQUENCE_INITIATIVE
#define FCP_TASK_ATTR_ORDERED
static void ocs_dispatch_unsolicited_tmf(ocs_io_t *io, uint8_t task_management_flags, ocs_node_t *node, uint32_t lun)
Dispatch unsolicited FCP frames (RQ Pair).
ocs_hal_rtn_e ocs_hal_send_frame(ocs_hal_t *hal, fc_header_le_t *hdr, uint8_t sof, uint8_t eof, ocs_dma_t *payload, ocs_hal_send_frame_context_t *ctx, void(*callback)(void *arg, uint8_t *cqe, int32_t status), void *arg)
Send a raw frame.
int32_t ocs_domain_process_pending(ocs_domain_t *domain)
Process pending frames queued to the given domain.
ocs_hal_rtn_e ocs_hal_io_abort(ocs_hal_t *hal, ocs_hal_io_t *io_to_abort, uint32_t send_abts, void *cb, void *arg)
Abort a previously-started IO.
#define FCP_CLEAR_TASK_SET
#define FCP_TASK_ATTR_UNTAGGED
static uint32_t ocs_fc_decode_lun(uint8_t *lu)
Decode a LU Number according to SAM.
#define frame_printf(ocs, hdr, fmt,...)
static void ocs_sframe_common_send_cb(void *arg, uint8_t *cqe, int32_t status)
Process send fcp response frame callback.
#define FC_TYPE_BASIC_LINK
#define FCP_TASK_ATTR_SIMPLE
#define FCP_LUN_ADDRESS_METHOD_MASK
int32_t ocs_node_purge_pending(ocs_node_t *node)
Purge node's pending (queued) frames.
ocs_hal_sequence_t * ocs_frame_next(ocs_list_t *pend_list, ocs_lock_t *list_lock)
Return next FC frame on node->pend_frames list.
ocs_node_t * ocs_node_find(ocs_sport_t *sport, uint32_t port_id)
Find an FC node structure given the FC port ID.
#define FC_RCTL_INFO_CMD_STATUS
void ocs_scsi_io_free(ocs_io_t *io)
Free a SCSI IO context.
void ocs_node_init_device(ocs_node_t *node, int send_plogi)
Initialize device node.
#define OCS_SCSI_CMD_DIR_OUT
#define FCP_LUN_ADDR_METHOD_PERIPHERAL
#define FC_FCTL_END_SEQUENCE
#define FCP_TASK_ATTR_ACA
static uint8_t ocs_domain_frames_held(void *arg)
Check if domain's pending frames are held.
ocs_lock_t pend_frames_lock
static ocs_hal_rtn_e ocs_hal_sequence_free(ocs_hal_t *hal, ocs_hal_sequence_t *seq)
static int32_t ocs_purge_pending(ocs_t *ocs, ocs_list_t *pend_list, ocs_lock_t *list_lock)
Purge given pending list.
#define FCP_QUERY_ASYNCHRONOUS_EVENT
#define FC_DFCTL_ESP_HDR_MASK
int32_t ocs_unsolicited_cb(void *arg, ocs_hal_sequence_t *seq)
Handle unsolicited FC frames.
#define FC_RCTL_INFO_UNSOL_CMD
static int32_t ocs_dispatch_fcp_data(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch FCP data frames for TOW.
static void ocs_populate_io_fcp_cmd(ocs_io_t *io, fcp_cmnd_iu_t *cmnd, fc_header_t *fchdr, uint8_t sit)
#define OCS_SCSI_CMD_UNTAGGED
#define FCP_ABORT_TASK_SET
#define FCP_QUERY_TASK_SET
#define FC_DFCTL_NETWORK_HDR_SIZE
#define OCS_SCSI_CMD_SIMPLE
ocs_hal_rtn_e ocs_hal_get(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t *value)
static int32_t ocs_node_dispatch_frame(void *arg, ocs_hal_sequence_t *seq)
Dispatch a frame.
#define FC_RCTL_INFO_SOL_CTRL
uint8_t data[FCP_MAX_RSP_INFO_LEN]
static int32_t ocs_fc_tmf_rejected_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg)
Handle the callback for the TMF FUNCTION_REJECTED response.
#define OCS_SCSI_CMD_ORDERED
static int32_t ocs_dispatch_tow_fcp_cmd(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch unsolicited FCP_CMND frame.
static uint32_t ocs_get_flags_fcp_cmd(fcp_cmnd_iu_t *cmnd)
static void ocs_port_owned_abort(ocs_t *ocs, ocs_hal_io_t *hio)
Abort either a RQ Pair auto XFER RDY XRI.
void * ocs_cbuf_get(ocs_cbuf_t *cbuf, int32_t timeout_usec)
Get pointer to buffer.
ocs_node_t * ocs_node_alloc(ocs_sport_t *sport, uint32_t port_id, uint8_t init, uint8_t targ)
Allocate an fc node structure and add to node list.
#define FC_FCTL_PRIORITY_ENABLE
int32_t ocs_scsi_recv_cmd(ocs_io_t *io, uint32_t lun, uint8_t *cdb, uint32_t cdb_len, uint32_t flags)
ocs_domain_t * ocs_hal_domain_get(ocs_hal_t *hal, uint16_t fcfi)
static int32_t ocs_unsol_process(ocs_t *ocs, ocs_hal_sequence_t *seq)
Handle unsolicited FC frames.
int32_t ocs_node_recv_els_frame(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch a ELS frame.
uint8_t fcp_cdb_and_dl[20]
static int32_t ocs_validate_fcp_cmd(ocs_t *ocs, ocs_hal_sequence_t *seq)
#define SCSI_STATUS_TASK_SET_FULL
#define FC_FCTL_EXCHANGE_RESPONDER
ocs_hal_unsol_status_e status
static void ocs_list_add_tail(ocs_list_t *list, void *item)
Add an item to the tail of the list.
void ocs_domain_hold_frames(ocs_domain_t *domain)
Globally (at xport level) hold unsolicited frames.
#define ocs_list_remove_head(list)
Remove and return an item from the head of the list.
ocs_hal_io_t * ocs_hal_io_activate_port_owned(ocs_hal_t *hal, ocs_hal_io_t *io)
Allocate/Activate a port owned HAL IO object.
int32_t ocs_sframe_send_bls_acc(ocs_node_t *node, ocs_hal_sequence_t *seq)
Send BA_ACC using sent frame.
static int32_t ocs_sframe_common_send(ocs_node_t *node, ocs_hal_sequence_t *seq, uint8_t r_ctl, uint8_t info, uint32_t f_ctl, uint8_t type, void *payload, uint32_t payload_len)
Send a frame, common code.
#define OCS_SCSI_CMD_DIR_IN
static int32_t ocs_sframe_send_fcp_rsp(ocs_node_t *node, ocs_hal_sequence_t *seq, void *rsp, uint32_t rsp_len)
Send FCP response using SEND_FRAME.
Defines a general FC sequence object, consisting of a header, payload buffers and a HAL IO in the cas...
#define FC_DFCTL_DEVICE_HDR_16_MASK
#define FCP_LUN_ADDR_METHOD_FLAT
#define FCP_LOGICAL_UNIT_RESET
FCFI lookup/pending frames.
int32_t ocs_process_node_pending(ocs_node_t *node)
Process pending frames queued to the given node.
#define node_printf(node, fmt,...)
#define FC_DFCTL_ESP_HDR_SIZE
#define SLI4_MAX_FCFI
Maximum value for a FCFI.
#define ocs_assert(cond,...)
int32_t ocs_cbuf_put(ocs_cbuf_t *cbuf, void *elem)
write a buffer
static int32_t ocs_unsol_abort_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t len, int32_t status, uint32_t ext, void *arg)
Callback function when aborting a port owned XRI exchanges.
static uint32_t fc_be24toh(uint32_t x)
int32_t ocs_scsi_send_tmf_resp(ocs_io_t *io, ocs_scsi_tmf_resp_e rspcode, uint8_t addl_rsp_info[3], ocs_scsi_io_cb_t cb, void *arg)
Send TMF response data.
ocs_io_t * ocs_scsi_io_alloc(ocs_node_t *node, ocs_scsi_io_role_e role)
Allocate a SCSI IO context.
int32_t ocs_unsol_rq_thread(ocs_thread_t *mythread)
Process the RQ circular buffer and process the incoming frames.
int32_t ocs_scsi_recv_cmd_first_burst(ocs_io_t *io, uint32_t lun, uint8_t *cdb, uint32_t cdb_len, uint32_t flags, ocs_dma_t first_burst_buffers[], uint32_t first_burst_bytes)
Receive an FCP SCSI command with the first burst data.
#define FC_RCTL_INFO_SOL_DATA
int32_t ocs_node_recv_fcp_cmd(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch a FCP command frame when the node is not ready.
uint8_t uint8_t task_management_flags
static int32_t ocs_dispatch_fcp_cmd(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch unsolicited FCP_CMND frame.
int32_t ocs_scsi_io_alloc_enabled(ocs_node_t *node)
Get state of IO allocation.
static int32_t ocs_domain_dispatch_frame(void *arg, ocs_hal_sequence_t *seq)
Dispatch unsolicited FC frame.
#define FCP_LUN_ADDRESS_METHOD_SHIFT
ocs_hal_rq_buffer_t * payload
static uint8_t ocs_node_frames_held(void *arg)
Check if node's pending frames are held.
#define FC_DFCTL_NETWORK_HDR_MASK
Structure to hold the information related to an RQ processing thread used to increase 40G performance...
#define FC_FCTL_LAST_SEQUENCE
#define FCP_TASK_ATTR_HEAD_OF_QUEUE
#define FCP_LUN_ADDR_METHOD_EXTENDED