diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_fsf.c')
| -rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 1625 |
1 files changed, 696 insertions, 929 deletions
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index f09c863dc6b..0fe8d5d9511 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -3,21 +3,29 @@ * * Implementation of FSF commands. * - * Copyright IBM Corporation 2002, 2009 + * Copyright IBM Corp. 2002, 2013 */ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include <linux/blktrace_api.h> +#include <linux/slab.h> +#include <scsi/fc/fc_els.h> #include "zfcp_ext.h" +#include "zfcp_fc.h" #include "zfcp_dbf.h" +#include "zfcp_qdio.h" +#include "zfcp_reqlist.h" + +struct kmem_cache *zfcp_fsf_qtcb_cache; static void zfcp_fsf_request_timeout_handler(unsigned long data) { struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; + zfcp_qdio_siosl(adapter); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, - "fsrth_1", NULL); + "fsrth_1"); } static void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, @@ -55,50 +63,11 @@ static u32 fsf_qtcb_type[] = { [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND }; -static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table) -{ - u16 subtable = table >> 16; - u16 rule = table & 0xffff; - const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" }; - - if (subtable && subtable < ARRAY_SIZE(act_type)) - dev_warn(&adapter->ccw_device->dev, - "Access denied according to ACT rule type %s, " - "rule %d\n", act_type[subtable], rule); -} - -static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req, - struct zfcp_port *port) -{ - struct fsf_qtcb_header *header = &req->qtcb->header; - dev_warn(&req->adapter->ccw_device->dev, - "Access denied to port 0x%016Lx\n", - (unsigned long long)port->wwpn); - zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); - zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); - zfcp_erp_port_access_denied(port, "fspad_1", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; -} - -static void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req, - struct zfcp_unit *unit) -{ - struct fsf_qtcb_header *header = &req->qtcb->header; - dev_warn(&req->adapter->ccw_device->dev, - "Access denied to unit 0x%016Lx on port 0x%016Lx\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); - zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); - zfcp_erp_unit_access_denied(unit, "fsuad_1", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; -} - static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req) { dev_err(&req->adapter->ccw_device->dev, "FCP device not " "operational because of an unsupported FC class\n"); - zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1", req); + zfcp_erp_adapter_shutdown(req->adapter, 0, "fscns_1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; } @@ -116,42 +85,38 @@ void zfcp_fsf_req_free(struct zfcp_fsf_req *req) } if (likely(req->qtcb)) - kmem_cache_free(zfcp_data.qtcb_cache, req->qtcb); + kmem_cache_free(zfcp_fsf_qtcb_cache, req->qtcb); kfree(req); } static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req) { + unsigned long flags; struct fsf_status_read_buffer *sr_buf = req->data; struct zfcp_adapter *adapter = req->adapter; struct zfcp_port *port; - int d_id = sr_buf->d_id & ZFCP_DID_MASK; - unsigned long flags; + int d_id = ntoh24(sr_buf->d_id); - read_lock_irqsave(&zfcp_data.config_lock, flags); - list_for_each_entry(port, &adapter->port_list_head, list) + read_lock_irqsave(&adapter->port_list_lock, flags); + list_for_each_entry(port, &adapter->port_list, list) if (port->d_id == d_id) { - read_unlock_irqrestore(&zfcp_data.config_lock, flags); - zfcp_erp_port_reopen(port, 0, "fssrpc1", req); - return; + zfcp_erp_port_reopen(port, 0, "fssrpc1"); + break; } - read_unlock_irqrestore(&zfcp_data.config_lock, flags); + read_unlock_irqrestore(&adapter->port_list_lock, flags); } -static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id, +static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, struct fsf_link_down_info *link_down) { struct zfcp_adapter *adapter = req->adapter; - unsigned long flags; if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) return; atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); - read_lock_irqsave(&zfcp_data.config_lock, flags); zfcp_scsi_schedule_rports_block(adapter); - read_unlock_irqrestore(&zfcp_data.config_lock, flags); if (!link_down) goto out; @@ -221,7 +186,7 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, char *id, "the FC fabric is down\n"); } out: - zfcp_erp_adapter_failed(adapter, id, req); + zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_ERP_FAILED); } static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req) @@ -232,13 +197,13 @@ static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req) switch (sr_buf->status_subtype) { case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: - zfcp_fsf_link_down_info_eval(req, "fssrld1", ldi); + zfcp_fsf_link_down_info_eval(req, ldi); break; case FSF_STATUS_READ_SUB_FDISC_FAILED: - zfcp_fsf_link_down_info_eval(req, "fssrld2", ldi); + zfcp_fsf_link_down_info_eval(req, ldi); break; case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: - zfcp_fsf_link_down_info_eval(req, "fssrld3", NULL); + zfcp_fsf_link_down_info_eval(req, NULL); }; } @@ -248,13 +213,13 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) struct fsf_status_read_buffer *sr_buf = req->data; if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { - zfcp_dbf_hba_fsf_unsol("dism", adapter->dbf, sr_buf); - mempool_free(sr_buf, adapter->pool.status_read_data); + zfcp_dbf_hba_fsf_uss("fssrh_1", req); + mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data); zfcp_fsf_req_free(req); return; } - zfcp_dbf_hba_fsf_unsol("read", adapter->dbf, sr_buf); + zfcp_dbf_hba_fsf_uss("fssrh_4", req); switch (sr_buf->status_type) { case FSF_STATUS_READ_PORT_CLOSED: @@ -269,39 +234,35 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) dev_warn(&adapter->ccw_device->dev, "The error threshold for checksum statistics " "has been exceeded\n"); - zfcp_dbf_hba_berr(adapter->dbf, req); + zfcp_dbf_hba_bit_err("fssrh_3", req); break; case FSF_STATUS_READ_LINK_DOWN: zfcp_fsf_status_read_link_down(req); + zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKDOWN, 0); break; case FSF_STATUS_READ_LINK_UP: dev_info(&adapter->ccw_device->dev, "The local link has been restored\n"); /* All ports should be marked as ready to run again */ - zfcp_erp_modify_adapter_status(adapter, "fssrh_1", NULL, - ZFCP_STATUS_COMMON_RUNNING, - ZFCP_SET); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED, - "fssrh_2", req); + "fssrh_2"); + zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKUP, 0); + break; case FSF_STATUS_READ_NOTIFICATION_LOST: - if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) - zfcp_erp_adapter_access_changed(adapter, "fssrh_3", - req); if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) - schedule_work(&adapter->scan_work); - break; - case FSF_STATUS_READ_CFDC_UPDATED: - zfcp_erp_adapter_access_changed(adapter, "fssrh_4", req); + zfcp_fc_conditional_port_scan(adapter); break; case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: adapter->adapter_features = sr_buf->payload.word[0]; break; } - mempool_free(sr_buf, adapter->pool.status_read_data); + mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data); zfcp_fsf_req_free(req); atomic_inc(&adapter->stat_miss); @@ -317,13 +278,13 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req) case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: return; case FSF_SQ_COMMAND_ABORTED: - req->status |= ZFCP_STATUS_FSFREQ_ABORTED; break; case FSF_SQ_NO_RECOM: dev_err(&req->adapter->ccw_device->dev, "The FCP adapter reported a problem " "that cannot be recovered\n"); - zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req); + zfcp_qdio_siosl(req->adapter); + zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1"); break; } /* all non-return stats set FSFREQ_ERROR*/ @@ -340,7 +301,7 @@ static void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req) dev_err(&req->adapter->ccw_device->dev, "The FCP adapter does not recognize the command 0x%x\n", req->qtcb->header.fsf_command); - zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1", req); + zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfse_1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: @@ -358,8 +319,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) zfcp_dbf_hba_fsf_response(req); if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */ + req->status |= ZFCP_STATUS_FSFREQ_ERROR; return; } @@ -372,17 +332,17 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) "QTCB version 0x%x not supported by FCP adapter " "(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION, psq->word[0], psq->word[1]); - zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fspse_1"); break; case FSF_PROT_ERROR_STATE: case FSF_PROT_SEQ_NUMB_ERROR: - zfcp_erp_adapter_reopen(adapter, 0, "fspse_2", req); - req->status |= ZFCP_STATUS_FSFREQ_RETRY; + zfcp_erp_adapter_reopen(adapter, 0, "fspse_2"); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PROT_UNSUPP_QTCB_TYPE: dev_err(&adapter->ccw_device->dev, "The QTCB type is not supported by the FCP adapter\n"); - zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3"); break; case FSF_PROT_HOST_CONNECTION_INITIALIZING: atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, @@ -392,29 +352,28 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) dev_err(&adapter->ccw_device->dev, "0x%Lx is an ambiguous request identifier\n", (unsigned long long)qtcb->bottom.support.req_handle); - zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fspse_4"); break; case FSF_PROT_LINK_DOWN: - zfcp_fsf_link_down_info_eval(req, "fspse_5", - &psq->link_down_info); - /* FIXME: reopening adapter now? better wait for link up */ - zfcp_erp_adapter_reopen(adapter, 0, "fspse_6", req); + zfcp_fsf_link_down_info_eval(req, &psq->link_down_info); + /* go through reopen to flush pending requests */ + zfcp_erp_adapter_reopen(adapter, 0, "fspse_6"); break; case FSF_PROT_REEST_QUEUE: /* All ports should be marked as ready to run again */ - zfcp_erp_modify_adapter_status(adapter, "fspse_7", NULL, - ZFCP_STATUS_COMMON_RUNNING, - ZFCP_SET); + zfcp_erp_set_adapter_status(adapter, + ZFCP_STATUS_COMMON_RUNNING); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED, - "fspse_8", req); + "fspse_8"); break; default: dev_err(&adapter->ccw_device->dev, "0x%x is not a valid transfer protocol status\n", qtcb->prefix.prot_status); - zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req); + zfcp_qdio_siosl(adapter); + zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9"); } req->status |= ZFCP_STATUS_FSFREQ_ERROR; } @@ -461,15 +420,10 @@ static void zfcp_fsf_req_complete(struct zfcp_fsf_req *req) void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) { struct zfcp_fsf_req *req, *tmp; - unsigned long flags; LIST_HEAD(remove_queue); - unsigned int i; BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP); - spin_lock_irqsave(&adapter->req_list_lock, flags); - for (i = 0; i < REQUEST_LIST_SIZE; i++) - list_splice_init(&adapter->req_list[i], &remove_queue); - spin_unlock_irqrestore(&adapter->req_list_lock, flags); + zfcp_reqlist_move(adapter->req_list, &remove_queue); list_for_each_entry_safe(req, tmp, &remove_queue, list) { list_del(&req->list); @@ -478,34 +432,79 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) } } +#define ZFCP_FSF_PORTSPEED_1GBIT (1 << 0) +#define ZFCP_FSF_PORTSPEED_2GBIT (1 << 1) +#define ZFCP_FSF_PORTSPEED_4GBIT (1 << 2) +#define ZFCP_FSF_PORTSPEED_10GBIT (1 << 3) +#define ZFCP_FSF_PORTSPEED_8GBIT (1 << 4) +#define ZFCP_FSF_PORTSPEED_16GBIT (1 << 5) +#define ZFCP_FSF_PORTSPEED_NOT_NEGOTIATED (1 << 15) + +static u32 zfcp_fsf_convert_portspeed(u32 fsf_speed) +{ + u32 fdmi_speed = 0; + if (fsf_speed & ZFCP_FSF_PORTSPEED_1GBIT) + fdmi_speed |= FC_PORTSPEED_1GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_2GBIT) + fdmi_speed |= FC_PORTSPEED_2GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_4GBIT) + fdmi_speed |= FC_PORTSPEED_4GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_10GBIT) + fdmi_speed |= FC_PORTSPEED_10GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_8GBIT) + fdmi_speed |= FC_PORTSPEED_8GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_16GBIT) + fdmi_speed |= FC_PORTSPEED_16GBIT; + if (fsf_speed & ZFCP_FSF_PORTSPEED_NOT_NEGOTIATED) + fdmi_speed |= FC_PORTSPEED_NOT_NEGOTIATED; + return fdmi_speed; +} + static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) { - struct fsf_qtcb_bottom_config *bottom; + struct fsf_qtcb_bottom_config *bottom = &req->qtcb->bottom.config; struct zfcp_adapter *adapter = req->adapter; struct Scsi_Host *shost = adapter->scsi_host; + struct fc_els_flogi *nsp, *plogi; - bottom = &req->qtcb->bottom.config; + /* adjust pointers for missing command code */ + nsp = (struct fc_els_flogi *) ((u8 *)&bottom->nport_serv_param + - sizeof(u32)); + plogi = (struct fc_els_flogi *) ((u8 *)&bottom->plogi_payload + - sizeof(u32)); if (req->data) memcpy(req->data, bottom, sizeof(*bottom)); - 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_port_name(shost) = nsp->fl_wwpn; + fc_host_node_name(shost) = nsp->fl_wwnn; fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; - adapter->hydra_version = bottom->adapter_type; - adapter->timer_ticks = bottom->timer_interval; + adapter->timer_ticks = bottom->timer_interval & ZFCP_FSF_TIMER_INT_MASK; + adapter->stat_read_buf_num = max(bottom->status_read_buf_num, + (u16)FSF_STATUS_READS_RECOM); if (fc_host_permanent_port_name(shost) == -1) fc_host_permanent_port_name(shost) = fc_host_port_name(shost); + zfcp_scsi_set_prot(adapter); + + /* no error return above here, otherwise must fix call chains */ + /* do not evaluate invalid fields */ + if (req->qtcb->header.fsf_status == FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE) + return 0; + + fc_host_port_id(shost) = ntoh24(bottom->s_id); + fc_host_speed(shost) = + zfcp_fsf_convert_portspeed(bottom->fc_link_speed); + + adapter->hydra_version = bottom->adapter_type; + switch (bottom->fc_topology) { case 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; + adapter->peer_d_id = ntoh24(bottom->peer_d_id); + adapter->peer_wwpn = plogi->fl_wwpn; + adapter->peer_wwnn = plogi->fl_wwnn; fc_host_port_type(shost) = FC_PORTTYPE_PTP; break; case FSF_TOPO_FABRIC: @@ -518,7 +517,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) dev_err(&adapter->ccw_device->dev, "Unknown or unsupported arbitrated loop " "fibre channel topology detected\n"); - zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fsece_1"); return -EIO; } @@ -552,7 +551,7 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) "FCP adapter maximum QTCB size (%d bytes) " "is too small\n", bottom->max_qtcb_size); - zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1"); return; } atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, @@ -566,14 +565,17 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; adapter->hydra_version = 0; + /* avoids adapter shutdown to be able to recognize + * events such as LINK UP */ atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); - - zfcp_fsf_link_down_info_eval(req, "fsecdh2", + zfcp_fsf_link_down_info_eval(req, &qtcb->header.fsf_status_qual.link_down_info); + if (zfcp_fsf_exchange_config_evaluate(req)) + return; break; default: - zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh3"); return; } @@ -589,14 +591,14 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) dev_err(&adapter->ccw_device->dev, "The FCP adapter only supports newer " "control block versions\n"); - zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh4"); return; } if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) { dev_err(&adapter->ccw_device->dev, "The FCP adapter only supports older " "control block versions\n"); - zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5", req); + zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh5"); } } @@ -615,7 +617,12 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req) } else fc_host_permanent_port_name(shost) = fc_host_port_name(shost); fc_host_maxframe_size(shost) = bottom->maximum_frame_size; - fc_host_supported_speeds(shost) = bottom->supported_speed; + fc_host_supported_speeds(shost) = + zfcp_fsf_convert_portspeed(bottom->supported_speed); + memcpy(fc_host_supported_fc4s(shost), bottom->supported_fc4_types, + FC_FC4_LIST_SIZE); + memcpy(fc_host_active_fc4s(shost), bottom->active_fc4_types, + FC_FC4_LIST_SIZE); } static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) @@ -631,43 +638,12 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) break; case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: zfcp_fsf_exchange_port_evaluate(req); - zfcp_fsf_link_down_info_eval(req, "fsepdh1", + zfcp_fsf_link_down_info_eval(req, &qtcb->header.fsf_status_qual.link_down_info); break; } } -static int zfcp_fsf_sbal_check(struct zfcp_qdio *qdio) -{ - struct zfcp_qdio_queue *req_q = &qdio->req_q; - - spin_lock_bh(&qdio->req_q_lock); - if (atomic_read(&req_q->count)) - return 1; - spin_unlock_bh(&qdio->req_q_lock); - return 0; -} - -static int zfcp_fsf_req_sbal_get(struct zfcp_qdio *qdio) -{ - struct zfcp_adapter *adapter = qdio->adapter; - long ret; - - spin_unlock_bh(&qdio->req_q_lock); - ret = wait_event_interruptible_timeout(qdio->req_q_wq, - zfcp_fsf_sbal_check(qdio), 5 * HZ); - if (ret > 0) - return 0; - if (!ret) { - atomic_inc(&qdio->req_q_full); - /* assume hanging outbound queue, try queue recovery */ - zfcp_erp_adapter_reopen(adapter, 0, "fsrsg_1", NULL); - } - - spin_lock_bh(&qdio->req_q_lock); - return -EIO; -} - static struct zfcp_fsf_req *zfcp_fsf_alloc(mempool_t *pool) { struct zfcp_fsf_req *req; @@ -692,7 +668,7 @@ static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool) if (likely(pool)) qtcb = mempool_alloc(pool, GFP_ATOMIC); else - qtcb = kmem_cache_alloc(zfcp_data.qtcb_cache, GFP_ATOMIC); + qtcb = kmem_cache_alloc(zfcp_fsf_qtcb_cache, GFP_ATOMIC); if (unlikely(!qtcb)) return NULL; @@ -702,10 +678,9 @@ static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool) } static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio, - u32 fsf_cmd, mempool_t *pool) + u32 fsf_cmd, u8 sbtype, + mempool_t *pool) { - struct qdio_buffer_element *sbale; - struct zfcp_qdio_queue *req_q = &qdio->req_q; struct zfcp_adapter *adapter = qdio->adapter; struct zfcp_fsf_req *req = zfcp_fsf_alloc(pool); @@ -722,14 +697,6 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio, req->adapter = adapter; req->fsf_command = fsf_cmd; req->req_id = adapter->req_no; - req->queue_req.sbal_number = 1; - req->queue_req.sbal_first = req_q->first; - req->queue_req.sbal_last = req_q->first; - req->queue_req.sbale_curr = 1; - - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].addr = (void *) req->req_id; - sbale[0].flags |= SBAL_FLAGS0_COMMAND; if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) { if (likely(pool)) @@ -742,6 +709,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio, return ERR_PTR(-ENOMEM); } + req->seq_no = adapter->fsf_req_seq_no; req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; req->qtcb->prefix.req_id = req->req_id; req->qtcb->prefix.ulp_info = 26; @@ -749,16 +717,10 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio, req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION; req->qtcb->header.req_handle = req->req_id; req->qtcb->header.fsf_command = req->fsf_command; - req->seq_no = adapter->fsf_req_seq_no; - req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; - sbale[1].addr = (void *) req->qtcb; - sbale[1].length = sizeof(struct fsf_qtcb); } - if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) { - zfcp_fsf_req_free(req); - return ERR_PTR(-EIO); - } + zfcp_qdio_req_init(adapter->qdio, &req->qdio_req, req->req_id, sbtype, + req->qtcb, sizeof(struct fsf_qtcb)); return req; } @@ -767,26 +729,18 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; struct zfcp_qdio *qdio = adapter->qdio; - unsigned long flags; - int idx; - int with_qtcb = (req->qtcb != NULL); - - /* put allocated FSF request into hash table */ - spin_lock_irqsave(&adapter->req_list_lock, flags); - idx = zfcp_reqlist_hash(req->req_id); - list_add_tail(&req->list, &adapter->req_list[idx]); - spin_unlock_irqrestore(&adapter->req_list_lock, flags); - - req->queue_req.qdio_outb_usage = atomic_read(&qdio->req_q.count); - req->issued = get_clock(); - if (zfcp_qdio_send(qdio, &req->queue_req)) { + int with_qtcb = (req->qtcb != NULL); + int req_id = req->req_id; + + zfcp_reqlist_add(adapter->req_list, req); + + req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free); + req->issued = get_tod_clock(); + if (zfcp_qdio_send(qdio, &req->qdio_req)) { del_timer(&req->timer); - spin_lock_irqsave(&adapter->req_list_lock, flags); /* lookup request again, list might have changed */ - if (zfcp_reqlist_find_safe(adapter, req)) - zfcp_reqlist_remove(adapter, req); - spin_unlock_irqrestore(&adapter->req_list_lock, flags); - zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1", req); + zfcp_reqlist_find_rm(adapter->req_list, req_id); + zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1"); return -EIO; } @@ -809,34 +763,32 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio) struct zfcp_adapter *adapter = qdio->adapter; struct zfcp_fsf_req *req; struct fsf_status_read_buffer *sr_buf; - struct qdio_buffer_element *sbale; + struct page *page; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS, + SBAL_SFLAGS0_TYPE_STATUS, adapter->pool.status_read_req); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; } - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; - req->queue_req.sbale_curr = 2; - - sr_buf = mempool_alloc(adapter->pool.status_read_data, GFP_ATOMIC); - if (!sr_buf) { + page = mempool_alloc(adapter->pool.sr_data, GFP_ATOMIC); + if (!page) { retval = -ENOMEM; goto failed_buf; } + sr_buf = page_address(page); memset(sr_buf, 0, sizeof(*sr_buf)); req->data = sr_buf; - sbale = zfcp_qdio_sbale_curr(qdio, &req->queue_req); - sbale->addr = (void *) sr_buf; - sbale->length = sizeof(*sr_buf); + + zfcp_qdio_fill_next(qdio, &req->qdio_req, sr_buf, sizeof(*sr_buf)); + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); retval = zfcp_fsf_req_send(req); if (retval) @@ -845,34 +797,38 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio) goto out; failed_req_send: - mempool_free(sr_buf, adapter->pool.status_read_data); + req->data = NULL; + mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data); failed_buf: + zfcp_dbf_hba_fsf_uss("fssr__1", req); zfcp_fsf_req_free(req); - zfcp_dbf_hba_fsf_unsol("fail", adapter->dbf, NULL); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) { - struct zfcp_unit *unit = req->data; + struct scsi_device *sdev = req->data; + struct zfcp_scsi_dev *zfcp_sdev; union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; + zfcp_sdev = sdev_to_zfcp(sdev); + switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: if (fsq->word[0] == fsq->word[1]) { - zfcp_erp_adapter_reopen(unit->port->adapter, 0, - "fsafch1", req); + zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, + "fsafch1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; } break; case FSF_LUN_HANDLE_NOT_VALID: if (fsq->word[0] == fsq->word[1]) { - zfcp_erp_port_reopen(unit->port, 0, "fsafch2", req); + zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fsafch2"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; } break; @@ -880,19 +836,22 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED; break; case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, "fsafch3", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + zfcp_erp_set_port_status(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ERP_FAILED, "fsafch3"); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_BOXED: - zfcp_erp_unit_boxed(unit, "fsafch4", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, + "fsafch4"); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: switch (fsq->word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - zfcp_fc_test_link(unit->port); + zfcp_fc_test_link(zfcp_sdev->port); /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -906,41 +865,40 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) } /** - * zfcp_fsf_abort_fcp_command - abort running SCSI command - * @old_req_id: unsigned long - * @unit: pointer to struct zfcp_unit + * zfcp_fsf_abort_fcp_cmnd - abort running SCSI command + * @scmnd: The SCSI command to abort * Returns: pointer to struct zfcp_fsf_req */ -struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, - struct zfcp_unit *unit) +struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd) { - struct qdio_buffer_element *sbale; struct zfcp_fsf_req *req = NULL; - struct zfcp_qdio *qdio = unit->port->adapter->qdio; + struct scsi_device *sdev = scmnd->device; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_qdio *qdio = zfcp_sdev->port->adapter->qdio; + unsigned long old_req_id = (unsigned long) scmnd->host_scribble; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_ABORT_FCP_CMND, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.scsi_abort); if (IS_ERR(req)) { req = NULL; goto out; } - if (unlikely(!(atomic_read(&unit->status) & + if (unlikely(!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) goto out_error_free; - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); - req->data = unit; + req->data = sdev; req->handler = zfcp_fsf_abort_fcp_command_handler; - req->qtcb->header.lun_handle = unit->handle; - req->qtcb->header.port_handle = unit->port->handle; + req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; + req->qtcb->header.port_handle = zfcp_sdev->port->handle; req->qtcb->bottom.support.req_handle = (u64) old_req_id; zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); @@ -951,25 +909,25 @@ out_error_free: zfcp_fsf_req_free(req); req = NULL; out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return req; } static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; - struct zfcp_send_ct *send_ct = req->data; + struct zfcp_fsf_ct_els *ct = req->data; struct fsf_qtcb_header *header = &req->qtcb->header; - send_ct->status = -EINVAL; + ct->status = -EINVAL; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) goto skip_fsfstatus; switch (header->fsf_status) { case FSF_GOOD: - zfcp_dbf_san_ct_response(req); - send_ct->status = 0; + zfcp_dbf_san_res("fsscth2", req); + ct->status = 0; break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: zfcp_fsf_class_not_supp(req); @@ -982,14 +940,11 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) break; } break; - case FSF_ACCESS_DENIED: - break; case FSF_PORT_BOXED: - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req); + zfcp_erp_adapter_reopen(adapter, 0, "fsscth1"); /* fall through */ case FSF_GENERIC_COMMAND_REJECTED: case FSF_PAYLOAD_SIZE_MISMATCH: @@ -1001,71 +956,87 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) } skip_fsfstatus: - if (send_ct->handler) - send_ct->handler(send_ct->handler_data); + if (ct->handler) + ct->handler(ct->handler_data); } -static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale, +static void zfcp_fsf_setup_ct_els_unchained(struct zfcp_qdio *qdio, + struct zfcp_qdio_req *q_req, struct scatterlist *sg_req, struct scatterlist *sg_resp) { - sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; - sbale[2].addr = sg_virt(sg_req); - sbale[2].length = sg_req->length; - sbale[3].addr = sg_virt(sg_resp); - sbale[3].length = sg_resp->length; - sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; -} - -static int zfcp_fsf_one_sbal(struct scatterlist *sg) -{ - return sg_is_last(sg) && sg->length <= PAGE_SIZE; + zfcp_qdio_fill_next(qdio, q_req, sg_virt(sg_req), sg_req->length); + zfcp_qdio_fill_next(qdio, q_req, sg_virt(sg_resp), sg_resp->length); + zfcp_qdio_set_sbale_last(qdio, q_req); } static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, struct scatterlist *sg_req, - struct scatterlist *sg_resp, - int max_sbals) + struct scatterlist *sg_resp) { struct zfcp_adapter *adapter = req->adapter; - struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(adapter->qdio, - &req->queue_req); + struct zfcp_qdio *qdio = adapter->qdio; + struct fsf_qtcb *qtcb = req->qtcb; u32 feat = adapter->adapter_features; - int bytes; - if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) { - if (!zfcp_fsf_one_sbal(sg_req) || !zfcp_fsf_one_sbal(sg_resp)) - return -EOPNOTSUPP; + if (zfcp_adapter_multi_buffer_active(adapter)) { + if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_req)) + return -EIO; + if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_resp)) + return -EIO; - zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp); + zfcp_qdio_set_data_div(qdio, &req->qdio_req, + zfcp_qdio_sbale_count(sg_req)); + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); + zfcp_qdio_set_scount(qdio, &req->qdio_req); return 0; } /* use single, unchained SBAL if it can hold the request */ - if (zfcp_fsf_one_sbal(sg_req) && zfcp_fsf_one_sbal(sg_resp)) { - zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp); + if (zfcp_qdio_sg_one_sbale(sg_req) && zfcp_qdio_sg_one_sbale(sg_resp)) { + zfcp_fsf_setup_ct_els_unchained(qdio, &req->qdio_req, + sg_req, sg_resp); return 0; } - bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->queue_req, - SBAL_FLAGS0_TYPE_WRITE_READ, - sg_req, max_sbals); - if (bytes <= 0) + if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) + return -EOPNOTSUPP; + + if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_req)) return -EIO; - req->qtcb->bottom.support.req_buf_length = bytes; - req->queue_req.sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; - bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->queue_req, - SBAL_FLAGS0_TYPE_WRITE_READ, - sg_resp, max_sbals); - if (bytes <= 0) + qtcb->bottom.support.req_buf_length = zfcp_qdio_real_bytes(sg_req); + + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); + zfcp_qdio_skip_to_last_sbale(qdio, &req->qdio_req); + + if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_resp)) return -EIO; + qtcb->bottom.support.resp_buf_length = zfcp_qdio_real_bytes(sg_resp); + + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); + + return 0; +} + +static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req, + struct scatterlist *sg_req, + struct scatterlist *sg_resp, + unsigned int timeout) +{ + int ret; + + ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp); + if (ret) + return ret; + /* common settings for ct/gs and els requests */ - req->qtcb->bottom.support.resp_buf_length = bytes; + if (timeout > 255) + timeout = 255; /* max value accepted by hardware */ req->qtcb->bottom.support.service_class = FSF_CLASS_3; - req->qtcb->bottom.support.timeout = 2 * R_A_TOV; - zfcp_fsf_start_timer(req, 2 * R_A_TOV + 10); + req->qtcb->bottom.support.timeout = timeout; + zfcp_fsf_start_timer(req, (timeout + 10) * HZ); return 0; } @@ -1075,18 +1046,20 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, * @ct: pointer to struct zfcp_send_ct with data for request * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req */ -int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool) +int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port, + struct zfcp_fsf_ct_els *ct, mempool_t *pool, + unsigned int timeout) { - struct zfcp_wka_port *wka_port = ct->wka_port; struct zfcp_qdio *qdio = wka_port->adapter->qdio; struct zfcp_fsf_req *req; int ret = -EIO; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC, pool); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC, + SBAL_SFLAGS0_TYPE_WRITE_READ, pool); if (IS_ERR(req)) { ret = PTR_ERR(req); @@ -1094,8 +1067,7 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - ret = zfcp_fsf_setup_ct_els_sbals(req, ct->req, ct->resp, - FSF_MAX_SBALS_PER_REQ); + ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp, timeout); if (ret) goto failed_send; @@ -1103,7 +1075,7 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool) req->qtcb->header.port_handle = wka_port->handle; req->data = ct; - zfcp_dbf_san_ct_request(req); + zfcp_dbf_san_req("fssct_1", req, wka_port->d_id); ret = zfcp_fsf_req_send(req); if (ret) @@ -1114,14 +1086,13 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool) failed_send: zfcp_fsf_req_free(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return ret; } static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) { - struct zfcp_send_els *send_els = req->data; - struct zfcp_port *port = send_els->port; + struct zfcp_fsf_ct_els *send_els = req->data; struct fsf_qtcb_header *header = &req->qtcb->header; send_els->status = -EINVAL; @@ -1131,7 +1102,7 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) switch (header->fsf_status) { case FSF_GOOD: - zfcp_dbf_san_els_response(req); + zfcp_dbf_san_res("fsselh1", req); send_els->status = 0; break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: @@ -1140,9 +1111,6 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]){ case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - if (port && (send_els->ls_code != ZFCP_LS_ADISC)) - zfcp_fc_test_link(port); - /*fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: case FSF_SQ_RETRY_IF_POSSIBLE: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1154,12 +1122,8 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) case FSF_REQUEST_SIZE_TOO_LARGE: case FSF_RESPONSE_SIZE_TOO_LARGE: break; - case FSF_ACCESS_DENIED: - if (port) - zfcp_fsf_access_denied_port(req, port); - break; case FSF_SBAL_MISMATCH: - /* should never occure, avoided in zfcp_fsf_send_els */ + /* should never occur, avoided in zfcp_fsf_send_els */ /* fall through */ default: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1174,17 +1138,19 @@ skip_fsfstatus: * zfcp_fsf_send_els - initiate an ELS command (FC-FS) * @els: pointer to struct zfcp_send_els with data for the command */ -int zfcp_fsf_send_els(struct zfcp_send_els *els) +int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, + struct zfcp_fsf_ct_els *els, unsigned int timeout) { struct zfcp_fsf_req *req; - struct zfcp_qdio *qdio = els->adapter->qdio; + struct zfcp_qdio *qdio = adapter->qdio; int ret = -EIO; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS, NULL); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS, + SBAL_SFLAGS0_TYPE_WRITE_READ, NULL); if (IS_ERR(req)) { ret = PTR_ERR(req); @@ -1192,16 +1158,20 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - ret = zfcp_fsf_setup_ct_els_sbals(req, els->req, els->resp, 2); + + if (!zfcp_adapter_multi_buffer_active(adapter)) + zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 2); + + ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, timeout); if (ret) goto failed_send; - req->qtcb->bottom.support.d_id = els->d_id; + hton24(req->qtcb->bottom.support.d_id, d_id); req->handler = zfcp_fsf_send_els_handler; req->data = els; - zfcp_dbf_san_els_request(req); + zfcp_dbf_san_req("fssels1", req, d_id); ret = zfcp_fsf_req_send(req); if (ret) @@ -1212,22 +1182,22 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) failed_send: zfcp_fsf_req_free(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return ret; } int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) { - struct qdio_buffer_element *sbale; struct zfcp_fsf_req *req; struct zfcp_qdio *qdio = erp_action->adapter->qdio; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1236,56 +1206,48 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); req->qtcb->bottom.config.feature_selection = - FSF_FEATURE_CFDC | - FSF_FEATURE_LUN_SHARING | FSF_FEATURE_NOTIFICATION_LOST | FSF_FEATURE_UPDATE_ALERT; req->erp_action = erp_action; req->handler = zfcp_fsf_exchange_config_data_handler; - erp_action->fsf_req = req; + erp_action->fsf_req_id = req->req_id; zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); - erp_action->fsf_req = NULL; + erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, struct fsf_qtcb_bottom_config *data) { - struct qdio_buffer_element *sbale; struct zfcp_fsf_req *req = NULL; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out_unlock; - req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, NULL); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, + SBAL_SFLAGS0_TYPE_READ, NULL); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out_unlock; } - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); req->handler = zfcp_fsf_exchange_config_data_handler; req->qtcb->bottom.config.feature_selection = - FSF_FEATURE_CFDC | - FSF_FEATURE_LUN_SHARING | FSF_FEATURE_NOTIFICATION_LOST | FSF_FEATURE_UPDATE_ALERT; @@ -1294,7 +1256,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); if (!retval) wait_for_completion(&req->completion); @@ -1302,7 +1264,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, return retval; out_unlock: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1314,18 +1276,18 @@ out_unlock: int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) { struct zfcp_qdio *qdio = erp_action->adapter->qdio; - struct qdio_buffer_element *sbale; struct zfcp_fsf_req *req; int retval = -EIO; if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) return -EOPNOTSUPP; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1334,22 +1296,20 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); req->handler = zfcp_fsf_exchange_port_data_handler; req->erp_action = erp_action; - erp_action->fsf_req = req; + erp_action->fsf_req_id = req->req_id; zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); - erp_action->fsf_req = NULL; + erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1362,18 +1322,18 @@ out: int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, struct fsf_qtcb_bottom_port *data) { - struct qdio_buffer_element *sbale; struct zfcp_fsf_req *req = NULL; int retval = -EIO; if (!(qdio->adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) return -EOPNOTSUPP; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out_unlock; - req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, NULL); + req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, + SBAL_SFLAGS0_TYPE_READ, NULL); if (IS_ERR(req)) { retval = PTR_ERR(req); @@ -1383,14 +1343,12 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, if (data) req->data = data; - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); req->handler = zfcp_fsf_exchange_port_data_handler; zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); if (!retval) wait_for_completion(&req->completion); @@ -1400,7 +1358,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, return retval; out_unlock: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1408,7 +1366,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) { struct zfcp_port *port = req->data; struct fsf_qtcb_header *header = &req->qtcb->header; - struct fsf_plogi *plogi; + struct fc_els_flogi *plogi; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) goto out; @@ -1416,15 +1374,13 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) switch (header->fsf_status) { case FSF_PORT_ALREADY_OPEN: break; - case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_port(req, port); - break; case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: dev_warn(&req->adapter->ccw_device->dev, "Not enough FCP adapter resources to open " "remote port 0x%016Lx\n", (unsigned long long)port->wwpn); - zfcp_erp_port_failed(port, "fsoph_1", req); + zfcp_erp_set_port_status(port, + ZFCP_STATUS_COMMON_ERP_FAILED); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: @@ -1458,16 +1414,10 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) * another GID_PN straight after a port has been opened. * Alternately, an ADISC/PDISC ELS should suffice, as well. */ - plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els; + plogi = (struct fc_els_flogi *) req->qtcb->bottom.support.els; if (req->qtcb->bottom.support.els1_length >= - FSF_PLOGI_MIN_LEN) { - if (plogi->serv_param.wwpn != port->wwpn) - port->d_id = 0; - else { - port->wwnn = plogi->serv_param.wwnn; + FSF_PLOGI_MIN_LEN) zfcp_fc_plogi_evaluate(port, plogi); - } - } break; case FSF_UNKNOWN_OP_SUBTYPE: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1475,7 +1425,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) } out: - zfcp_port_put(port); + put_device(&port->dev); } /** @@ -1485,17 +1435,17 @@ out: */ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) { - struct qdio_buffer_element *sbale; struct zfcp_qdio *qdio = erp_action->adapter->qdio; struct zfcp_port *port = erp_action->port; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1504,26 +1454,24 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); req->handler = zfcp_fsf_open_port_handler; - req->qtcb->bottom.support.d_id = port->d_id; + hton24(req->qtcb->bottom.support.d_id, port->d_id); req->data = port; req->erp_action = erp_action; - erp_action->fsf_req = req; - zfcp_port_get(port); + erp_action->fsf_req_id = req->req_id; + get_device(&port->dev); zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); - erp_action->fsf_req = NULL; - zfcp_port_put(port); + erp_action->fsf_req_id = 0; + put_device(&port->dev); } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1536,15 +1484,13 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req) switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1", req); + zfcp_erp_adapter_reopen(port->adapter, 0, "fscph_1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: break; case FSF_GOOD: - zfcp_erp_modify_port_status(port, "fscph_2", req, - ZFCP_STATUS_COMMON_OPEN, - ZFCP_CLEAR); + zfcp_erp_clear_port_status(port, ZFCP_STATUS_COMMON_OPEN); break; } } @@ -1556,16 +1502,16 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req) */ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) { - struct qdio_buffer_element *sbale; struct zfcp_qdio *qdio = erp_action->adapter->qdio; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1574,34 +1520,32 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); req->handler = zfcp_fsf_close_port_handler; req->data = erp_action->port; req->erp_action = erp_action; req->qtcb->header.port_handle = erp_action->port->handle; - erp_action->fsf_req = req; + erp_action->fsf_req_id = req->req_id; zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); - erp_action->fsf_req = NULL; + erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req) { - struct zfcp_wka_port *wka_port = req->data; + struct zfcp_fc_wka_port *wka_port = req->data; struct fsf_qtcb_header *header = &req->qtcb->header; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) { - wka_port->status = ZFCP_WKA_PORT_OFFLINE; + wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; goto out; } @@ -1612,15 +1556,13 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req) /* fall through */ case FSF_ADAPTER_STATUS_AVAILABLE: req->status |= ZFCP_STATUS_FSFREQ_ERROR; - /* fall through */ - case FSF_ACCESS_DENIED: - wka_port->status = ZFCP_WKA_PORT_OFFLINE; + wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; break; case FSF_GOOD: wka_port->handle = header->port_handle; /* fall through */ case FSF_PORT_ALREADY_OPEN: - wka_port->status = ZFCP_WKA_PORT_ONLINE; + wka_port->status = ZFCP_FC_WKA_PORT_ONLINE; } out: wake_up(&wka_port->completion_wq); @@ -1628,35 +1570,33 @@ out: /** * zfcp_fsf_open_wka_port - create and send open wka-port request - * @wka_port: pointer to struct zfcp_wka_port + * @wka_port: pointer to struct zfcp_fc_wka_port * Returns: 0 on success, error otherwise */ -int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port) +int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port) { - struct qdio_buffer_element *sbale; struct zfcp_qdio *qdio = wka_port->adapter->qdio; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); - if (unlikely(IS_ERR(req))) { + if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); req->handler = zfcp_fsf_open_wka_port_handler; - req->qtcb->bottom.support.d_id = wka_port->d_id; + hton24(req->qtcb->bottom.support.d_id, wka_port->d_id); req->data = wka_port; zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); @@ -1664,51 +1604,49 @@ int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port) if (retval) zfcp_fsf_req_free(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req) { - struct zfcp_wka_port *wka_port = req->data; + struct zfcp_fc_wka_port *wka_port = req->data; if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) { req->status |= ZFCP_STATUS_FSFREQ_ERROR; - zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1", req); + zfcp_erp_adapter_reopen(wka_port->adapter, 0, "fscwph1"); } - wka_port->status = ZFCP_WKA_PORT_OFFLINE; + wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; wake_up(&wka_port->completion_wq); } /** * zfcp_fsf_close_wka_port - create and send close wka port request - * @erp_action: pointer to struct zfcp_erp_action + * @wka_port: WKA port to open * Returns: 0 on success, error otherwise */ -int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port) +int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port) { - struct qdio_buffer_element *sbale; struct zfcp_qdio *qdio = wka_port->adapter->qdio; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); - if (unlikely(IS_ERR(req))) { + if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); req->handler = zfcp_fsf_close_wka_port_handler; req->data = wka_port; @@ -1719,7 +1657,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port) if (retval) zfcp_fsf_req_free(req); out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -1727,30 +1665,28 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) { struct zfcp_port *port = req->data; struct fsf_qtcb_header *header = &req->qtcb->header; - struct zfcp_unit *unit; + struct scsi_device *sdev; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; switch (header->fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1", req); + zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_port(req, port); - break; case FSF_PORT_BOXED: /* can't use generic zfcp_erp_modify_port_status because * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); - list_for_each_entry(unit, &port->unit_list_head, list) - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, - &unit->status); - zfcp_erp_port_boxed(port, "fscpph2", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; - + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, + &sdev_to_zfcp(sdev)->status); + zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, + "fscpph2"); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]) { @@ -1766,9 +1702,10 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); - list_for_each_entry(unit, &port->unit_list_head, list) - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, - &unit->status); + shost_for_each_device(sdev, port->adapter->scsi_host) + if (sdev_to_zfcp(sdev)->port == port) + atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, + &sdev_to_zfcp(sdev)->status); break; } } @@ -1780,16 +1717,16 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) */ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) { - struct qdio_buffer_element *sbale; struct zfcp_qdio *qdio = erp_action->adapter->qdio; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PHYSICAL_PORT, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1798,87 +1735,77 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); req->data = erp_action->port; req->qtcb->header.port_handle = erp_action->port->handle; req->erp_action = erp_action; req->handler = zfcp_fsf_close_physical_port_handler; - erp_action->fsf_req = req; + erp_action->fsf_req_id = req->req_id; zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); - erp_action->fsf_req = NULL; + erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } -static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) +static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; - struct zfcp_unit *unit = req->data; + struct scsi_device *sdev = req->data; + struct zfcp_scsi_dev *zfcp_sdev; struct fsf_qtcb_header *header = &req->qtcb->header; - struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support; - struct fsf_queue_designator *queue_designator = - &header->fsf_status_qual.fsf_queue_designator; - int exclusive, readwrite; + union fsf_status_qual *qual = &header->fsf_status_qual; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; + zfcp_sdev = sdev_to_zfcp(sdev); + atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | - ZFCP_STATUS_COMMON_ACCESS_BOXED | - ZFCP_STATUS_UNIT_SHARED | - ZFCP_STATUS_UNIT_READONLY, - &unit->status); + ZFCP_STATUS_COMMON_ACCESS_BOXED, + &zfcp_sdev->status); switch (header->fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fsouh_1", req); + zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1"); /* fall through */ case FSF_LUN_ALREADY_OPEN: break; - case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_unit(req, unit); - atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); - atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); - break; case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, "fsouh_2", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + zfcp_erp_set_port_status(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ERP_FAILED, "fsouh_2"); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_SHARING_VIOLATION: - if (header->fsf_status_qual.word[0]) - dev_warn(&adapter->ccw_device->dev, + if (qual->word[0]) + dev_warn(&zfcp_sdev->port->adapter->ccw_device->dev, "LUN 0x%Lx on port 0x%Lx is already in " "use by CSS%d, MIF Image ID %x\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn, - queue_designator->cssid, - queue_designator->hla); - else - zfcp_act_eval_err(adapter, - header->fsf_status_qual.word[2]); - zfcp_erp_unit_access_denied(unit, "fsouh_3", req); - atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); - atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); + zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn, + qual->fsf_queue_designator.cssid, + qual->fsf_queue_designator.hla); + zfcp_erp_set_lun_status(sdev, + ZFCP_STATUS_COMMON_ERP_FAILED | + ZFCP_STATUS_COMMON_ACCESS_DENIED); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED: dev_warn(&adapter->ccw_device->dev, "No handle is available for LUN " "0x%016Lx on port 0x%016Lx\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_failed(unit, "fsouh_4", req); + (unsigned long long)zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED); /* fall through */ case FSF_INVALID_COMMAND_OPTION: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1886,7 +1813,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - zfcp_fc_test_link(unit->port); + zfcp_fc_test_link(zfcp_sdev->port); /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1895,75 +1822,30 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) break; case FSF_GOOD: - unit->handle = header->lun_handle; - atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); - - if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) && - (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) && - !zfcp_ccw_priv_sch(adapter)) { - exclusive = (bottom->lun_access_info & - FSF_UNIT_ACCESS_EXCLUSIVE); - readwrite = (bottom->lun_access_info & - FSF_UNIT_ACCESS_OUTBOUND_TRANSFER); - - if (!exclusive) - atomic_set_mask(ZFCP_STATUS_UNIT_SHARED, - &unit->status); - - if (!readwrite) { - atomic_set_mask(ZFCP_STATUS_UNIT_READONLY, - &unit->status); - dev_info(&adapter->ccw_device->dev, - "SCSI device at LUN 0x%016Lx on port " - "0x%016Lx opened read-only\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - } - - if (exclusive && !readwrite) { - dev_err(&adapter->ccw_device->dev, - "Exclusive read-only access not " - "supported (unit 0x%016Lx, " - "port 0x%016Lx)\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_failed(unit, "fsouh_5", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - zfcp_erp_unit_shutdown(unit, 0, "fsouh_6", req); - } else if (!exclusive && readwrite) { - dev_err(&adapter->ccw_device->dev, - "Shared read-write access not " - "supported (unit 0x%016Lx, port " - "0x%016Lx)\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_failed(unit, "fsouh_7", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - zfcp_erp_unit_shutdown(unit, 0, "fsouh_8", req); - } - } + zfcp_sdev->lun_handle = header->lun_handle; + atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); break; } } /** - * zfcp_fsf_open_unit - open unit + * zfcp_fsf_open_lun - open LUN * @erp_action: pointer to struct zfcp_erp_action * Returns: 0 on success, error otherwise */ -int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) +int zfcp_fsf_open_lun(struct zfcp_erp_action *erp_action) { - struct qdio_buffer_element *sbale; struct zfcp_adapter *adapter = erp_action->adapter; struct zfcp_qdio *qdio = adapter->qdio; struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_LUN, + SBAL_SFLAGS0_TYPE_READ, adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1972,16 +1854,14 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); req->qtcb->header.port_handle = erp_action->port->handle; - req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun; - req->handler = zfcp_fsf_open_unit_handler; - req->data = erp_action->unit; + req->qtcb->bottom.support.fcp_lun = zfcp_scsi_dev_lun(erp_action->sdev); + req->handler = zfcp_fsf_open_lun_handler; + req->data = erp_action->sdev; req->erp_action = erp_action; - erp_action->fsf_req = req; + erp_action->fsf_req_id = req->req_id; if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING; @@ -1990,38 +1870,43 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); - erp_action->fsf_req = NULL; + erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } -static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req) +static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) { - struct zfcp_unit *unit = req->data; + struct scsi_device *sdev = req->data; + struct zfcp_scsi_dev *zfcp_sdev; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; + zfcp_sdev = sdev_to_zfcp(sdev); + switch (req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fscuh_1", req); + zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_HANDLE_NOT_VALID: - zfcp_erp_port_reopen(unit->port, 0, "fscuh_2", req); + zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fscuh_2"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, "fscuh_3", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + zfcp_erp_set_port_status(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ERP_FAILED, "fscuh_3"); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: switch (req->qtcb->header.fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - zfcp_fc_test_link(unit->port); + zfcp_fc_test_link(zfcp_sdev->port); /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -2029,28 +1914,29 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req) } break; case FSF_GOOD: - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); + atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); break; } } /** - * zfcp_fsf_close_unit - close zfcp unit - * @erp_action: pointer to struct zfcp_unit + * zfcp_fsf_close_LUN - close LUN + * @erp_action: pointer to erp_action triggering the "close LUN" * Returns: 0 on success, error otherwise */ -int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) +int zfcp_fsf_close_lun(struct zfcp_erp_action *erp_action) { - struct qdio_buffer_element *sbale; struct zfcp_qdio *qdio = erp_action->adapter->qdio; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(erp_action->sdev); struct zfcp_fsf_req *req; int retval = -EIO; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_LUN, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -2059,25 +1945,23 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); req->qtcb->header.port_handle = erp_action->port->handle; - req->qtcb->header.lun_handle = erp_action->unit->handle; - req->handler = zfcp_fsf_close_unit_handler; - req->data = erp_action->unit; + req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; + req->handler = zfcp_fsf_close_lun_handler; + req->data = erp_action->sdev; req->erp_action = erp_action; - erp_action->fsf_req = req; + erp_action->fsf_req_id = req->req_id; zfcp_fsf_start_erp_timer(req); retval = zfcp_fsf_req_send(req); if (retval) { zfcp_fsf_req_free(req); - erp_action->fsf_req = NULL; + erp_action->fsf_req_id = 0; } out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return retval; } @@ -2088,352 +1972,300 @@ static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat) lat_rec->max = max(lat_rec->max, lat); } -static void zfcp_fsf_req_latency(struct zfcp_fsf_req *req) -{ - struct fsf_qual_latency_info *lat_inf; - struct latency_cont *lat; - struct zfcp_unit *unit = req->unit; - - lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info; - - switch (req->qtcb->bottom.io.data_direction) { - case FSF_DATADIR_READ: - lat = &unit->latencies.read; - break; - case FSF_DATADIR_WRITE: - lat = &unit->latencies.write; - break; - case FSF_DATADIR_CMND: - lat = &unit->latencies.cmd; - break; - default: - return; - } - - spin_lock(&unit->latencies.lock); - zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat); - zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat); - lat->counter++; - spin_unlock(&unit->latencies.lock); -} - -#ifdef CONFIG_BLK_DEV_IO_TRACE -static void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req) -{ - struct fsf_qual_latency_info *lat_inf; - struct scsi_cmnd *scsi_cmnd = (struct scsi_cmnd *)fsf_req->data; - struct request *req = scsi_cmnd->request; - struct zfcp_blk_drv_data trace; - int ticks = fsf_req->adapter->timer_ticks; - - trace.flags = 0; - trace.magic = ZFCP_BLK_DRV_DATA_MAGIC; - if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) { - trace.flags |= ZFCP_BLK_LAT_VALID; - lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info; - trace.channel_lat = lat_inf->channel_lat * ticks; - trace.fabric_lat = lat_inf->fabric_lat * ticks; - } - if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) - trace.flags |= ZFCP_BLK_REQ_ERROR; - trace.inb_usage = fsf_req->queue_req.qdio_inb_usage; - trace.outb_usage = fsf_req->queue_req.qdio_outb_usage; - - blk_add_driver_data(req->q, req, &trace, sizeof(trace)); -} -#else -static inline void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req) -{ -} -#endif - -static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) +static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) { - struct scsi_cmnd *scpnt; - struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) - &(req->qtcb->bottom.io.fcp_rsp); - u32 sns_len; - char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; - unsigned long flags; - - read_lock_irqsave(&req->adapter->abort_lock, flags); - - scpnt = req->data; - if (unlikely(!scpnt)) { - read_unlock_irqrestore(&req->adapter->abort_lock, flags); - return; - } - - if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) { - set_host_byte(scpnt, DID_SOFT_ERROR); - goto skip_fsfstatus; - } - - if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { - set_host_byte(scpnt, DID_ERROR); - goto skip_fsfstatus; - } - - set_msg_byte(scpnt, COMMAND_COMPLETE); + struct fsf_qual_latency_info *lat_in; + struct latency_cont *lat = NULL; + struct zfcp_scsi_dev *zfcp_sdev; + struct zfcp_blk_drv_data blktrc; + int ticks = req->adapter->timer_ticks; - scpnt->result |= fcp_rsp_iu->scsi_status; + lat_in = &req->qtcb->prefix.prot_status_qual.latency_info; - if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) - zfcp_fsf_req_latency(req); - - zfcp_fsf_trace_latency(req); - - if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { - if (fcp_rsp_info[3] == RSP_CODE_GOOD) - set_host_byte(scpnt, DID_OK); - else { - set_host_byte(scpnt, DID_ERROR); - goto skip_fsfstatus; + blktrc.flags = 0; + blktrc.magic = ZFCP_BLK_DRV_DATA_MAGIC; + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) + blktrc.flags |= ZFCP_BLK_REQ_ERROR; + blktrc.inb_usage = 0; + blktrc.outb_usage = req->qdio_req.qdio_outb_usage; + + if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA && + !(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { + zfcp_sdev = sdev_to_zfcp(scsi->device); + blktrc.flags |= ZFCP_BLK_LAT_VALID; + blktrc.channel_lat = lat_in->channel_lat * ticks; + blktrc.fabric_lat = lat_in->fabric_lat * ticks; + + switch (req->qtcb->bottom.io.data_direction) { + case FSF_DATADIR_DIF_READ_STRIP: + case FSF_DATADIR_DIF_READ_CONVERT: + case FSF_DATADIR_READ: + lat = &zfcp_sdev->latencies.read; + break; + case FSF_DATADIR_DIF_WRITE_INSERT: + case FSF_DATADIR_DIF_WRITE_CONVERT: + case FSF_DATADIR_WRITE: + lat = &zfcp_sdev->latencies.write; + break; + case FSF_DATADIR_CMND: + lat = &zfcp_sdev->latencies.cmd; + break; } - } - - if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) { - sns_len = FSF_FCP_RSP_SIZE - sizeof(struct fcp_rsp_iu) + - fcp_rsp_iu->fcp_rsp_len; - sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE); - sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len); - - memcpy(scpnt->sense_buffer, - zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len); - } - if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) { - scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid); - if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) < - scpnt->underflow) - set_host_byte(scpnt, DID_ERROR); + if (lat) { + spin_lock(&zfcp_sdev->latencies.lock); + zfcp_fsf_update_lat(&lat->channel, lat_in->channel_lat); + zfcp_fsf_update_lat(&lat->fabric, lat_in->fabric_lat); + lat->counter++; + spin_unlock(&zfcp_sdev->latencies.lock); + } } -skip_fsfstatus: - if (scpnt->result != 0) - zfcp_dbf_scsi_result("erro", 3, req->adapter->dbf, scpnt, req); - else if (scpnt->retries > 0) - zfcp_dbf_scsi_result("retr", 4, req->adapter->dbf, scpnt, req); - else - zfcp_dbf_scsi_result("norm", 6, req->adapter->dbf, scpnt, req); - - scpnt->host_scribble = NULL; - (scpnt->scsi_done) (scpnt); - /* - * We must hold this lock until scsi_done has been called. - * Otherwise we may call scsi_done after abort regarding this - * command has completed. - * Note: scsi_done must not block! - */ - read_unlock_irqrestore(&req->adapter->abort_lock, flags); -} - -static void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req) -{ - struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) - &(req->qtcb->bottom.io.fcp_rsp); - char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; - if ((fcp_rsp_info[3] != RSP_CODE_GOOD) || - (req->status & ZFCP_STATUS_FSFREQ_ERROR)) - req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; + blk_add_driver_data(scsi->request->q, scsi->request, &blktrc, + sizeof(blktrc)); } - -static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req) +static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) { - struct zfcp_unit *unit; + struct scsi_cmnd *scmnd = req->data; + struct scsi_device *sdev = scmnd->device; + struct zfcp_scsi_dev *zfcp_sdev; struct fsf_qtcb_header *header = &req->qtcb->header; - if (unlikely(req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)) - unit = req->data; - else - unit = req->unit; - if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) - goto skip_fsfstatus; + return; + + zfcp_sdev = sdev_to_zfcp(sdev); switch (header->fsf_status) { case FSF_HANDLE_MISMATCH: case FSF_PORT_HANDLE_NOT_VALID: - zfcp_erp_adapter_reopen(unit->port->adapter, 0, "fssfch1", req); + zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fssfch1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_FCPLUN_NOT_VALID: case FSF_LUN_HANDLE_NOT_VALID: - zfcp_erp_port_reopen(unit->port, 0, "fssfch2", req); + zfcp_erp_port_reopen(zfcp_sdev->port, 0, "fssfch2"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: zfcp_fsf_class_not_supp(req); break; - case FSF_ACCESS_DENIED: - zfcp_fsf_access_denied_unit(req, unit); - break; case FSF_DIRECTION_INDICATOR_NOT_VALID: dev_err(&req->adapter->ccw_device->dev, - "Incorrect direction %d, unit 0x%016Lx on port " + "Incorrect direction %d, LUN 0x%016Lx on port " "0x%016Lx closed\n", req->qtcb->bottom.io.data_direction, - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch3", - req); + (unsigned long long)zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0, + "fssfch3"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_CMND_LENGTH_NOT_VALID: dev_err(&req->adapter->ccw_device->dev, - "Incorrect CDB length %d, unit 0x%016Lx on " + "Incorrect CDB length %d, LUN 0x%016Lx on " "port 0x%016Lx closed\n", req->qtcb->bottom.io.fcp_cmnd_length, - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_adapter_shutdown(unit->port->adapter, 0, "fssfch4", - req); + (unsigned long long)zfcp_scsi_dev_lun(sdev), + (unsigned long long)zfcp_sdev->port->wwpn); + zfcp_erp_adapter_shutdown(zfcp_sdev->port->adapter, 0, + "fssfch4"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PORT_BOXED: - zfcp_erp_port_boxed(unit->port, "fssfch5", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + zfcp_erp_set_port_status(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_port_reopen(zfcp_sdev->port, + ZFCP_STATUS_COMMON_ERP_FAILED, "fssfch5"); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_BOXED: - zfcp_erp_unit_boxed(unit, "fssfch6", req); - req->status |= ZFCP_STATUS_FSFREQ_ERROR | - ZFCP_STATUS_FSFREQ_RETRY; + zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ACCESS_BOXED); + zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, + "fssfch6"); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_ADAPTER_STATUS_AVAILABLE: if (header->fsf_status_qual.word[0] == FSF_SQ_INVOKE_LINK_TEST_PROCEDURE) - zfcp_fc_test_link(unit->port); + zfcp_fc_test_link(zfcp_sdev->port); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } -skip_fsfstatus: - if (req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) - zfcp_fsf_send_fcp_ctm_handler(req); - else { - zfcp_fsf_send_fcp_command_task_handler(req); - req->unit = NULL; - zfcp_unit_put(unit); - } } -static void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, u32 fcp_dl) +static void zfcp_fsf_fcp_cmnd_handler(struct zfcp_fsf_req *req) { - u32 *fcp_dl_ptr; + struct scsi_cmnd *scpnt; + struct fcp_resp_with_ext *fcp_rsp; + unsigned long flags; + + read_lock_irqsave(&req->adapter->abort_lock, flags); + + scpnt = req->data; + if (unlikely(!scpnt)) { + read_unlock_irqrestore(&req->adapter->abort_lock, flags); + return; + } + + zfcp_fsf_fcp_handler_common(req); + + if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { + set_host_byte(scpnt, DID_TRANSPORT_DISRUPTED); + goto skip_fsfstatus; + } + + switch (req->qtcb->header.fsf_status) { + case FSF_INCONSISTENT_PROT_DATA: + case FSF_INVALID_PROT_PARM: + set_host_byte(scpnt, DID_ERROR); + goto skip_fsfstatus; + case FSF_BLOCK_GUARD_CHECK_FAILURE: + zfcp_scsi_dif_sense_error(scpnt, 0x1); + goto skip_fsfstatus; + case FSF_APP_TAG_CHECK_FAILURE: + zfcp_scsi_dif_sense_error(scpnt, 0x2); + goto skip_fsfstatus; + case FSF_REF_TAG_CHECK_FAILURE: + zfcp_scsi_dif_sense_error(scpnt, 0x3); + goto skip_fsfstatus; + } + fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp; + zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt); +skip_fsfstatus: + zfcp_fsf_req_trace(req, scpnt); + zfcp_dbf_scsi_result(scpnt, req); + + scpnt->host_scribble = NULL; + (scpnt->scsi_done) (scpnt); /* - * fcp_dl_addr = start address of fcp_cmnd structure + - * size of fixed part + size of dynamically sized add_dcp_cdb field - * SEE FCP-2 documentation + * We must hold this lock until scsi_done has been called. + * Otherwise we may call scsi_done after abort regarding this + * command has completed. + * Note: scsi_done must not block! */ - fcp_dl_ptr = (u32 *) ((unsigned char *) &fcp_cmd[1] + - (fcp_cmd->add_fcp_cdb_length << 2)); - *fcp_dl_ptr = fcp_dl; + read_unlock_irqrestore(&req->adapter->abort_lock, flags); +} + +static int zfcp_fsf_set_data_dir(struct scsi_cmnd *scsi_cmnd, u32 *data_dir) +{ + switch (scsi_get_prot_op(scsi_cmnd)) { + case SCSI_PROT_NORMAL: + switch (scsi_cmnd->sc_data_direction) { + case DMA_NONE: + *data_dir = FSF_DATADIR_CMND; + break; + case DMA_FROM_DEVICE: + *data_dir = FSF_DATADIR_READ; + break; + case DMA_TO_DEVICE: + *data_dir = FSF_DATADIR_WRITE; + break; + case DMA_BIDIRECTIONAL: + return -EINVAL; + } + break; + + case SCSI_PROT_READ_STRIP: + *data_dir = FSF_DATADIR_DIF_READ_STRIP; + break; + case SCSI_PROT_WRITE_INSERT: + *data_dir = FSF_DATADIR_DIF_WRITE_INSERT; + break; + case SCSI_PROT_READ_PASS: + *data_dir = FSF_DATADIR_DIF_READ_CONVERT; + break; + case SCSI_PROT_WRITE_PASS: + *data_dir = FSF_DATADIR_DIF_WRITE_CONVERT; + break; + default: + return -EINVAL; + } + + return 0; } /** - * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) - * @unit: unit where command is sent to + * zfcp_fsf_fcp_cmnd - initiate an FCP command (for a SCSI command) * @scsi_cmnd: scsi command to be sent */ -int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, - struct scsi_cmnd *scsi_cmnd) +int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) { struct zfcp_fsf_req *req; - struct fcp_cmnd_iu *fcp_cmnd_iu; - unsigned int sbtype = SBAL_FLAGS0_TYPE_READ; - int real_bytes, retval = -EIO; - struct zfcp_adapter *adapter = unit->port->adapter; + struct fcp_cmnd *fcp_cmnd; + u8 sbtype = SBAL_SFLAGS0_TYPE_READ; + int retval = -EIO; + struct scsi_device *sdev = scsi_cmnd->device; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; struct zfcp_qdio *qdio = adapter->qdio; + struct fsf_qtcb_bottom_io *io; + unsigned long flags; - if (unlikely(!(atomic_read(&unit->status) & + if (unlikely(!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) return -EBUSY; - spin_lock(&qdio->req_q_lock); - if (atomic_read(&qdio->req_q.count) <= 0) { + spin_lock_irqsave(&qdio->req_q_lock, flags); + if (atomic_read(&qdio->req_q_free) <= 0) { atomic_inc(&qdio->req_q_full); goto out; } + if (scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) + sbtype = SBAL_SFLAGS0_TYPE_WRITE; + req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND, - adapter->pool.scsi_req); + sbtype, adapter->pool.scsi_req); if (IS_ERR(req)) { retval = PTR_ERR(req); goto out; } + scsi_cmnd->host_scribble = (unsigned char *) req->req_id; + + io = &req->qtcb->bottom.io; req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - zfcp_unit_get(unit); - req->unit = unit; req->data = scsi_cmnd; - req->handler = zfcp_fsf_send_fcp_command_handler; - req->qtcb->header.lun_handle = unit->handle; - req->qtcb->header.port_handle = unit->port->handle; - req->qtcb->bottom.io.service_class = FSF_CLASS_3; - - scsi_cmnd->host_scribble = (unsigned char *) req->req_id; + req->handler = zfcp_fsf_fcp_cmnd_handler; + req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; + req->qtcb->header.port_handle = zfcp_sdev->port->handle; + io->service_class = FSF_CLASS_3; + io->fcp_cmnd_length = FCP_CMND_LEN; - fcp_cmnd_iu = (struct fcp_cmnd_iu *) &(req->qtcb->bottom.io.fcp_cmnd); - fcp_cmnd_iu->fcp_lun = unit->fcp_lun; - /* - * set depending on data direction: - * data direction bits in SBALE (SB Type) - * data direction bits in QTCB - * data direction bits in FCP_CMND IU - */ - switch (scsi_cmnd->sc_data_direction) { - case DMA_NONE: - req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; - break; - case DMA_FROM_DEVICE: - req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ; - fcp_cmnd_iu->rddata = 1; - break; - case DMA_TO_DEVICE: - req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE; - sbtype = SBAL_FLAGS0_TYPE_WRITE; - fcp_cmnd_iu->wddata = 1; - break; - case DMA_BIDIRECTIONAL: - goto failed_scsi_cmnd; + if (scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) { + io->data_block_length = scsi_cmnd->device->sector_size; + io->ref_tag_value = scsi_get_lba(scsi_cmnd) & 0xFFFFFFFF; } - if (likely((scsi_cmnd->device->simple_tags) || - ((atomic_read(&unit->status) & ZFCP_STATUS_UNIT_READONLY) && - (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_SHARED)))) - fcp_cmnd_iu->task_attribute = SIMPLE_Q; - else - fcp_cmnd_iu->task_attribute = UNTAGGED; - - if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) - fcp_cmnd_iu->add_fcp_cdb_length = - (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2; + if (zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction)) + goto failed_scsi_cmnd; - memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); + fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; + zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd, 0); - req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + - fcp_cmnd_iu->add_fcp_cdb_length + sizeof(u32); + if (scsi_prot_sg_count(scsi_cmnd)) { + zfcp_qdio_set_data_div(qdio, &req->qdio_req, + scsi_prot_sg_count(scsi_cmnd)); + retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, + scsi_prot_sglist(scsi_cmnd)); + if (retval) + goto failed_scsi_cmnd; + io->prot_data_length = zfcp_qdio_real_bytes( + scsi_prot_sglist(scsi_cmnd)); + } - real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->queue_req, sbtype, - scsi_sglist(scsi_cmnd), - FSF_MAX_SBALS_PER_REQ); - if (unlikely(real_bytes < 0)) { - if (req->queue_req.sbal_number >= FSF_MAX_SBALS_PER_REQ) { - dev_err(&adapter->ccw_device->dev, - "Oversize data package, unit 0x%016Lx " - "on port 0x%016Lx closed\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_shutdown(unit, 0, "fssfct1", req); - retval = -EINVAL; - } + retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, + scsi_sglist(scsi_cmnd)); + if (unlikely(retval)) goto failed_scsi_cmnd; - } - zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes); + zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); + if (zfcp_adapter_multi_buffer_active(adapter)) + zfcp_qdio_set_scount(qdio, &req->qdio_req); retval = zfcp_fsf_req_send(req); if (unlikely(retval)) @@ -2442,36 +2274,52 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, goto out; failed_scsi_cmnd: - zfcp_unit_put(unit); zfcp_fsf_req_free(req); scsi_cmnd->host_scribble = NULL; out: - spin_unlock(&qdio->req_q_lock); + spin_unlock_irqrestore(&qdio->req_q_lock, flags); return retval; } +static void zfcp_fsf_fcp_task_mgmt_handler(struct zfcp_fsf_req *req) +{ + struct fcp_resp_with_ext *fcp_rsp; + struct fcp_resp_rsp_info *rsp_info; + + zfcp_fsf_fcp_handler_common(req); + + fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp; + rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1]; + + if ((rsp_info->rsp_code != FCP_TMF_CMPL) || + (req->status & ZFCP_STATUS_FSFREQ_ERROR)) + req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; +} + /** - * zfcp_fsf_send_fcp_ctm - send SCSI task management command - * @unit: pointer to struct zfcp_unit + * zfcp_fsf_fcp_task_mgmt - send SCSI task management command + * @scmnd: SCSI command to send the task management command for * @tm_flags: unsigned byte for task management flags * Returns: on success pointer to struct fsf_req, NULL otherwise */ -struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) +struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd, + u8 tm_flags) { - struct qdio_buffer_element *sbale; struct zfcp_fsf_req *req = NULL; - struct fcp_cmnd_iu *fcp_cmnd_iu; - struct zfcp_qdio *qdio = unit->port->adapter->qdio; + struct fcp_cmnd *fcp_cmnd; + struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scmnd->device); + struct zfcp_qdio *qdio = zfcp_sdev->port->adapter->qdio; - if (unlikely(!(atomic_read(&unit->status) & + if (unlikely(!(atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) return NULL; - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) + spin_lock_irq(&qdio->req_q_lock); + if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND, + SBAL_SFLAGS0_TYPE_WRITE, qdio->adapter->pool.scsi_req); if (IS_ERR(req)) { @@ -2479,23 +2327,18 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) goto out; } - req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT; - req->data = unit; - req->handler = zfcp_fsf_send_fcp_command_handler; - req->qtcb->header.lun_handle = unit->handle; - req->qtcb->header.port_handle = unit->port->handle; + req->data = scmnd; + req->handler = zfcp_fsf_fcp_task_mgmt_handler; + req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; + req->qtcb->header.port_handle = zfcp_sdev->port->handle; req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; req->qtcb->bottom.io.service_class = FSF_CLASS_3; - req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + - sizeof(u32); + req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN; - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; - sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); - fcp_cmnd_iu = (struct fcp_cmnd_iu *) &req->qtcb->bottom.io.fcp_cmnd; - fcp_cmnd_iu->fcp_lun = unit->fcp_lun; - fcp_cmnd_iu->task_management_flags = tm_flags; + fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; + zfcp_fc_scsi_to_fcp(fcp_cmnd, scmnd, tm_flags); zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); if (!zfcp_fsf_req_send(req)) @@ -2504,82 +2347,10 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) zfcp_fsf_req_free(req); req = NULL; out: - spin_unlock_bh(&qdio->req_q_lock); + spin_unlock_irq(&qdio->req_q_lock); return req; } -static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req) -{ -} - -/** - * zfcp_fsf_control_file - control file upload/download - * @adapter: pointer to struct zfcp_adapter - * @fsf_cfdc: pointer to struct zfcp_fsf_cfdc - * Returns: on success pointer to struct zfcp_fsf_req, NULL otherwise - */ -struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, - struct zfcp_fsf_cfdc *fsf_cfdc) -{ - struct qdio_buffer_element *sbale; - struct zfcp_qdio *qdio = adapter->qdio; - struct zfcp_fsf_req *req = NULL; - struct fsf_qtcb_bottom_support *bottom; - int direction, retval = -EIO, bytes; - - if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) - return ERR_PTR(-EOPNOTSUPP); - - switch (fsf_cfdc->command) { - case FSF_QTCB_DOWNLOAD_CONTROL_FILE: - direction = SBAL_FLAGS0_TYPE_WRITE; - break; - case FSF_QTCB_UPLOAD_CONTROL_FILE: - direction = SBAL_FLAGS0_TYPE_READ; - break; - default: - return ERR_PTR(-EINVAL); - } - - spin_lock_bh(&qdio->req_q_lock); - if (zfcp_fsf_req_sbal_get(qdio)) - goto out; - - req = zfcp_fsf_req_create(qdio, fsf_cfdc->command, NULL); - if (IS_ERR(req)) { - retval = -EPERM; - goto out; - } - - req->handler = zfcp_fsf_control_file_handler; - - sbale = zfcp_qdio_sbale_req(qdio, &req->queue_req); - sbale[0].flags |= direction; - - bottom = &req->qtcb->bottom.support; - bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; - bottom->option = fsf_cfdc->option; - - bytes = zfcp_qdio_sbals_from_sg(qdio, &req->queue_req, - direction, fsf_cfdc->sg, - FSF_MAX_SBALS_PER_REQ); - if (bytes != ZFCP_CFDC_MAX_SIZE) { - zfcp_fsf_req_free(req); - goto out; - } - - zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); - retval = zfcp_fsf_req_send(req); -out: - spin_unlock_bh(&qdio->req_q_lock); - - if (!retval) { - wait_for_completion(&req->completion); - return req; - } - return ERR_PTR(retval); -} - /** * zfcp_fsf_reqid_check - validate req_id contained in SBAL returned by QDIO * @adapter: pointer to struct zfcp_adapter @@ -2588,36 +2359,32 @@ out: void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx) { struct zfcp_adapter *adapter = qdio->adapter; - struct qdio_buffer *sbal = qdio->resp_q.sbal[sbal_idx]; + struct qdio_buffer *sbal = qdio->res_q[sbal_idx]; struct qdio_buffer_element *sbale; struct zfcp_fsf_req *fsf_req; - unsigned long flags, req_id; + unsigned long req_id; int idx; for (idx = 0; idx < QDIO_MAX_ELEMENTS_PER_BUFFER; idx++) { sbale = &sbal->element[idx]; req_id = (unsigned long) sbale->addr; - spin_lock_irqsave(&adapter->req_list_lock, flags); - fsf_req = zfcp_reqlist_find(adapter, req_id); + fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id); - if (!fsf_req) + if (!fsf_req) { /* * Unknown request means that we have potentially memory * corruption and must stop the machine immediately. */ + zfcp_qdio_siosl(adapter); panic("error: unknown req_id (%lx) on adapter %s.\n", req_id, dev_name(&adapter->ccw_device->dev)); + } - list_del(&fsf_req->list); - spin_unlock_irqrestore(&adapter->req_list_lock, flags); - - fsf_req->queue_req.sbal_response = sbal_idx; - fsf_req->queue_req.qdio_inb_usage = - atomic_read(&qdio->resp_q.count); + fsf_req->qdio_req.sbal_response = sbal_idx; zfcp_fsf_req_complete(fsf_req); - if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY)) + if (likely(sbale->eflags & SBAL_EFLAGS_LAST_ENTRY)) break; } } |
