📄 zfcp_fsf.c
字号:
"to be reopened\n", unit->fcp_lun, unit->port->wwpn, zfcp_get_busid_by_unit(unit)); debug_text_event(new_fsf_req->adapter->erp_dbf, 1, "fsf_s_lboxed"); zfcp_erp_unit_boxed(unit); new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; break; case FSF_ADAPTER_STATUS_AVAILABLE: switch (new_fsf_req->qtcb->header.fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: debug_text_event(new_fsf_req->adapter->erp_dbf, 1, "fsf_sq_ltest"); zfcp_test_link(unit->port); new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: /* SCSI stack will escalate */ debug_text_event(new_fsf_req->adapter->erp_dbf, 1, "fsf_sq_ulp"); new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; default: ZFCP_LOG_NORMAL ("bug: Wrong status qualifier 0x%x arrived.\n", new_fsf_req->qtcb->header.fsf_status_qual.word[0]); debug_text_event(new_fsf_req->adapter->erp_dbf, 0, "fsf_sq_inval:"); debug_exception(new_fsf_req->adapter->erp_dbf, 0, &new_fsf_req->qtcb->header. fsf_status_qual.word[0], sizeof (u32)); break; } break; case FSF_GOOD: retval = 0; new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED; break; default: ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " "(debug info 0x%x)\n", new_fsf_req->qtcb->header.fsf_status); debug_text_event(new_fsf_req->adapter->erp_dbf, 0, "fsf_s_inval:"); debug_exception(new_fsf_req->adapter->erp_dbf, 0, &new_fsf_req->qtcb->header.fsf_status, sizeof (u32)); break; } skip_fsfstatus: return retval;}/** * zfcp_use_one_sbal - checks whether req buffer and resp bother each fit into * one SBALE * Two scatter-gather lists are passed, one for the reqeust and one for the * response. */static inline intzfcp_use_one_sbal(struct scatterlist *req, int req_count, struct scatterlist *resp, int resp_count){ return ((req_count == 1) && (resp_count == 1) && (((unsigned long) zfcp_sg_to_address(&req[0]) & PAGE_MASK) == ((unsigned long) (zfcp_sg_to_address(&req[0]) + req[0].length - 1) & PAGE_MASK)) && (((unsigned long) zfcp_sg_to_address(&resp[0]) & PAGE_MASK) == ((unsigned long) (zfcp_sg_to_address(&resp[0]) + resp[0].length - 1) & PAGE_MASK)));}/** * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS) * @ct: pointer to struct zfcp_send_ct which conatins all needed data for * the request * @pool: pointer to memory pool, if non-null this pool is used to allocate * a struct zfcp_fsf_req * @erp_action: pointer to erp_action, if non-null the Generic Service request * is sent within error recovery */intzfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, struct zfcp_erp_action *erp_action){ volatile struct qdio_buffer_element *sbale; struct zfcp_port *port; struct zfcp_adapter *adapter; struct zfcp_fsf_req *fsf_req; unsigned long lock_flags; int bytes; int ret = 0; port = ct->port; adapter = port->adapter; ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC, ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, pool, &lock_flags, &fsf_req); if (ret < 0) { ZFCP_LOG_INFO("error: Could not create CT request (FC-GS) for " "adapter: %s\n", zfcp_get_busid_by_adapter(adapter)); goto failed_req; } if (erp_action != NULL) { erp_action->fsf_req = fsf_req; fsf_req->erp_action = erp_action; } sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); if (zfcp_use_one_sbal(ct->req, ct->req_count, ct->resp, ct->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(&ct->req[0]); sbale[2].length = ct->req[0].length; sbale[3].addr = zfcp_sg_to_address(&ct->resp[0]); sbale[3].length = ct->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, ct->req, ct->req_count, ZFCP_MAX_SBALS_PER_CT_REQ); if (bytes <= 0) { ZFCP_LOG_INFO("error: creation of CT request failed " "on adapter %s\n", zfcp_get_busid_by_adapter(adapter)); 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, ct->resp, ct->resp_count, ZFCP_MAX_SBALS_PER_CT_REQ); if (bytes <= 0) { ZFCP_LOG_INFO("error: creation of CT request failed " "on adapter %s\n", zfcp_get_busid_by_adapter(adapter)); if (bytes == 0) ret = -ENOMEM; else ret = bytes; goto failed_send; } fsf_req->qtcb->bottom.support.resp_buf_length = bytes; } else { /* reject send generic request */ ZFCP_LOG_INFO( "error: microcode does not support chained SBALs," "CT request too big (adapter %s)\n", zfcp_get_busid_by_adapter(adapter)); ret = -EOPNOTSUPP; goto failed_send; } /* settings in QTCB */ fsf_req->qtcb->header.port_handle = port->handle; fsf_req->qtcb->bottom.support.service_class = adapter->fc_service_class; fsf_req->qtcb->bottom.support.timeout = ct->timeout; fsf_req->data = (unsigned long) ct; zfcp_san_dbf_event_ct_request(fsf_req); /* start QDIO request for this FSF request */ ret = zfcp_fsf_req_send(fsf_req, ct->timer); if (ret) { ZFCP_LOG_DEBUG("error: initiation of CT request failed " "(adapter %s, port 0x%016Lx)\n", zfcp_get_busid_by_adapter(adapter), port->wwpn); goto failed_send; } ZFCP_LOG_DEBUG("CT request initiated (adapter %s, port 0x%016Lx)\n", zfcp_get_busid_by_adapter(adapter), port->wwpn); goto out; failed_send: zfcp_fsf_req_free(fsf_req); if (erp_action != NULL) { erp_action->fsf_req = NULL; } failed_req: out: write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); return ret;}/** * zfcp_fsf_send_ct_handler - handler for Generic Service requests * @fsf_req: pointer to struct zfcp_fsf_req * * Data specific for the Generic Service request is passed using * fsf_req->data. There we find the pointer to struct zfcp_send_ct. * Usually a specific handler for the CT request is called which is * found in this structure. */static intzfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req){ struct zfcp_port *port; struct zfcp_adapter *adapter; struct zfcp_send_ct *send_ct; struct fsf_qtcb_header *header; struct fsf_qtcb_bottom_support *bottom; int retval = -EINVAL; u16 subtable, rule, counter; adapter = fsf_req->adapter; send_ct = (struct zfcp_send_ct *) fsf_req->data; port = send_ct->port; header = &fsf_req->qtcb->header; bottom = &fsf_req->qtcb->bottom.support; if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) goto skip_fsfstatus; /* evaluate FSF status in QTCB */ switch (header->fsf_status) { case FSF_GOOD: zfcp_san_dbf_event_ct_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 fc " "class %d.\n", zfcp_get_busid_by_port(port), adapter->fc_service_class); } else { ZFCP_LOG_INFO("bug: The fibre channel class at the " "adapter %s is invalid. " "(debug info %d)\n", zfcp_get_busid_by_port(port), 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: /* reopening link to port */ debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest"); zfcp_test_link(port); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: /* ERP strategy will escalate */ debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp"); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; default: ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x " "arrived.\n", header->fsf_status_qual.word[0]); break; } break; case FSF_ACCESS_DENIED: ZFCP_LOG_NORMAL("access denied, cannot send generic service " "command (adapter %s, port d_id=0x%08x)\n", zfcp_get_busid_by_port(port), port->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"); zfcp_erp_port_access_denied(port); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_GENERIC_COMMAND_REJECTED: ZFCP_LOG_INFO("generic service command rejected " "(adapter %s, port d_id=0x%08x)\n", zfcp_get_busid_by_port(port), port->d_id); ZFCP_LOG_INFO("status qualifier:\n"); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, (char *) &header->fsf_status_qual, sizeof (union fsf_status_qual)); debug_text_event(adapter->erp_dbf, 1, "fsf_s_gcom_rej"); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_HANDLE_NOT_VALID: ZFCP_LOG_DEBUG("Temporary port identifier 0x%x for port " "0x%016Lx on adapter %s invalid. This may " "happen occasionally.\n", port->handle, port->wwpn, zfcp_get_busid_by_port(port)); ZFCP_LOG_INFO("status qualifier:\n"); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, (char *) &header->fsf_status_qual, sizeof (union fsf_status_qual)); debug_text_event(adapter->erp_dbf, 1, "fsf_s_phandle_nv"); zfcp_erp_adapter_reopen(adapter, 0); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_BOXED: ZFCP_LOG_INFO("port needs to be reopened " "(adapter %s, port d_id=0x%08x)\n", zfcp_get_busid_by_port(port), port->d_id); debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed"); zfcp_erp_port_boxed(port); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; break; /* following states should never occure, all cases avoided in zfcp_fsf_send_ct - but who knows ... */ case FSF_PAYLOAD_SIZE_MISMATCH: ZFCP_LOG_INFO("payload size 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_REQUEST_SIZE_TOO_LARGE: ZFCP_LOG_INFO("request size too large (adapter: %s, " "req_buf_length=%d)\n", zfcp_get_busid_by_adapter(adapter), bottom->req_buf_length); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_RESPONSE_SIZE_TOO_LARGE: ZFCP_LOG_INFO("response size too large (adapter: %s, " "resp_buf_length=%d)\n", zfcp_get_busid_by_adapter(adapter), bottom->resp_buf_length); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SBAL_MISMATCH: 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; default: ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " "(debug info 0x%x)\n", 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)); break; }skip_fsfstatus: send_ct->status = retval; if (send_ct->handler != NULL) send_ct->handler(send_ct->handler_data); return retval;}/** * zfcp_fsf_send_els - initiate an ELS command (FC-FS) * @els: pointer to struct zfcp_send_els which contains all needed data for * the command. */intzfcp_fsf_send_els(struct zfcp_send_els *els){ volatile struct qdio_buffer_element *sbale; struct zfcp_fsf_req *fsf_req; u32 d_id; struct zfcp_adapter *adapter; unsigned long lock_flags; int bytes; int ret = 0; d_id = els->d_id; adapter = els->adapter;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -