diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_fsf.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 293 |
1 files changed, 197 insertions, 96 deletions
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 99299976e891..ff866ebd44ac 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -80,10 +80,10 @@ static const char zfcp_act_subtable_type[5][8] = { /* * function: zfcp_fsf_req_alloc * - * purpose: Obtains an fsf_req and potentially a qtcb (for all but + * purpose: Obtains an fsf_req and potentially a qtcb (for all but * unsolicited requests) via helper functions * Does some initial fsf request set-up. - * + * * returns: pointer to allocated fsf_req if successfull * NULL otherwise * @@ -192,7 +192,7 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) * returns: 0 - success * !0 - failure * - * context: + * context: */ int zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) @@ -214,8 +214,8 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) } /* - * fsf_req may be deleted due to waking up functions, so - * cleanup is saved here and used later + * fsf_req may be deleted due to waking up functions, so + * cleanup is saved here and used later */ if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP)) cleanup = 1; @@ -259,9 +259,9 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) * and initiates appropriate actions * (usually calling FSF command specific handlers) * - * returns: + * returns: * - * context: + * context: * * locks: */ @@ -638,7 +638,7 @@ zfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter, * * purpose: calls the appropriate command specific handler * - * returns: + * returns: */ static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) @@ -854,7 +854,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req) * * purpose: is called for finished Open Port command * - * returns: + * returns: */ static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) @@ -1088,7 +1088,7 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) * returns: address of initiated FSF request * NULL - request could not be initiated * - * FIXME(design): should be watched by a timeout !!! + * FIXME(design): should be watched by a timeout !!! * FIXME(design) shouldn't this be modified to return an int * also...don't know how though */ @@ -1157,7 +1157,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id, * * purpose: is called for finished Abort FCP Command request * - * returns: + * returns: */ static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) @@ -1941,25 +1941,28 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) { volatile struct qdio_buffer_element *sbale; struct zfcp_fsf_req *fsf_req; + struct zfcp_adapter *adapter = erp_action->adapter; unsigned long lock_flags; - int retval = 0; + int retval; /* setup new FSF request */ - retval = zfcp_fsf_req_create(erp_action->adapter, + retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, ZFCP_REQ_AUTO_CLEANUP, - erp_action->adapter->pool.fsf_req_erp, + adapter->pool.fsf_req_erp, &lock_flags, &fsf_req); - if (retval < 0) { + if (retval) { 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; + zfcp_get_busid_by_adapter(adapter)); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, + lock_flags); + return retval; } sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; + sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; fsf_req->qtcb->bottom.config.feature_selection = FSF_FEATURE_CFDC | @@ -1971,23 +1974,71 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) zfcp_erp_start_timer(fsf_req); retval = zfcp_fsf_req_send(fsf_req); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, + lock_flags); 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_LOG_INFO("error: Could not send exchange configuration " + "data command on the adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); zfcp_fsf_req_free(fsf_req); erp_action->fsf_req = NULL; - goto out; } + else + ZFCP_LOG_DEBUG("exchange configuration data request initiated " + "(adapter %s)\n", + zfcp_get_busid_by_adapter(adapter)); - ZFCP_LOG_DEBUG("exchange configuration data request initiated " - "(adapter %s)\n", - zfcp_get_busid_by_adapter(erp_action->adapter)); + return retval; +} - out: - write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, +int +zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, + struct fsf_qtcb_bottom_config *data) +{ + volatile struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *fsf_req; + unsigned long lock_flags; + int retval; + + /* setup new FSF request */ + retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, + 0, NULL, &lock_flags, &fsf_req); + if (retval) { + ZFCP_LOG_INFO("error: Could not create exchange configuration " + "data request for adapter %s.\n", + zfcp_get_busid_by_adapter(adapter)); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, + lock_flags); + return retval; + } + + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; + sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + + fsf_req->qtcb->bottom.config.feature_selection = + FSF_FEATURE_CFDC | + FSF_FEATURE_LUN_SHARING | + FSF_FEATURE_NOTIFICATION_LOST | + FSF_FEATURE_UPDATE_ALERT; + + if (data) + fsf_req->data = (unsigned long) data; + + zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); + retval = zfcp_fsf_req_send(fsf_req); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); + if (retval) + ZFCP_LOG_INFO("error: Could not send exchange configuration " + "data command on the adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + else + wait_event(fsf_req->completion_wq, + fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + + zfcp_fsf_req_free(fsf_req); + return retval; } @@ -2016,11 +2067,17 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) adapter->peer_d_id = 0; if (xchg_ok) { + + if (fsf_req->data) + memcpy((struct fsf_qtcb_bottom_config *) fsf_req->data, + bottom, sizeof (struct fsf_qtcb_bottom_config)); + 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; + fc_host_supported_classes(shost) = + FC_COS_CLASS2 | FC_COS_CLASS3; adapter->hydra_version = bottom->adapter_type; if (fc_host_permanent_port_name(shost) == -1) fc_host_permanent_port_name(shost) = @@ -2053,7 +2110,8 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) min(FC_SERIAL_NUMBER_SIZE, 17)); } - ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n" + ZFCP_LOG_NORMAL("The adapter %s reported the following " + "characteristics:\n" "WWNN 0x%016Lx, " "WWPN 0x%016Lx, " "S_ID 0x%06x,\n" @@ -2090,7 +2148,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) return 0; } -/* +/** * function: zfcp_fsf_exchange_config_data_handler * * purpose: is called for finished Exchange Configuration Data command @@ -2125,7 +2183,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) adapter->peer_wwpn, adapter->peer_d_id); debug_text_event(fsf_req->adapter->erp_dbf, 0, - "top-p-to-p"); + "top-p-to-p"); break; case FC_PORTTYPE_NLPORT: ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel " @@ -2138,8 +2196,8 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) return -EIO; case FC_PORTTYPE_NPORT: ZFCP_LOG_NORMAL("Switched fabric fibrechannel " - "network detected at adapter %s.\n", - zfcp_get_busid_by_adapter(adapter)); + "network detected at adapter %s.\n", + zfcp_get_busid_by_adapter(adapter)); break; default: ZFCP_LOG_NORMAL("bug: The fibrechannel topology " @@ -2179,7 +2237,8 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0)) return -EIO; - atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); + atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, + &adapter->status); zfcp_fsf_link_down_info_eval(adapter, &qtcb->header.fsf_status_qual.link_down_info); @@ -2187,7 +2246,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) default: debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng"); debug_event(fsf_req->adapter->erp_dbf, 0, - &fsf_req->qtcb->header.fsf_status, sizeof (u32)); + &fsf_req->qtcb->header.fsf_status, sizeof(u32)); zfcp_erp_adapter_shutdown(adapter, 0); return -EIO; } @@ -2197,74 +2256,118 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) /** * zfcp_fsf_exchange_port_data - request information about local port * @erp_action: ERP action for the adapter for which port data is requested - * @adapter: for which port data is requested - * @data: response to exchange port data request */ int -zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action, - struct zfcp_adapter *adapter, - struct fsf_qtcb_bottom_port *data) +zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) { volatile struct qdio_buffer_element *sbale; - struct zfcp_fsf_req *fsf_req; + struct zfcp_fsf_req *fsf_req; + struct zfcp_adapter *adapter = erp_action->adapter; unsigned long lock_flags; - int retval = 0; + int retval; if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) { ZFCP_LOG_INFO("error: exchange port data " - "command not supported by adapter %s\n", + "command not supported by adapter %s\n", zfcp_get_busid_by_adapter(adapter)); - return -EOPNOTSUPP; - } + return -EOPNOTSUPP; + } /* setup new FSF request */ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, - erp_action ? ZFCP_REQ_AUTO_CLEANUP : 0, - NULL, &lock_flags, &fsf_req); - if (retval < 0) { + ZFCP_REQ_AUTO_CLEANUP, + adapter->pool.fsf_req_erp, + &lock_flags, &fsf_req); + if (retval) { ZFCP_LOG_INFO("error: Out of resources. Could not create an " - "exchange port data request for" - "the adapter %s.\n", + "exchange port data request for" + "the adapter %s.\n", zfcp_get_busid_by_adapter(adapter)); write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); return retval; } - if (data) - fsf_req->data = (unsigned long) data; - sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; + sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - if (erp_action) { - erp_action->fsf_req = fsf_req; - fsf_req->erp_action = erp_action; - zfcp_erp_start_timer(fsf_req); - } else - zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); + erp_action->fsf_req = fsf_req; + fsf_req->erp_action = erp_action; + zfcp_erp_start_timer(fsf_req); retval = zfcp_fsf_req_send(fsf_req); + write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); + if (retval) { ZFCP_LOG_INFO("error: Could not send an exchange port data " - "command on the adapter %s\n", + "command on the adapter %s\n", zfcp_get_busid_by_adapter(adapter)); zfcp_fsf_req_free(fsf_req); - if (erp_action) - erp_action->fsf_req = NULL; + erp_action->fsf_req = NULL; + } + else + ZFCP_LOG_DEBUG("exchange port data request initiated " + "(adapter %s)\n", + zfcp_get_busid_by_adapter(adapter)); + return retval; +} + + +/** + * zfcp_fsf_exchange_port_data_sync - request information about local port + * and wait until information is ready + */ +int +zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, + struct fsf_qtcb_bottom_port *data) +{ + volatile struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *fsf_req; + unsigned long lock_flags; + int retval; + + if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) { + ZFCP_LOG_INFO("error: exchange port data " + "command not supported by adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + return -EOPNOTSUPP; + } + + /* setup new FSF request */ + retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, + 0, NULL, &lock_flags, &fsf_req); + if (retval) { + ZFCP_LOG_INFO("error: Out of resources. Could not create an " + "exchange port data request for" + "the adapter %s.\n", + zfcp_get_busid_by_adapter(adapter)); write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); return retval; } + if (data) + fsf_req->data = (unsigned long) data; + + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; + sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + + zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); + retval = zfcp_fsf_req_send(fsf_req); write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); - if (!erp_action) { + if (retval) + ZFCP_LOG_INFO("error: Could not send an exchange port data " + "command on the adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + else wait_event(fsf_req->completion_wq, fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); - zfcp_fsf_req_free(fsf_req); - } + + zfcp_fsf_req_free(fsf_req); + return retval; } @@ -2277,18 +2380,16 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) { struct zfcp_adapter *adapter; - struct fsf_qtcb *qtcb; - struct fsf_qtcb_bottom_port *bottom, *data; + struct fsf_qtcb_bottom_port *bottom; struct Scsi_Host *shost; adapter = fsf_req->adapter; - qtcb = fsf_req->qtcb; - bottom = &qtcb->bottom.port; + bottom = &fsf_req->qtcb->bottom.port; shost = adapter->scsi_host; - data = (struct fsf_qtcb_bottom_port*) fsf_req->data; - if (data) - memcpy(data, bottom, sizeof(struct fsf_qtcb_bottom_port)); + if (fsf_req->data) + memcpy((struct fsf_qtcb_bottom_port*) fsf_req->data, bottom, + sizeof(struct fsf_qtcb_bottom_port)); if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) fc_host_permanent_port_name(shost) = bottom->wwpn; @@ -2336,10 +2437,10 @@ zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req) /* * function: zfcp_fsf_open_port * - * purpose: + * purpose: * * returns: address of initiated FSF request - * NULL - request could not be initiated + * NULL - request could not be initiated */ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) @@ -2400,7 +2501,7 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) * * purpose: is called for finished Open Port command * - * returns: + * returns: */ static int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) @@ -3002,7 +3103,7 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) * * purpose: is called for finished Open LUN command * - * returns: + * returns: */ static int zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) @@ -3265,7 +3366,7 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) * purpose: * * returns: address of fsf_req - request successfully initiated - * NULL - + * NULL - * * assumptions: This routine does not check whether the associated * remote port/lun has already been opened. This should be @@ -3586,17 +3687,17 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, ZFCP_LOG_DEBUG( "Data did not fit into available buffer(s), " "waiting for more...\n"); - retval = -EIO; - } else { - ZFCP_LOG_NORMAL("error: No truncation implemented but " - "required. Shutting down unit " - "(adapter %s, port 0x%016Lx, " - "unit 0x%016Lx)\n", - zfcp_get_busid_by_unit(unit), - unit->port->wwpn, - unit->fcp_lun); - zfcp_erp_unit_shutdown(unit, 0); - retval = -EINVAL; + retval = -EIO; + } else { + ZFCP_LOG_NORMAL("error: No truncation implemented but " + "required. Shutting down unit " + "(adapter %s, port 0x%016Lx, " + "unit 0x%016Lx)\n", + zfcp_get_busid_by_unit(unit), + unit->port->wwpn, + unit->fcp_lun); + zfcp_erp_unit_shutdown(unit, 0); + retval = -EINVAL; } goto no_fit; } @@ -3727,7 +3828,7 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, * * purpose: is called for finished Send FCP Command * - * returns: + * returns: */ static int zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) @@ -3964,7 +4065,7 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) * * purpose: evaluates FCP_RSP IU * - * returns: + * returns: */ static int zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) @@ -4192,7 +4293,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) * * purpose: evaluates FCP_RSP IU * - * returns: + * returns: */ static int zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req) @@ -4635,7 +4736,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, INIT_LIST_HEAD(&fsf_req->list); init_timer(&fsf_req->timer); - /* initialize waitqueue which may be used to wait on + /* initialize waitqueue which may be used to wait on this request completion */ init_waitqueue_head(&fsf_req->completion_wq); |