📄 zfcp_aux.c
字号:
(ZFCP_STATUS_PORT_DID_DID, &port->status)) { ZFCP_LOG_INFO("incoming RSCN, trying to open " "port 0x%016Lx\n", port->wwpn); zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED); continue; } /* * FIXME: race: d_id might being invalidated * (...DID_DID reset) */ if ((port->d_id & range_mask) == (fcp_rscn_element->nport_did & range_mask)) { ZFCP_LOG_TRACE("reopen did 0x%08x\n", fcp_rscn_element->nport_did); /* * Unfortunately, an RSCN does not specify the * type of change a target underwent. We assume * that it makes sense to reopen the link. * FIXME: Shall we try to find out more about * the target and link state before closing it? * How to accomplish this? (nameserver?) * Where would such code be put in? * (inside or outside erp) */ ZFCP_LOG_INFO("incoming RSCN, trying to open " "port 0x%016Lx\n", port->wwpn); zfcp_test_link(port); } } read_unlock_irqrestore(&zfcp_data.config_lock, flags); }}static voidzfcp_fsf_incoming_els_plogi(struct zfcp_adapter *adapter, struct fsf_status_read_buffer *status_buffer){ logi *els_logi = (logi *) status_buffer->payload; struct zfcp_port *port; unsigned long flags; read_lock_irqsave(&zfcp_data.config_lock, flags); list_for_each_entry(port, &adapter->port_list_head, list) { if (port->wwpn == (*(wwn_t *) & els_logi->nport_wwn)) break; } read_unlock_irqrestore(&zfcp_data.config_lock, flags); if (!port || (port->wwpn != (*(wwn_t *) & els_logi->nport_wwn))) { ZFCP_LOG_DEBUG("ignored incoming PLOGI for nonexisting port " "with d_id 0x%08x on adapter %s\n", status_buffer->d_id, zfcp_get_busid_by_adapter(adapter)); } else { zfcp_erp_port_forced_reopen(port, 0); }}static voidzfcp_fsf_incoming_els_logo(struct zfcp_adapter *adapter, struct fsf_status_read_buffer *status_buffer){ struct fcp_logo *els_logo = (struct fcp_logo *) status_buffer->payload; struct zfcp_port *port; unsigned long flags; read_lock_irqsave(&zfcp_data.config_lock, flags); list_for_each_entry(port, &adapter->port_list_head, list) { if (port->wwpn == els_logo->nport_wwpn) break; } read_unlock_irqrestore(&zfcp_data.config_lock, flags); if (!port || (port->wwpn != els_logo->nport_wwpn)) { ZFCP_LOG_DEBUG("ignored incoming LOGO for nonexisting port " "with d_id 0x%08x on adapter %s\n", status_buffer->d_id, zfcp_get_busid_by_adapter(adapter)); } else { zfcp_erp_port_forced_reopen(port, 0); }}static voidzfcp_fsf_incoming_els_unknown(struct zfcp_adapter *adapter, struct fsf_status_read_buffer *status_buffer){ ZFCP_LOG_NORMAL("warning: unknown incoming ELS 0x%08x " "for adapter %s\n", *(u32 *) (status_buffer->payload), zfcp_get_busid_by_adapter(adapter));}voidzfcp_fsf_incoming_els(struct zfcp_fsf_req *fsf_req){ struct fsf_status_read_buffer *status_buffer; u32 els_type; struct zfcp_adapter *adapter; status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; els_type = *(u32 *) (status_buffer->payload); adapter = fsf_req->adapter; zfcp_san_dbf_event_incoming_els(fsf_req); if (els_type == LS_PLOGI) zfcp_fsf_incoming_els_plogi(adapter, status_buffer); else if (els_type == LS_LOGO) zfcp_fsf_incoming_els_logo(adapter, status_buffer); else if ((els_type & 0xffff0000) == LS_RSCN) /* we are only concerned with the command, not the length */ zfcp_fsf_incoming_els_rscn(adapter, status_buffer); else zfcp_fsf_incoming_els_unknown(adapter, status_buffer);}/** * zfcp_gid_pn_buffers_alloc - allocate buffers for GID_PN nameserver request * @gid_pn: pointer to return pointer to struct zfcp_gid_pn_data * @pool: pointer to mempool_t if non-null memory pool is used for allocation */static intzfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool){ struct zfcp_gid_pn_data *data; if (pool != NULL) { data = mempool_alloc(pool, GFP_ATOMIC); if (likely(data != NULL)) { data->ct.pool = pool; } } else { data = kmalloc(sizeof(struct zfcp_gid_pn_data), GFP_ATOMIC); } if (NULL == data) return -ENOMEM; memset(data, 0, sizeof(*data)); data->ct.req = &data->req; data->ct.resp = &data->resp; data->ct.req_count = data->ct.resp_count = 1; zfcp_address_to_sg(&data->ct_iu_req, &data->req); zfcp_address_to_sg(&data->ct_iu_resp, &data->resp); data->req.length = sizeof(struct ct_iu_gid_pn_req); data->resp.length = sizeof(struct ct_iu_gid_pn_resp); *gid_pn = data; return 0;}/** * zfcp_gid_pn_buffers_free - free buffers for GID_PN nameserver request * @gid_pn: pointer to struct zfcp_gid_pn_data which has to be freed */static voidzfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn){ if ((gid_pn->ct.pool != 0)) mempool_free(gid_pn, gid_pn->ct.pool); else kfree(gid_pn); return;}/** * zfcp_ns_gid_pn_request - initiate GID_PN nameserver request * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed */intzfcp_ns_gid_pn_request(struct zfcp_erp_action *erp_action){ int ret; struct ct_iu_gid_pn_req *ct_iu_req; struct zfcp_gid_pn_data *gid_pn; struct zfcp_adapter *adapter = erp_action->adapter; ret = zfcp_gid_pn_buffers_alloc(&gid_pn, adapter->pool.data_gid_pn); if (ret < 0) { ZFCP_LOG_INFO("error: buffer allocation for gid_pn nameserver " "request failed for adapter %s\n", zfcp_get_busid_by_adapter(adapter)); goto out; } /* setup nameserver request */ ct_iu_req = zfcp_sg_to_address(gid_pn->ct.req); ct_iu_req->header.revision = ZFCP_CT_REVISION; ct_iu_req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; ct_iu_req->header.gs_subtype = ZFCP_CT_NAME_SERVER; ct_iu_req->header.options = ZFCP_CT_SYNCHRONOUS; ct_iu_req->header.cmd_rsp_code = ZFCP_CT_GID_PN; ct_iu_req->header.max_res_size = ZFCP_CT_MAX_SIZE; ct_iu_req->wwpn = erp_action->port->wwpn; /* setup parameters for send generic command */ gid_pn->ct.port = adapter->nameserver_port; gid_pn->ct.handler = zfcp_ns_gid_pn_handler; gid_pn->ct.handler_data = (unsigned long) gid_pn; gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; gid_pn->ct.timer = &erp_action->timer; gid_pn->port = erp_action->port; ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp, erp_action); if (ret) { ZFCP_LOG_INFO("error: initiation of gid_pn nameserver request " "failed for adapter %s\n", zfcp_get_busid_by_adapter(adapter)); zfcp_gid_pn_buffers_free(gid_pn); } out: return ret;}/** * zfcp_ns_gid_pn_handler - handler for GID_PN nameserver request * @data: unsigned long, contains pointer to struct zfcp_gid_pn_data */static void zfcp_ns_gid_pn_handler(unsigned long data){ struct zfcp_port *port; struct zfcp_send_ct *ct; struct ct_iu_gid_pn_req *ct_iu_req; struct ct_iu_gid_pn_resp *ct_iu_resp; struct zfcp_gid_pn_data *gid_pn; gid_pn = (struct zfcp_gid_pn_data *) data; port = gid_pn->port; ct = &gid_pn->ct; ct_iu_req = zfcp_sg_to_address(ct->req); ct_iu_resp = zfcp_sg_to_address(ct->resp); if (ct->status != 0) goto failed; if (zfcp_check_ct_response(&ct_iu_resp->header)) { /* FIXME: do we need some specific erp entry points */ atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); goto failed; } /* paranoia */ if (ct_iu_req->wwpn != port->wwpn) { ZFCP_LOG_NORMAL("bug: wwpn 0x%016Lx returned by nameserver " "lookup does not match expected wwpn 0x%016Lx " "for adapter %s\n", ct_iu_req->wwpn, port->wwpn, zfcp_get_busid_by_port(port)); goto mismatch; } /* looks like a valid d_id */ port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); ZFCP_LOG_DEBUG("adapter %s: wwpn=0x%016Lx ---> d_id=0x%08x\n", zfcp_get_busid_by_port(port), port->wwpn, port->d_id); goto out; mismatch: ZFCP_LOG_DEBUG("CT IUs do not match:\n"); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_req, sizeof(struct ct_iu_gid_pn_req)); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_resp, sizeof(struct ct_iu_gid_pn_resp)); failed: ZFCP_LOG_NORMAL("warning: failed gid_pn nameserver request for wwpn " "0x%016Lx for adapter %s\n", port->wwpn, zfcp_get_busid_by_port(port)); out: zfcp_gid_pn_buffers_free(gid_pn); return;}/* reject CT_IU reason codes acc. to FC-GS-4 */static const struct zfcp_rc_entry zfcp_ct_rc[] = { {0x01, "invalid command code"}, {0x02, "invalid version level"}, {0x03, "logical error"}, {0x04, "invalid CT_IU size"}, {0x05, "logical busy"}, {0x07, "protocol error"}, {0x09, "unable to perform command request"}, {0x0b, "command not supported"}, {0x0d, "server not available"}, {0x0e, "session could not be established"}, {0xff, "vendor specific error"}, {0, NULL},};/* LS_RJT reason codes acc. to FC-FS */static const struct zfcp_rc_entry zfcp_ls_rjt_rc[] = { {0x01, "invalid LS_Command code"}, {0x03, "logical error"}, {0x05, "logical busy"}, {0x07, "protocol error"}, {0x09, "unable to perform command request"}, {0x0b, "command not supported"}, {0x0e, "command already in progress"}, {0xff, "vendor specific error"}, {0, NULL},};/* reject reason codes according to FC-PH/FC-FS */static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = { {0x01, "invalid D_ID"}, {0x02, "invalid S_ID"}, {0x03, "Nx_Port not available, temporary"}, {0x04, "Nx_Port not available, permament"}, {0x05, "class not supported"}, {0x06, "delimiter usage error"}, {0x07, "TYPE not supported"}, {0x08, "invalid Link_Control"}, {0x09, "invalid R_CTL field"}, {0x0a, "invalid F_CTL field"}, {0x0b, "invalid OX_ID"}, {0x0c, "invalid RX_ID"}, {0x0d, "invalid SEQ_ID"}, {0x0e, "invalid DF_CTL"}, {0x0f, "invalid SEQ_CNT"}, {0x10, "invalid parameter field"}, {0x11, "exchange error"}, {0x12, "protocol error"}, {0x13, "incorrect length"}, {0x14, "unsupported ACK"}, {0x15, "class of service not supported by entity at FFFFFE"}, {0x16, "login required"}, {0x17, "excessive sequences attempted"}, {0x18, "unable to establish exchange"}, {0x1a, "fabric path not available"}, {0x1b, "invalid VC_ID (class 4)"}, {0x1c, "invalid CS_CTL field"}, {0x1d, "insufficient resources for VC (class 4)"}, {0x1f, "invalid class of service"}, {0x20, "preemption request rejected"}, {0x21, "preemption not enabled"}, {0x22, "multicast error"}, {0x23, "multicast error terminate"}, {0x24, "process login required"}, {0xff, "vendor specific reject"}, {0, NULL},};/** * zfcp_rc_description - return description for given reaon code * @code: reason code * @rc_table: table of reason codes and descriptions */static inline const char *zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table){ const char *descr = "unknown reason code"; do { if (code == rc_table->code) { descr = rc_table->description; break; } rc_table++; } while (rc_table->code && rc_table->description); return descr;}/** * zfcp_check_ct_response - evaluate reason code for CT_IU * @rjt: response payload to an CT_IU request * Return: 0 for accept CT_IU, 1 for reject CT_IU or invlid response code */intzfcp_check_ct_response(struct ct_hdr *rjt){ if (rjt->cmd_rsp_code == ZFCP_CT_ACCEPT) return 0; if (rjt->cmd_rsp_code != ZFCP_CT_REJECT) { ZFCP_LOG_NORMAL("error: invalid Generic Service command/" "response code (0x%04hx)\n", rjt->cmd_rsp_code); return 1; } ZFCP_LOG_INFO("Generic Service command rejected\n"); ZFCP_LOG_INFO("%s (0x%02x, 0x%02x, 0x%02x)\n", zfcp_rc_description(rjt->reason_code, zfcp_ct_rc), (u32) rjt->reason_code, (u32) rjt->reason_code_expl, (u32) rjt->vendor_unique); return 1;}/** * zfcp_print_els_rjt - print reject parameter and description for ELS reject * @rjt_par: reject parameter acc. to FC-PH/FC-FS * @rc_table: table of reason codes and descriptions */static inline voidzfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par, const struct zfcp_rc_entry *rc_table){ ZFCP_LOG_INFO("%s (%02x %02x %02x %02x)\n", zfcp_rc_description(rjt_par->reason_code, rc_table), (u32) rjt_par->action, (u32) rjt_par->reason_code, (u32) rjt_par->reason_expl, (u32) rjt_par->vendor_unique);}/** * zfcp_fsf_handle_els_rjt - evaluate status qualifier/reason code on ELS reject * @sq: status qualifier word * @rjt_par: reject parameter as described in FC-PH and FC-FS * Return: -EROMTEIO for LS_RJT, -EREMCHG for invalid D_ID, -EIO else */intzfcp_handle_els_rjt(u32 sq, struct zfcp_ls_rjt_par *rjt_par){ int ret = -EIO; if (sq == FSF_IOSTAT_NPORT_RJT) { ZFCP_LOG_INFO("ELS rejected (P_RJT)\n"); zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); /* invalid d_id */ if (rjt_par->reason_code == 0x01) ret = -EREMCHG; } else if (sq == FSF_IOSTAT_FABRIC_RJT) { ZFCP_LOG_INFO("ELS rejected (F_RJT)\n"); zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); /* invalid d_id */ if (rjt_par->reason_code == 0x01) ret = -EREMCHG; } else if (sq == FSF_IOSTAT_LS_RJT) { ZFCP_LOG_INFO("ELS rejected (LS_RJT)\n"); zfcp_print_els_rjt(rjt_par, zfcp_ls_rjt_rc); ret = -EREMOTEIO; } else ZFCP_LOG_INFO("unexpected SQ: 0x%02x\n", sq); return ret;}#undef ZFCP_LOG_AREA
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -