diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_fsf.c')
| -rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 324 |
1 files changed, 143 insertions, 181 deletions
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 8512b5c0ef8..0fe8d5d9511 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -3,7 +3,7 @@ * * Implementation of FSF commands. * - * Copyright IBM Corporation 2002, 2010 + * Copyright IBM Corp. 2002, 2013 */ #define KMSG_COMPONENT "zfcp" @@ -219,7 +219,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) return; } - zfcp_dbf_hba_fsf_uss("fssrh_2", req); + zfcp_dbf_hba_fsf_uss("fssrh_4", req); switch (sr_buf->status_type) { case FSF_STATUS_READ_PORT_CLOSED: @@ -254,13 +254,8 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) break; case FSF_STATUS_READ_NOTIFICATION_LOST: - if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) - zfcp_cfdc_adapter_access_changed(adapter); if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) - queue_work(adapter->work_queue, &adapter->scan_work); - break; - case FSF_STATUS_READ_CFDC_UPDATED: - zfcp_cfdc_adapter_access_changed(adapter); + zfcp_fc_conditional_port_scan(adapter); break; case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: adapter->adapter_features = sr_buf->payload.word[0]; @@ -437,6 +432,34 @@ 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 = &req->qtcb->bottom.config; @@ -455,11 +478,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) fc_host_port_name(shost) = nsp->fl_wwpn; fc_host_node_name(shost) = nsp->fl_wwnn; - fc_host_port_id(shost) = ntoh24(bottom->s_id); - fc_host_speed(shost) = bottom->fc_link_speed; fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; - adapter->hydra_version = bottom->adapter_type; 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); @@ -467,6 +487,19 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) 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 = ntoh24(bottom->peer_d_id); @@ -488,8 +521,6 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) return -EIO; } - zfcp_scsi_set_prot(adapter); - return 0; } @@ -534,8 +565,14 @@ 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, &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"); @@ -580,7 +617,8 @@ 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, @@ -640,7 +678,7 @@ 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, u32 sbtype, + u32 fsf_cmd, u8 sbtype, mempool_t *pool) { struct zfcp_adapter *adapter = qdio->adapter; @@ -697,7 +735,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) zfcp_reqlist_add(adapter->req_list, req); req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free); - req->issued = get_clock(); + req->issued = get_tod_clock(); if (zfcp_qdio_send(qdio, &req->qdio_req)) { del_timer(&req->timer); /* lookup request again, list might have changed */ @@ -732,7 +770,8 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio) if (zfcp_qdio_sbal_get(qdio)) goto out; - req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS, 0, + 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); @@ -771,12 +810,14 @@ out: static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) { struct scsi_device *sdev = req->data; - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + 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]) { @@ -841,7 +882,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd) if (zfcp_qdio_sbal_get(qdio)) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_ABORT_FCP_CMND, - SBAL_FLAGS0_TYPE_READ, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.scsi_abort); if (IS_ERR(req)) { req = NULL; @@ -885,7 +926,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) switch (header->fsf_status) { case FSF_GOOD: - zfcp_dbf_san_res("fsscth1", req); + zfcp_dbf_san_res("fsscth2", req); ct->status = 0; break; case FSF_SERVICE_CLASS_NOT_SUPPORTED: @@ -899,8 +940,6 @@ 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; break; @@ -936,39 +975,47 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, struct scatterlist *sg_resp) { struct zfcp_adapter *adapter = req->adapter; + 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_qdio_sg_one_sbale(sg_req) || - !zfcp_qdio_sg_one_sbale(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(adapter->qdio, &req->qdio_req, - 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_qdio_sg_one_sbale(sg_req) && zfcp_qdio_sg_one_sbale(sg_resp)) { - zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req, + 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->qdio_req, sg_req); - 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; - zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); - req->qtcb->bottom.support.req_buf_length = bytes; - zfcp_qdio_skip_to_last_sbale(&req->qdio_req); - bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, - sg_resp); - req->qtcb->bottom.support.resp_buf_length = bytes; - 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; - zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); + + qtcb->bottom.support.resp_buf_length = zfcp_qdio_real_bytes(sg_resp); + + zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); return 0; } @@ -1012,7 +1059,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port, goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC, - SBAL_FLAGS0_TYPE_WRITE_READ, pool); + SBAL_SFLAGS0_TYPE_WRITE_READ, pool); if (IS_ERR(req)) { ret = PTR_ERR(req); @@ -1046,7 +1093,6 @@ out: static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) { struct zfcp_fsf_ct_els *send_els = req->data; - struct zfcp_port *port = send_els->port; struct fsf_qtcb_header *header = &req->qtcb->header; send_els->status = -EINVAL; @@ -1076,12 +1122,6 @@ 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_cfdc_port_denied(port, &header->fsf_status_qual); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - } - break; case FSF_SBAL_MISMATCH: /* should never occur, avoided in zfcp_fsf_send_els */ /* fall through */ @@ -1110,7 +1150,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS, - SBAL_FLAGS0_TYPE_WRITE_READ, NULL); + SBAL_SFLAGS0_TYPE_WRITE_READ, NULL); if (IS_ERR(req)) { ret = PTR_ERR(req); @@ -1119,7 +1159,8 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 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); @@ -1156,7 +1197,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, - SBAL_FLAGS0_TYPE_READ, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1168,8 +1209,6 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) 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; @@ -1198,7 +1237,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, goto out_unlock; req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, - SBAL_FLAGS0_TYPE_READ, NULL); + SBAL_SFLAGS0_TYPE_READ, NULL); if (IS_ERR(req)) { retval = PTR_ERR(req); @@ -1209,8 +1248,6 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, 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; @@ -1250,7 +1287,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, - SBAL_FLAGS0_TYPE_READ, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1296,7 +1333,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, goto out_unlock; req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, - SBAL_FLAGS0_TYPE_READ, NULL); + SBAL_SFLAGS0_TYPE_READ, NULL); if (IS_ERR(req)) { retval = PTR_ERR(req); @@ -1337,10 +1374,6 @@ 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_cfdc_port_denied(port, &header->fsf_status_qual); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: dev_warn(&req->adapter->ccw_device->dev, "Not enough FCP adapter resources to open " @@ -1412,7 +1445,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID, - SBAL_FLAGS0_TYPE_READ, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1478,7 +1511,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT, - SBAL_FLAGS0_TYPE_READ, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1523,8 +1556,6 @@ 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_FC_WKA_PORT_OFFLINE; break; case FSF_GOOD: @@ -1553,7 +1584,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID, - SBAL_FLAGS0_TYPE_READ, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1606,7 +1637,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT, - SBAL_FLAGS0_TYPE_READ, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1644,9 +1675,6 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) zfcp_erp_adapter_reopen(port->adapter, 0, "fscpph1"); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; - case FSF_ACCESS_DENIED: - zfcp_cfdc_port_denied(port, &header->fsf_status_qual); - 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 */ @@ -1698,7 +1726,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PHYSICAL_PORT, - SBAL_FLAGS0_TYPE_READ, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1730,17 +1758,17 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; struct scsi_device *sdev = req->data; - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_scsi_dev *zfcp_sdev; struct fsf_qtcb_header *header = &req->qtcb->header; - struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support; + 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_LUN_SHARED | - ZFCP_STATUS_LUN_READONLY, + ZFCP_STATUS_COMMON_ACCESS_BOXED, &zfcp_sdev->status); switch (header->fsf_status) { @@ -1750,10 +1778,6 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) /* fall through */ case FSF_LUN_ALREADY_OPEN: break; - case FSF_ACCESS_DENIED: - zfcp_cfdc_lun_denied(sdev, &header->fsf_status_qual); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; case FSF_PORT_BOXED: zfcp_erp_set_port_status(zfcp_sdev->port, ZFCP_STATUS_COMMON_ACCESS_BOXED); @@ -1762,7 +1786,17 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_LUN_SHARING_VIOLATION: - zfcp_cfdc_lun_shrng_vltn(sdev, &header->fsf_status_qual); + 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", + 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: @@ -1790,7 +1824,6 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) case FSF_GOOD: zfcp_sdev->lun_handle = header->lun_handle; atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); - zfcp_cfdc_open_lun_eval(sdev, bottom); break; } } @@ -1812,7 +1845,7 @@ int zfcp_fsf_open_lun(struct zfcp_erp_action *erp_action) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_LUN, - SBAL_FLAGS0_TYPE_READ, + SBAL_SFLAGS0_TYPE_READ, adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1847,11 +1880,13 @@ out: static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) { struct scsi_device *sdev = req->data; - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + 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(zfcp_sdev->port->adapter, 0, "fscuh_1"); @@ -1901,7 +1936,7 @@ int zfcp_fsf_close_lun(struct zfcp_erp_action *erp_action) goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_LUN, - SBAL_FLAGS0_TYPE_READ, + SBAL_SFLAGS0_TYPE_READ, qdio->adapter->pool.erp_req); if (IS_ERR(req)) { @@ -1941,7 +1976,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) { struct fsf_qual_latency_info *lat_in; struct latency_cont *lat = NULL; - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scsi->device); + struct zfcp_scsi_dev *zfcp_sdev; struct zfcp_blk_drv_data blktrc; int ticks = req->adapter->timer_ticks; @@ -1956,6 +1991,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) 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; @@ -1993,12 +2029,14 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) { struct scsi_cmnd *scmnd = req->data; struct scsi_device *sdev = scmnd->device; - struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + struct zfcp_scsi_dev *zfcp_sdev; struct fsf_qtcb_header *header = &req->qtcb->header; if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) return; + zfcp_sdev = sdev_to_zfcp(sdev); + switch (header->fsf_status) { case FSF_HANDLE_MISMATCH: case FSF_PORT_HANDLE_NOT_VALID: @@ -2013,10 +2051,6 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) case FSF_SERVICE_CLASS_NOT_SUPPORTED: zfcp_fsf_class_not_supp(req); break; - case FSF_ACCESS_DENIED: - zfcp_cfdc_lun_denied(sdev, &header->fsf_status_qual); - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; case FSF_DIRECTION_INDICATOR_NOT_VALID: dev_err(&req->adapter->ccw_device->dev, "Incorrect direction %d, LUN 0x%016Lx on port " @@ -2161,8 +2195,8 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) { struct zfcp_fsf_req *req; struct fcp_cmnd *fcp_cmnd; - unsigned int sbtype = SBAL_FLAGS0_TYPE_READ; - int real_bytes, retval = -EIO, dix_bytes = 0; + 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; @@ -2181,7 +2215,7 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) } if (scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) - sbtype = SBAL_FLAGS0_TYPE_WRITE; + sbtype = SBAL_SFLAGS0_TYPE_WRITE; req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND, sbtype, adapter->pool.scsi_req); @@ -2207,7 +2241,8 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) io->ref_tag_value = scsi_get_lba(scsi_cmnd) & 0xFFFFFFFF; } - zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction); + if (zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction)) + goto failed_scsi_cmnd; fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd, 0); @@ -2215,18 +2250,22 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) if (scsi_prot_sg_count(scsi_cmnd)) { zfcp_qdio_set_data_div(qdio, &req->qdio_req, scsi_prot_sg_count(scsi_cmnd)); - dix_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, + 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)); - io->prot_data_length = dix_bytes; } - real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, - scsi_sglist(scsi_cmnd)); - - if (unlikely(real_bytes < 0) || unlikely(dix_bytes < 0)) + retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, + scsi_sglist(scsi_cmnd)); + if (unlikely(retval)) goto failed_scsi_cmnd; 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)) @@ -2280,7 +2319,7 @@ struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd, goto out; req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND, - SBAL_FLAGS0_TYPE_WRITE, + SBAL_SFLAGS0_TYPE_WRITE, qdio->adapter->pool.scsi_req); if (IS_ERR(req)) { @@ -2312,74 +2351,6 @@ out: 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 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_irq(&qdio->req_q_lock); - if (zfcp_qdio_sbal_get(qdio)) - goto out; - - req = zfcp_fsf_req_create(qdio, fsf_cfdc->command, direction, NULL); - if (IS_ERR(req)) { - retval = -EPERM; - goto out; - } - - req->handler = zfcp_fsf_control_file_handler; - - 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->qdio_req, fsf_cfdc->sg); - - if (bytes != ZFCP_CFDC_MAX_SIZE) { - zfcp_fsf_req_free(req); - goto out; - } - zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); - - zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); - retval = zfcp_fsf_req_send(req); -out: - spin_unlock_irq(&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 @@ -2413,16 +2384,7 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx) 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; } } - -struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *qdio, - struct qdio_buffer *sbal) -{ - struct qdio_buffer_element *sbale = &sbal->element[0]; - u64 req_id = (unsigned long) sbale->addr; - - return zfcp_reqlist_find(qdio->adapter->req_list, req_id); -} |
