📄 zfcp_fsf.c
字号:
ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, ZFCP_REQ_AUTO_CLEANUP, NULL, &lock_flags, &fsf_req); if (ret < 0) { ZFCP_LOG_INFO("error: creation of ELS request failed " "(adapter %s, port d_id: 0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id); goto failed_req; } sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); if (zfcp_use_one_sbal(els->req, els->req_count, els->resp, els->resp_count)){ /* both request buffer and response buffer fit into one sbale each */ sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; sbale[2].addr = zfcp_sg_to_address(&els->req[0]); sbale[2].length = els->req[0].length; sbale[3].addr = zfcp_sg_to_address(&els->resp[0]); sbale[3].length = els->resp[0].length; sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; } else if (adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS) { /* try to use chained SBALs */ bytes = zfcp_qdio_sbals_from_sg(fsf_req, SBAL_FLAGS0_TYPE_WRITE_READ, els->req, els->req_count, ZFCP_MAX_SBALS_PER_ELS_REQ); if (bytes <= 0) { ZFCP_LOG_INFO("error: creation of ELS request failed " "(adapter %s, port d_id: 0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id); if (bytes == 0) { ret = -ENOMEM; } else { ret = bytes; } goto failed_send; } fsf_req->qtcb->bottom.support.req_buf_length = bytes; fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; bytes = zfcp_qdio_sbals_from_sg(fsf_req, SBAL_FLAGS0_TYPE_WRITE_READ, els->resp, els->resp_count, ZFCP_MAX_SBALS_PER_ELS_REQ); if (bytes <= 0) { ZFCP_LOG_INFO("error: creation of ELS request failed " "(adapter %s, port d_id: 0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id); if (bytes == 0) { ret = -ENOMEM; } else { ret = bytes; } goto failed_send; } fsf_req->qtcb->bottom.support.resp_buf_length = bytes; } else { /* reject request */ ZFCP_LOG_INFO("error: microcode does not support chained SBALs" ", ELS request too big (adapter %s, " "port d_id: 0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id); ret = -EOPNOTSUPP; goto failed_send; } /* settings in QTCB */ fsf_req->qtcb->bottom.support.d_id = d_id; fsf_req->qtcb->bottom.support.service_class = adapter->fc_service_class; fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT; fsf_req->data = (unsigned long) els; sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); zfcp_san_dbf_event_els_request(fsf_req); /* start QDIO request for this FSF request */ ret = zfcp_fsf_req_send(fsf_req, els->timer); if (ret) { ZFCP_LOG_DEBUG("error: initiation of ELS request failed " "(adapter %s, port d_id: 0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id); goto failed_send; } ZFCP_LOG_DEBUG("ELS request initiated (adapter %s, port d_id: " "0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id); goto out; failed_send: zfcp_fsf_req_free(fsf_req); failed_req: out: write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); return ret;}/** * zfcp_fsf_send_els_handler - handler for ELS commands * @fsf_req: pointer to struct zfcp_fsf_req * * Data specific for the ELS command is passed using * fsf_req->data. There we find the pointer to struct zfcp_send_els. * Usually a specific handler for the ELS command is called which is * found in this structure. */static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req){ struct zfcp_adapter *adapter; struct zfcp_port *port; u32 d_id; struct fsf_qtcb_header *header; struct fsf_qtcb_bottom_support *bottom; struct zfcp_send_els *send_els; int retval = -EINVAL; u16 subtable, rule, counter; send_els = (struct zfcp_send_els *) fsf_req->data; adapter = send_els->adapter; port = send_els->port; d_id = send_els->d_id; header = &fsf_req->qtcb->header; bottom = &fsf_req->qtcb->bottom.support; if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) goto skip_fsfstatus; switch (header->fsf_status) { case FSF_GOOD: zfcp_san_dbf_event_els_response(fsf_req); retval = 0; break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: if (adapter->fc_service_class <= 3) { ZFCP_LOG_INFO("error: adapter %s does " "not support fibrechannel class %d.\n", zfcp_get_busid_by_adapter(adapter), adapter->fc_service_class); } else { ZFCP_LOG_INFO("bug: The fibrechannel class at " "adapter %s is invalid. " "(debug info %d)\n", zfcp_get_busid_by_adapter(adapter), adapter->fc_service_class); } /* stop operation for this adapter */ debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup"); zfcp_erp_adapter_shutdown(adapter, 0); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]){ case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest"); if (port && (send_els->ls_code != ZFCP_LS_ADISC)) zfcp_test_link(port); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp"); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; retval = zfcp_handle_els_rjt(header->fsf_status_qual.word[1], (struct zfcp_ls_rjt_par *) &header->fsf_status_qual.word[2]); break; case FSF_SQ_RETRY_IF_POSSIBLE: debug_text_event(adapter->erp_dbf, 1, "fsf_sq_retry"); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; default: ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x\n", header->fsf_status_qual.word[0]); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, (char*)header->fsf_status_qual.word, 16); } break; case FSF_ELS_COMMAND_REJECTED: ZFCP_LOG_INFO("ELS has been rejected because command filter " "prohibited sending " "(adapter: %s, port d_id: 0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id); break; case FSF_PAYLOAD_SIZE_MISMATCH: ZFCP_LOG_INFO( "ELS request size and ELS response size must be either " "both 0, or both greater than 0 " "(adapter: %s, req_buf_length=%d resp_buf_length=%d)\n", zfcp_get_busid_by_adapter(adapter), bottom->req_buf_length, bottom->resp_buf_length); break; case FSF_REQUEST_SIZE_TOO_LARGE: ZFCP_LOG_INFO( "Length of the ELS request buffer, " "specified in QTCB bottom, " "exceeds the size of the buffers " "that have been allocated for ELS request data " "(adapter: %s, req_buf_length=%d)\n", zfcp_get_busid_by_adapter(adapter), bottom->req_buf_length); break; case FSF_RESPONSE_SIZE_TOO_LARGE: ZFCP_LOG_INFO( "Length of the ELS response buffer, " "specified in QTCB bottom, " "exceeds the size of the buffers " "that have been allocated for ELS response data " "(adapter: %s, resp_buf_length=%d)\n", zfcp_get_busid_by_adapter(adapter), bottom->resp_buf_length); break; case FSF_SBAL_MISMATCH: /* should never occure, avoided in zfcp_fsf_send_els */ ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, " "resp_buf_length=%d)\n", zfcp_get_busid_by_adapter(adapter), bottom->req_buf_length, bottom->resp_buf_length); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ACCESS_DENIED: ZFCP_LOG_NORMAL("access denied, cannot send ELS command " "(adapter %s, port d_id=0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id); for (counter = 0; counter < 2; counter++) { subtable = header->fsf_status_qual.halfword[counter * 2]; rule = header->fsf_status_qual.halfword[counter * 2 + 1]; switch (subtable) { case FSF_SQ_CFDC_SUBTABLE_OS: case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: case FSF_SQ_CFDC_SUBTABLE_PORT_DID: case FSF_SQ_CFDC_SUBTABLE_LUN: ZFCP_LOG_INFO("Access denied (%s rule %d)\n", zfcp_act_subtable_type[subtable], rule); break; } } debug_text_event(adapter->erp_dbf, 1, "fsf_s_access"); if (port != NULL) zfcp_erp_port_access_denied(port); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; default: ZFCP_LOG_NORMAL( "bug: An unknown FSF Status was presented " "(adapter: %s, fsf_status=0x%08x)\n", zfcp_get_busid_by_adapter(adapter), header->fsf_status); debug_text_event(adapter->erp_dbf, 0, "fsf_sq_inval"); debug_exception(adapter->erp_dbf, 0, &header->fsf_status_qual.word[0], sizeof(u32)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; }skip_fsfstatus: send_els->status = retval; if (send_els->handler != 0) send_els->handler(send_els->handler_data); return retval;}/* * function: * * purpose: * * returns: address of initiated FSF request * NULL - request could not be initiated */intzfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action){ volatile struct qdio_buffer_element *sbale; unsigned long lock_flags; int retval = 0; /* setup new FSF request */ retval = zfcp_fsf_req_create(erp_action->adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, ZFCP_REQ_AUTO_CLEANUP, erp_action->adapter->pool.fsf_req_erp, &lock_flags, &(erp_action->fsf_req)); if (retval < 0) { ZFCP_LOG_INFO("error: Could not create exchange configuration " "data request for adapter %s.\n", zfcp_get_busid_by_adapter(erp_action->adapter)); goto out; } sbale = zfcp_qdio_sbale_req(erp_action->fsf_req, erp_action->fsf_req->sbal_curr, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; erp_action->fsf_req->erp_action = erp_action; erp_action->fsf_req->qtcb->bottom.config.feature_selection = FSF_FEATURE_CFDC | FSF_FEATURE_LUN_SHARING | FSF_FEATURE_UPDATE_ALERT; /* start QDIO request for this FSF request */ retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer); if (retval) { ZFCP_LOG_INFO ("error: Could not send exchange configuration data " "command on the adapter %s\n", zfcp_get_busid_by_adapter(erp_action->adapter)); zfcp_fsf_req_free(erp_action->fsf_req); erp_action->fsf_req = NULL; goto out; } ZFCP_LOG_DEBUG("exchange configuration data request initiated " "(adapter %s)\n", zfcp_get_busid_by_adapter(erp_action->adapter)); out: write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, lock_flags); return retval;}/** * zfcp_fsf_exchange_config_evaluate * @fsf_req: fsf_req which belongs to xchg config data request * @xchg_ok: specifies if xchg config data was incomplete or complete (0/1) * * returns: -EIO on error, 0 otherwise */static intzfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok){ struct fsf_qtcb_bottom_config *bottom; struct zfcp_adapter *adapter = fsf_req->adapter; struct Scsi_Host *shost = adapter->scsi_host; bottom = &fsf_req->qtcb->bottom.config; ZFCP_LOG_DEBUG("low/high QTCB version 0x%x/0x%x of FSF\n", bottom->low_qtcb_version, bottom->high_qtcb_version); adapter->fsf_lic_version = bottom->lic_version; adapter->adapter_features = bottom->adapter_features; adapter->connection_features = bottom->connection_features; adapter->peer_wwpn = 0; adapter->peer_wwnn = 0; adapter->peer_d_id = 0; if (xchg_ok) { fc_host_node_name(shost) = bottom->nport_serv_param.wwnn; fc_host_port_name(shost) = bottom->nport_serv_param.wwpn; fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK; fc_host_speed(shost) = bottom->fc_link_speed; fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; adapter->fc_topology = bottom->fc_topology; adapter->hydra_version = bottom->adapter_type; if (adapter->physical_wwpn == 0) adapter->physical_wwpn = fc_host_port_name(shost); if (adapter->physical_s_id == 0) adapter->physical_s_id = fc_host_port_id(shost); } else { fc_host_node_name(shost) = 0; fc_host_port_name(shost) = 0; fc_host_port_id(shost) = 0; fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; adapter->fc_topology = 0; adapter->hydra_version = 0; } if (adapter->fc_topology == FSF_TOPO_P2P) { adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK; adapter->peer_wwpn = bottom->plogi_payload.wwpn; adapter->peer_wwnn = bottom->plogi_payload.wwnn; } if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) { adapter->hardware_version = bottom->hardware_version; memcpy(fc_host_serial_number(shost), bottom->serial_number, min(FC_SERIAL_NUMBER_SIZE, 17)); EBCASC(fc_host_serial_number(shost), min(FC_SERIAL_NUMBER_SIZE, 17)); } ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n" "WWNN 0x%016Lx, " "WWPN 0x%016Lx, " "S_ID 0x%08x,\n" "adapter version 0x%x, " "LIC version 0x%x, " "FC link speed %d Gb/s\n", zfcp_get_busid_by_adapter(adapter), (wwn_t) fc_host_node_name(shost), (wwn_t) fc_host_port_name(shost), fc_hos
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -