X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fs390%2Fscsi%2Fzfcp_fsf.c;h=578b9fbe5206510c2ed5c5ed3cdda3adeedf3a69;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=44c646cca364799248af0f5d7c10da18152c9dd2;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 44c646cca..578b9fbe5 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -12,6 +12,8 @@ * Wolfgang Taphorn * Stefan Bader * Heiko Carstens + * Andreas Herrmann + * Volker Sameske * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,8 +30,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_FSF_C_REVISION "$Revision: 1.65 $" +#define ZFCP_FSF_C_REVISION "$Revision: 1.92 $" #include "zfcp_ext.h" @@ -783,12 +784,12 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) zfcp_fsf_exchange_config_data_handler(fsf_req); break; - case FSF_QTCB_EXCHANGE_PORT_DATA : + case FSF_QTCB_EXCHANGE_PORT_DATA: ZFCP_LOG_FLAGS(2, "FSF_QTCB_EXCHANGE_PORT_DATA\n"); zfcp_fsf_exchange_port_data_handler(fsf_req); break; - case FSF_QTCB_SEND_ELS : + case FSF_QTCB_SEND_ELS: ZFCP_LOG_FLAGS(2, "FSF_QTCB_SEND_ELS\n"); zfcp_fsf_send_els_handler(fsf_req); break; @@ -992,6 +993,15 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) zfcp_fsf_incoming_els(fsf_req); break; + case FSF_STATUS_READ_SENSE_DATA_AVAIL: + ZFCP_LOG_FLAGS(1, "FSF_STATUS_READ_SENSE_DATA_AVAIL\n"); + debug_text_event(adapter->erp_dbf, 3, "unsol_sense:"); + ZFCP_LOG_INFO("unsolicited sense data received (adapter %s)\n", + zfcp_get_busid_by_adapter(adapter)); + ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, (char *) status_buffer, + sizeof(struct fsf_status_read_buffer)); + break; + case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: ZFCP_LOG_FLAGS(1, "FSF_STATUS_READ_BIT_ERROR_THRESHOLD\n"); debug_text_event(adapter->erp_dbf, 3, "unsol_bit_err:"); @@ -1024,7 +1034,6 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED); - break; case FSF_STATUS_READ_CFDC_UPDATED: @@ -1032,6 +1041,7 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) debug_text_event(adapter->erp_dbf, 2, "unsol_cfdc_update:"); ZFCP_LOG_INFO("CFDC has been updated on the adapter %s\n", zfcp_get_busid_by_adapter(adapter)); + zfcp_erp_adapter_access_changed(adapter); break; case FSF_STATUS_READ_CFDC_HARDENED: @@ -1289,6 +1299,22 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) | ZFCP_STATUS_FSFREQ_RETRY; break; + case FSF_LUN_BOXED: + ZFCP_LOG_FLAGS(0, "FSF_LUN_BOXED\n"); + ZFCP_LOG_INFO( + "unit 0x%016Lx on port 0x%016Lx on adapter %s needs " + "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_reopen(unit, 0); + zfcp_cmd_dbf_event_fsf("unitbox", new_fsf_req, + &new_fsf_req->qtcb->header.fsf_status_qual, + sizeof(union fsf_status_qual)); + new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR + | ZFCP_STATUS_FSFREQ_RETRY; + break; + case FSF_ADAPTER_STATUS_AVAILABLE: /* 2 */ ZFCP_LOG_FLAGS(0, "FSF_ADAPTER_STATUS_AVAILABLE\n"); @@ -1520,20 +1546,18 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) header = &fsf_req->qtcb->header; bottom = &fsf_req->qtcb->bottom.support; - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { - /* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */ + if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) goto skip_fsfstatus; - } /* evaluate FSF status in QTCB */ switch (header->fsf_status) { - case FSF_GOOD : + case FSF_GOOD: ZFCP_LOG_FLAGS(2,"FSF_GOOD\n"); retval = 0; break; - case FSF_SERVICE_CLASS_NOT_SUPPORTED : + case FSF_SERVICE_CLASS_NOT_SUPPORTED: ZFCP_LOG_FLAGS(2, "FSF_SERVICE_CLASS_NOT_SUPPORTED\n"); if (adapter->fc_service_class <= 3) { ZFCP_LOG_INFO("error: adapter %s does not support fc " @@ -1549,21 +1573,21 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) } /* stop operation for this adapter */ debug_text_exception(adapter->erp_dbf, 0, "fsf_s_class_nsup"); - zfcp_erp_adapter_shutdown(port->adapter, 0); + zfcp_erp_adapter_shutdown(adapter, 0); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_ADAPTER_STATUS_AVAILABLE : + case FSF_ADAPTER_STATUS_AVAILABLE: ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n"); switch (header->fsf_status_qual.word[0]){ - case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE : + case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: ZFCP_LOG_FLAGS(2,"FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n"); /* 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 : + case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: ZFCP_LOG_FLAGS(2,"FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED\n"); /* ERP strategy will escalate */ debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp"); @@ -1579,9 +1603,9 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) case FSF_ACCESS_DENIED: ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n"); - ZFCP_LOG_NORMAL("Access denied, cannot send generic command " - "to port 0x%016Lx on adapter %s\n", port->wwpn, - zfcp_get_busid_by_port(port)); + 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]; @@ -1595,15 +1619,16 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) break; } } - debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access"); + 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 : + case FSF_GENERIC_COMMAND_REJECTED: ZFCP_LOG_FLAGS(2, "FSF_GENERIC_COMMAND_REJECTED\n"); - ZFCP_LOG_INFO("warning: The port 0x%016Lx on adapter %s has " - "rejected a generic services command.\n", - port->wwpn, zfcp_get_busid_by_port(port)); + 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, @@ -1612,7 +1637,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_PORT_HANDLE_NOT_VALID : + case FSF_PORT_HANDLE_NOT_VALID: ZFCP_LOG_FLAGS(2, "FSF_PORT_HANDLE_NOT_VALID\n"); ZFCP_LOG_DEBUG("Temporary port identifier 0x%x for port " "0x%016Lx on adapter %s invalid. This may " @@ -1623,22 +1648,57 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) (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(port->adapter, 0); + zfcp_erp_adapter_reopen(adapter, 0); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_PORT_BOXED : + case FSF_PORT_BOXED: ZFCP_LOG_FLAGS(2, "FSF_PORT_BOXED\n"); - ZFCP_LOG_INFO("The remote port 0x%016Lx on adapter %s " - "needs to be reopened\n", - port->wwpn, zfcp_get_busid_by_port(port)); + 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_reopen(port, 0); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; break; - default : + /* following states should never occure, all cases avoided + in zfcp_fsf_send_ct - but who knows ... */ + case FSF_PAYLOAD_SIZE_MISMATCH: + ZFCP_LOG_FLAGS(2, "FSF_PAYLOAD_SIZE_MISMATCH\n"); + 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_FLAGS(2, "FSF_REQUEST_SIZE_TOO_LARGE\n"); + 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_FLAGS(2, "FSF_RESPONSE_SIZE_TOO_LARGE\n"); + 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_FLAGS(2, "FSF_SBAL_MISMATCH\n"); + 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:"); @@ -1666,22 +1726,22 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) { volatile struct qdio_buffer_element *sbale; struct zfcp_fsf_req *fsf_req; - struct zfcp_port *port; + fc_id_t d_id; struct zfcp_adapter *adapter; unsigned long lock_flags; int bytes; int ret = 0; - port = els->port; - adapter = port->adapter; + d_id = els->d_id; + adapter = els->adapter; ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, - ZFCP_WAIT_FOR_SBAL|ZFCP_REQ_AUTO_CLEANUP, + 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), port->d_id); + zfcp_get_busid_by_adapter(adapter), d_id); goto failed_req; } @@ -1706,8 +1766,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) 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), - port->d_id); + zfcp_get_busid_by_adapter(adapter), d_id); if (bytes == 0) { ret = -ENOMEM; } else { @@ -1724,8 +1783,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) 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), - port->d_id); + zfcp_get_busid_by_adapter(adapter), d_id); if (bytes == 0) { ret = -ENOMEM; } else { @@ -1739,13 +1797,13 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) 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), port->d_id); + zfcp_get_busid_by_adapter(adapter), d_id); ret = -EOPNOTSUPP; goto failed_send; } /* settings in QTCB */ - fsf_req->qtcb->bottom.support.d_id = port->d_id; + 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.send_els = els; @@ -1756,13 +1814,13 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) ret = zfcp_fsf_req_send(fsf_req, els->timer); if (ret) { ZFCP_LOG_DEBUG("error: initiation of ELS request failed " - "(adapter %s, port 0x%016Lx)\n", - zfcp_get_busid_by_adapter(adapter), port->wwpn); + "(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 0x%016Lx)\n", - zfcp_get_busid_by_adapter(adapter), port->wwpn); + 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: @@ -1788,6 +1846,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) { struct zfcp_adapter *adapter; + fc_id_t d_id; struct zfcp_port *port; struct fsf_qtcb_header *header; struct fsf_qtcb_bottom_support *bottom; @@ -1795,9 +1854,9 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) int retval = -EINVAL; u16 subtable, rule, counter; - adapter = fsf_req->adapter; send_els = fsf_req->data.send_els; - port = send_els->port; + adapter = send_els->adapter; + d_id = send_els->d_id; header = &fsf_req->qtcb->header; bottom = &fsf_req->qtcb->bottom.support; @@ -1816,35 +1875,38 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) if (adapter->fc_service_class <= 3) { ZFCP_LOG_INFO("error: adapter %s does " "not support fibrechannel class %d.\n", - zfcp_get_busid_by_port(port), + 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_port(port), + 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(port->adapter, 0); + zfcp_erp_adapter_shutdown(adapter, 0); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: ZFCP_LOG_FLAGS(2, "FSF_ADAPTER_STATUS_AVAILABLE\n"); switch (header->fsf_status_qual.word[0]){ - case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: { + case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: ZFCP_LOG_FLAGS(2,"FSF_SQ_INVOKE_LINK_TEST_PROCEDURE\n"); debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ltest"); - if (send_els->ls_code != ZFCP_LS_ADISC) - zfcp_test_link(port); + if (send_els->ls_code != ZFCP_LS_ADISC) { + read_lock(&zfcp_data.config_lock); + port = zfcp_get_port_by_did(adapter, d_id); + if (port) + zfcp_test_link(port); + read_unlock(&zfcp_data.config_lock); + } fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - } case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: ZFCP_LOG_FLAGS(2,"FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED\n"); - /* ERP strategy will escalate */ debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp"); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; retval = @@ -1869,8 +1931,8 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) ZFCP_LOG_FLAGS(2, "FSF_ELS_COMMAND_REJECTED\n"); ZFCP_LOG_INFO("ELS has been rejected because command filter " "prohibited sending " - "(adapter: %s, wwpn=0x%016Lx)\n", - zfcp_get_busid_by_port(port), port->wwpn); + "(adapter: %s, port d_id: 0x%08x)\n", + zfcp_get_busid_by_adapter(adapter), d_id); break; @@ -1880,7 +1942,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) "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_port(port), + zfcp_get_busid_by_adapter(adapter), bottom->req_buf_length, bottom->resp_buf_length); break; @@ -1893,7 +1955,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) "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_port(port), + zfcp_get_busid_by_adapter(adapter), bottom->req_buf_length); break; @@ -1905,15 +1967,25 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) "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_port(port), + 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_FLAGS(2, "FSF_SBAL_MISMATCH\n"); + 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_FLAGS(2, "FSF_ACCESS_DENIED\n"); - ZFCP_LOG_NORMAL("Access denied, cannot send ELS " - "(adapter: %s, wwpn=0x%016Lx)\n", - zfcp_get_busid_by_port(port), port->wwpn); + 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]; @@ -1928,6 +2000,11 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) } } debug_text_event(adapter->erp_dbf, 1, "fsf_s_access"); + read_lock(&zfcp_data.config_lock); + port = zfcp_get_port_by_did(adapter, d_id); + if (port != NULL) + zfcp_erp_port_access_denied(port); + read_unlock(&zfcp_data.config_lock); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -1935,7 +2012,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) ZFCP_LOG_NORMAL( "bug: An unknown FSF Status was presented " "(adapter: %s, fsf_status=0x%08x)\n", - zfcp_get_busid_by_port(port), + 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, @@ -1988,7 +2065,7 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) erp_action->fsf_req->erp_action = erp_action; erp_action->fsf_req->qtcb->bottom.config.feature_selection = - FSF_FEATURE_CFDC; + (FSF_FEATURE_CFDC | FSF_FEATURE_LUN_SHARING); /* start QDIO request for this FSF request */ retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer); @@ -2287,7 +2364,7 @@ zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req) return; switch (fsf_req->qtcb->header.fsf_status) { - case FSF_GOOD : + case FSF_GOOD: ZFCP_LOG_FLAGS(2,"FSF_GOOD\n"); bottom = &fsf_req->qtcb->bottom.port; memcpy(data, bottom, sizeof(*data)); @@ -2406,7 +2483,7 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n"); ZFCP_LOG_NORMAL("Access denied, cannot open port 0x%016Lx " "on adapter %s\n", - port->wwpn, zfcp_get_busid_by_port(port)); + port->wwpn, zfcp_get_busid_by_port(port)); for (counter = 0; counter < 2; counter++) { subtable = header->fsf_status_qual.halfword[counter * 2]; rule = header->fsf_status_qual.halfword[counter * 2 + 1]; @@ -2421,7 +2498,7 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) } } debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access"); - zfcp_erp_port_failed(port); + zfcp_erp_port_access_denied(port); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -2537,6 +2614,16 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) } break; + case FSF_UNKNOWN_OP_SUBTYPE: + /* should never occure, subtype not set in zfcp_fsf_open_port */ + ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_OP_SUBTYPE\n"); + ZFCP_LOG_INFO("unknown operation subtype (adapter: %s, " + "op_subtype=0x%x)\n", + zfcp_get_busid_by_port(port), + fsf_req->qtcb->bottom.support.operation_subtype); + fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + default: ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " "(debug info 0x%x)\n", @@ -2803,9 +2890,8 @@ zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) case FSF_ACCESS_DENIED: ZFCP_LOG_FLAGS(2, "FSF_ACCESS_DENIED\n"); ZFCP_LOG_NORMAL("Access denied, cannot close " - "physical port 0x%016Lx on " - "adapter %s\n", port->wwpn, - zfcp_get_busid_by_port(port)); + "physical port 0x%016Lx on adapter %s\n", + port->wwpn, zfcp_get_busid_by_port(port)); for (counter = 0; counter < 2; counter++) { subtable = header->fsf_status_qual.halfword[counter * 2]; rule = header->fsf_status_qual.halfword[counter * 2 + 1]; @@ -2820,6 +2906,7 @@ zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) } } debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access"); + zfcp_erp_port_access_denied(port); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -2941,6 +3028,8 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) erp_action->port->handle; erp_action->fsf_req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun; + erp_action->fsf_req->qtcb->bottom.support.option = + FSF_OPEN_LUN_SUPPRESS_BOXING; atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status); erp_action->fsf_req->data.open_unit.unit = erp_action->unit; erp_action->fsf_req->erp_action = erp_action; @@ -2984,18 +3073,31 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) struct zfcp_unit *unit; struct fsf_qtcb_header *header; struct fsf_qtcb_bottom_support *bottom; + struct fsf_queue_designator *queue_designator; u16 subtable, rule, counter; + u32 allowed, exclusive, readwrite; - adapter = fsf_req->adapter; unit = fsf_req->data.open_unit.unit; - header = &fsf_req->qtcb->header; - bottom = &fsf_req->qtcb->bottom.support; if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { /* don't change unit status in our bookkeeping */ goto skip_fsfstatus; } + adapter = fsf_req->adapter; + header = &fsf_req->qtcb->header; + bottom = &fsf_req->qtcb->bottom.support; + queue_designator = &header->fsf_status_qual.fsf_queue_designator; + + allowed = bottom->lun_access_info & FSF_UNIT_ACCESS_OPEN_LUN_ALLOWED; + exclusive = bottom->lun_access_info & FSF_UNIT_ACCESS_EXCLUSIVE; + readwrite = bottom->lun_access_info & FSF_UNIT_ACCESS_OUTBOUND_TRANSFER; + + atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | + ZFCP_STATUS_UNIT_SHARED | + ZFCP_STATUS_UNIT_READONLY, + &unit->status); + /* evaluate FSF status in QTCB */ switch (header->fsf_status) { @@ -3046,7 +3148,9 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) } } debug_text_event(adapter->erp_dbf, 1, "fsf_s_access"); - zfcp_erp_unit_failed(unit); + zfcp_erp_unit_access_denied(unit); + atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); + atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -3061,17 +3165,18 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) ZFCP_STATUS_FSFREQ_RETRY; break; - case FSF_LUN_SHARING_VIOLATION : + case FSF_LUN_SHARING_VIOLATION: ZFCP_LOG_FLAGS(2, "FSF_LUN_SHARING_VIOLATION\n"); if (header->fsf_status_qual.word[0] != 0) { ZFCP_LOG_NORMAL("FCP-LUN 0x%Lx at the remote port " "with WWPN 0x%Lx " "connected to the adapter %s " - "is already in use in LPAR%d\n", + "is already in use in LPAR%d, CSS%d\n", unit->fcp_lun, unit->port->wwpn, zfcp_get_busid_by_unit(unit), - header->fsf_status_qual.fsf_queue_designator.hla); + queue_designator->hla, + queue_designator->cssid); } else { subtable = header->fsf_status_qual.halfword[4]; rule = header->fsf_status_qual.halfword[5]; @@ -3098,7 +3203,9 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) sizeof (union fsf_status_qual)); debug_text_event(adapter->erp_dbf, 2, "fsf_s_l_sh_vio"); - zfcp_erp_unit_failed(unit); + zfcp_erp_unit_access_denied(unit); + atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); + atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -3172,6 +3279,38 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) unit->handle); /* mark unit as open */ atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); + + if (adapter->supported_features & FSF_FEATURE_LUN_SHARING){ + if (!exclusive) + atomic_set_mask(ZFCP_STATUS_UNIT_SHARED, + &unit->status); + + if (!readwrite) { + atomic_set_mask(ZFCP_STATUS_UNIT_READONLY, + &unit->status); + ZFCP_LOG_NORMAL("read-only access for unit " + "(adapter %s, wwpn=0x%016Lx, " + "fcp_lun=0x%016Lx)\n", + zfcp_get_busid_by_unit(unit), + unit->port->wwpn, + unit->fcp_lun); + } + + if (exclusive && !readwrite) { + ZFCP_LOG_NORMAL("exclusive access of read-only " + "unit not supported\n"); + zfcp_erp_unit_failed(unit); + fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_erp_unit_shutdown(unit, 0); + } else if (!exclusive && readwrite) { + ZFCP_LOG_NORMAL("shared access of read-write " + "unit not supported\n"); + zfcp_erp_unit_failed(unit); + fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_erp_unit_shutdown(unit, 0); + } + } + retval = 0; break; @@ -3185,7 +3324,7 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) break; } - skip_fsfstatus: + skip_fsfstatus: atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status); return retval; } @@ -3421,6 +3560,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, unsigned long lock_flags; int real_bytes = 0; int retval = 0; + int mask; /* setup new FSF request */ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, @@ -3505,14 +3645,14 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, /* set FCP_LUN in FCP_CMND IU in QTCB */ fcp_cmnd_iu->fcp_lun = unit->fcp_lun; + mask = ZFCP_STATUS_UNIT_READONLY | ZFCP_STATUS_UNIT_SHARED; + /* set task attributes in FCP_CMND IU in QTCB */ - if (likely(scsi_cmnd->device->simple_tags)) { + if (likely((scsi_cmnd->device->simple_tags) || + (atomic_test_mask(mask, &unit->status)))) fcp_cmnd_iu->task_attribute = SIMPLE_Q; - ZFCP_LOG_TRACE("setting SIMPLE_Q task attribute\n"); - } else { + else fcp_cmnd_iu->task_attribute = UNTAGGED; - ZFCP_LOG_TRACE("setting UNTAGGED task attribute\n"); - } /* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */ if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) { @@ -3847,6 +3987,7 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) } } debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_access"); + zfcp_erp_unit_access_denied(unit); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -3906,16 +4047,15 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) case FSF_LUN_BOXED: ZFCP_LOG_FLAGS(0, "FSF_LUN_BOXED\n"); - ZFCP_LOG_NORMAL( - "unit 0x%016Lx on port 0x%016Lx on adapter %s needs " - "to be reopened\n", - unit->fcp_lun, unit->port->wwpn, - zfcp_get_busid_by_unit(unit)); + ZFCP_LOG_NORMAL("unit needs to be reopened (adapter %s, " + "wwpn=0x%016Lx, fcp_lun=0x%016Lx)\n", + zfcp_get_busid_by_unit(unit), + unit->port->wwpn, unit->fcp_lun); debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_lboxed"); zfcp_erp_unit_reopen(unit, 0); zfcp_cmd_dbf_event_fsf("unitbox", fsf_req, - &header->fsf_status_qual, - sizeof(union fsf_status_qual)); + &header->fsf_status_qual, + sizeof(union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; break; @@ -4182,22 +4322,19 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) /* check for underrun */ if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) { - ZFCP_LOG_DEBUG("A data underrun was detected for a command. " - "unit 0x%016Lx, port 0x%016Lx, adapter %s. " - "The response data length is " - "%d, the original length was %d.\n", - unit->fcp_lun, - unit->port->wwpn, - zfcp_get_busid_by_unit(unit), - fcp_rsp_iu->fcp_resid, - (int) zfcp_get_fcp_dl(fcp_cmnd_iu)); - /* - * It may not have been possible to send all data and the - * underrun on send may already be in scpnt->resid, so it's add - * not equals in the below statement. - */ - scpnt->resid += fcp_rsp_iu->fcp_resid; - ZFCP_LOG_TRACE("scpnt->resid=0x%x\n", scpnt->resid); + ZFCP_LOG_INFO("A data underrun was detected for a command. " + "unit 0x%016Lx, port 0x%016Lx, adapter %s. " + "The response data length is " + "%d, the original length was %d.\n", + unit->fcp_lun, + unit->port->wwpn, + zfcp_get_busid_by_unit(unit), + fcp_rsp_iu->fcp_resid, + (int) zfcp_get_fcp_dl(fcp_cmnd_iu)); + + scpnt->resid = fcp_rsp_iu->fcp_resid; + if (scpnt->request_bufflen - scpnt->resid < scpnt->underflow) + scpnt->result |= DID_ERROR << 16; } skip_fsfstatus: @@ -4306,7 +4443,7 @@ zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req) * -EOPNOTSUPP - The FCP adapter does not have Control File support * -EINVAL - Invalid direction specified * -ENOMEM - Insufficient memory - * -EPERM - Cannot create FSF request or or place it in QDIO queue + * -EPERM - Cannot create FSF request or place it in QDIO queue */ int zfcp_fsf_control_file(struct zfcp_adapter *adapter, @@ -4318,17 +4455,17 @@ zfcp_fsf_control_file(struct zfcp_adapter *adapter, struct zfcp_fsf_req *fsf_req; struct fsf_qtcb_bottom_support *bottom; volatile struct qdio_buffer_element *sbale; + struct timer_list *timer; unsigned long lock_flags; int req_flags = 0; int direction; int retval = 0; if (!(adapter->supported_features & FSF_FEATURE_CFDC)) { - ZFCP_LOG_INFO( - "Adapter %s does not support control file\n", - zfcp_get_busid_by_adapter(adapter)); + ZFCP_LOG_INFO("cfdc not supported (adapter %s)\n", + zfcp_get_busid_by_adapter(adapter)); retval = -EOPNOTSUPP; - goto no_cfdc_support; + goto out; } switch (fsf_command) { @@ -4346,9 +4483,16 @@ zfcp_fsf_control_file(struct zfcp_adapter *adapter, default: ZFCP_LOG_INFO("Invalid FSF command code 0x%08x\n", fsf_command); - goto invalid_command; + retval = -EINVAL; + goto out; } + timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); + if (!timer) { + retval = -ENOMEM; + goto out; + } + retval = zfcp_fsf_req_create(adapter, fsf_command, req_flags, NULL, &lock_flags, &fsf_req); if (retval < 0) { @@ -4356,7 +4500,7 @@ zfcp_fsf_control_file(struct zfcp_adapter *adapter, "adapter %s\n", zfcp_get_busid_by_adapter(adapter)); retval = -EPERM; - goto out; + goto unlock_queue_lock; } sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); @@ -4378,40 +4522,46 @@ zfcp_fsf_control_file(struct zfcp_adapter *adapter, "SBALS for an FSF request to the adapter %s\n", zfcp_get_busid_by_adapter(adapter)); retval = -ENOMEM; - goto sbals_failed; + goto free_fsf_req; } - } else { + } else sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - } - retval = zfcp_fsf_req_send(fsf_req, NULL); + init_timer(timer); + timer->function = zfcp_fsf_request_timeout_handler; + timer->data = (unsigned long) adapter; + timer->expires = ZFCP_FSF_REQUEST_TIMEOUT; + + retval = zfcp_fsf_req_send(fsf_req, timer); if (retval < 0) { - ZFCP_LOG_INFO( - "error: Could not send FSF request to the adapter %s\n", - zfcp_get_busid_by_adapter(adapter)); + ZFCP_LOG_INFO("initiation of cfdc up/download failed" + "(adapter %s)\n", + zfcp_get_busid_by_adapter(adapter)); retval = -EPERM; - goto queue_failed; + goto free_fsf_req; } + write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); - ZFCP_LOG_NORMAL( - "Control file %s FSF request has been sent to the adapter %s\n", - fsf_command == FSF_QTCB_DOWNLOAD_CONTROL_FILE ? + ZFCP_LOG_NORMAL("Control file %s FSF request has been sent to the " + "adapter %s\n", + fsf_command == FSF_QTCB_DOWNLOAD_CONTROL_FILE ? "download" : "upload", - zfcp_get_busid_by_adapter(adapter)); + zfcp_get_busid_by_adapter(adapter)); - *fsf_req_ptr = fsf_req; + wait_event(fsf_req->completion_wq, + fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); - goto out; + *fsf_req_ptr = fsf_req; + del_timer_sync(timer); + goto free_timer; -sbals_failed: -queue_failed: + free_fsf_req: zfcp_fsf_req_free(fsf_req); - -out: + unlock_queue_lock: write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); - -invalid_command: -no_cfdc_support: + free_timer: + kfree(timer); + out: return retval; } @@ -4550,11 +4700,10 @@ zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req) case FSF_UNKNOWN_OP_SUBTYPE: ZFCP_LOG_FLAGS(2, "FSF_UNKNOWN_OP_SUBTYPE\n"); - ZFCP_LOG_NORMAL( - "Invalid operation subtype 0x%x has been specified " - "in QTCB bottom sent to the adapter %s\n", - bottom->operation_subtype, - zfcp_get_busid_by_adapter(adapter)); + ZFCP_LOG_NORMAL("unknown operation subtype (adapter: %s, " + "op_subtype=0x%x)\n", + zfcp_get_busid_by_adapter(adapter), + bottom->operation_subtype); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; retval = -EINVAL; break; @@ -4682,6 +4831,8 @@ zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags, ZFCP_SBAL_TIMEOUT); if (ret < 0) return ret; + if (!ret) + return -EIO; } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1)) return -EIO; @@ -4871,7 +5022,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) * timer might be expired (absolutely unlikely) */ if (timer) - del_timer_sync(timer); + del_timer(timer); write_lock_irqsave(&adapter->fsf_req_list_lock, flags); list_del(&fsf_req->list); write_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);