/** * zfcp_status_read_refill - refill the long running status_read_requests * @adapter: ptr to struct zfcp_adapter for which the buffers should be refilled * * Returns: 0 on success, 1 otherwise * * if there are 16 or more status_read requests missing an adapter_reopen * is triggered */ int zfcp_status_read_refill(struct zfcp_adapter *adapter) { while (atomic_read(&adapter->stat_miss) > 0) if (zfcp_fsf_status_read(adapter->qdio)) { if (atomic_read(&adapter->stat_miss) >= adapter->stat_read_buf_num) { zfcp_erp_adapter_reopen(adapter, 0, "axsref1"); return 1; } break; } else atomic_dec(&adapter->stat_miss); return 0; }
static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; int ret; zfcp_erp_adapter_reopen(adapter, 0, "schrh_1"); zfcp_erp_wait(adapter); ret = fc_block_scsi_eh(scpnt); if (ret) return ret; return SUCCESS; }
static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, int queue_no, int idx, int count, unsigned long parm) { struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; struct zfcp_adapter *adapter = qdio->adapter; int sbal_no, sbal_idx; if (unlikely(qdio_err)) { if (zfcp_adapter_multi_buffer_active(adapter)) { void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1]; struct qdio_buffer_element *sbale; u64 req_id; u8 scount; memset(pl, 0, ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *)); sbale = qdio->res_q[idx]->element; req_id = (u64) sbale->addr; scount = min(sbale->scount + 1, ZFCP_QDIO_MAX_SBALS_PER_REQ + 1); /* incl. signaling SBAL */ for (sbal_no = 0; sbal_no < scount; sbal_no++) { sbal_idx = (idx + sbal_no) % QDIO_MAX_BUFFERS_PER_Q; pl[sbal_no] = qdio->res_q[sbal_idx]; } zfcp_dbf_hba_def_err(adapter, req_id, scount, pl); } zfcp_qdio_handler_error(qdio, "qdires1", qdio_err); return; } /* * go through all SBALs from input queue currently * returned by QDIO layer */ for (sbal_no = 0; sbal_no < count; sbal_no++) { sbal_idx = (idx + sbal_no) % QDIO_MAX_BUFFERS_PER_Q; /* go through all SBALEs of SBAL */ zfcp_fsf_reqid_check(qdio, sbal_idx); } /* * put SBALs back to response queue */ if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count)) zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2"); }
static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id, unsigned int qdio_err) { struct zfcp_adapter *adapter = qdio->adapter; dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n"); if (qdio_err & QDIO_ERROR_SLSB_STATE) { zfcp_qdio_siosl(adapter); zfcp_erp_adapter_shutdown(adapter, 0, id); return; } zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED, id); }
/** * zfcp_qdio_sbal_get - get free sbal in request queue, wait if necessary * @qdio: pointer to struct zfcp_qdio * * The req_q_lock must be held by the caller of this function, and * this function may only be called from process context; it will * sleep when waiting for a free sbal. * * Returns: 0 on success, -EIO if there is no free sbal after waiting. */ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio) { long ret; ret = wait_event_interruptible_lock_irq_timeout(qdio->req_q_wq, zfcp_qdio_sbal_check(qdio), qdio->req_q_lock, 5 * HZ); if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) return -EIO; if (ret > 0) return 0; if (!ret) { atomic_inc(&qdio->req_q_full); /* assume hanging outbound queue, try queue recovery */ zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1"); } return -EIO; }
static void zfcp_scsi_forget_cmnds(struct zfcp_scsi_dev *zsdev, u8 tm_flags) { struct zfcp_adapter *adapter = zsdev->port->adapter; struct zfcp_scsi_req_filter filter = { .tmf_scope = FCP_TMF_TGT_RESET, .port_handle = zsdev->port->handle, }; unsigned long flags; if (tm_flags == FCP_TMF_LUN_RESET) { filter.tmf_scope = FCP_TMF_LUN_RESET; filter.lun_handle = zsdev->lun_handle; } /* * abort_lock secures against other processings - in the abort-function * and normal cmnd-handler - of (struct zfcp_fsf_req *)->data */ write_lock_irqsave(&adapter->abort_lock, flags); zfcp_reqlist_apply_for_all(adapter->req_list, zfcp_scsi_forget_cmnd, &filter); write_unlock_irqrestore(&adapter->abort_lock, flags); } /** * zfcp_scsi_task_mgmt_function() - Send a task management function (sync). * @sdev: Pointer to SCSI device to send the task management command to. * @tm_flags: Task management flags, * here we only handle %FCP_TMF_TGT_RESET or %FCP_TMF_LUN_RESET. */ static int zfcp_scsi_task_mgmt_function(struct scsi_device *sdev, u8 tm_flags) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); struct zfcp_fsf_req *fsf_req = NULL; int retval = SUCCESS, ret; int retry = 3; while (retry--) { fsf_req = zfcp_fsf_fcp_task_mgmt(sdev, tm_flags); if (fsf_req) break; zfcp_dbf_scsi_devreset("wait", sdev, tm_flags, NULL); zfcp_erp_wait(adapter); ret = fc_block_rport(rport); if (ret) { zfcp_dbf_scsi_devreset("fiof", sdev, tm_flags, NULL); return ret; } if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) { zfcp_dbf_scsi_devreset("nres", sdev, tm_flags, NULL); return SUCCESS; } } if (!fsf_req) { zfcp_dbf_scsi_devreset("reqf", sdev, tm_flags, NULL); return FAILED; } wait_for_completion(&fsf_req->completion); if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { zfcp_dbf_scsi_devreset("fail", sdev, tm_flags, fsf_req); retval = FAILED; } else { zfcp_dbf_scsi_devreset("okay", sdev, tm_flags, fsf_req); zfcp_scsi_forget_cmnds(zfcp_sdev, tm_flags); } zfcp_fsf_req_free(fsf_req); return retval; } static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) { struct scsi_device *sdev = scpnt->device; return zfcp_scsi_task_mgmt_function(sdev, FCP_TMF_LUN_RESET); } static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) { struct scsi_target *starget = scsi_target(scpnt->device); struct fc_rport *rport = starget_to_rport(starget); struct Scsi_Host *shost = rport_to_shost(rport); struct scsi_device *sdev = NULL, *tmp_sdev; struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0]; int ret; shost_for_each_device(tmp_sdev, shost) { if (tmp_sdev->id == starget->id) { sdev = tmp_sdev; break; } } if (!sdev) { ret = FAILED; zfcp_dbf_scsi_eh("tr_nosd", adapter, starget->id, ret); return ret; } ret = zfcp_scsi_task_mgmt_function(sdev, FCP_TMF_TGT_RESET); /* release reference from above shost_for_each_device */ if (sdev) scsi_device_put(tmp_sdev); return ret; } static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; int ret = SUCCESS, fc_ret; zfcp_erp_adapter_reopen(adapter, 0, "schrh_1"); zfcp_erp_wait(adapter); fc_ret = fc_block_scsi_eh(scpnt); if (fc_ret) ret = fc_ret; zfcp_dbf_scsi_eh("schrh_r", adapter, ~0, ret); return ret; } /** * zfcp_scsi_sysfs_host_reset() - Support scsi_host sysfs attribute host_reset. * @shost: Pointer to Scsi_Host to perform action on. * @reset_type: We support %SCSI_ADAPTER_RESET but not %SCSI_FIRMWARE_RESET. * * Return: 0 on %SCSI_ADAPTER_RESET, -%EOPNOTSUPP otherwise. * * This is similar to zfcp_sysfs_adapter_failed_store(). */ static int zfcp_scsi_sysfs_host_reset(struct Scsi_Host *shost, int reset_type) { struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0]; int ret = 0; if (reset_type != SCSI_ADAPTER_RESET) { ret = -EOPNOTSUPP; zfcp_dbf_scsi_eh("scshr_n", adapter, ~0, ret); return ret; } zfcp_erp_adapter_reset_sync(adapter, "scshr_y"); return ret; } struct scsi_transport_template *zfcp_scsi_transport_template; static struct scsi_host_template zfcp_scsi_host_template = { .module = THIS_MODULE, .name = "zfcp", .queuecommand = zfcp_scsi_queuecommand, .eh_timed_out = fc_eh_timed_out, .eh_abort_handler = zfcp_scsi_eh_abort_handler, .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler, .eh_target_reset_handler = zfcp_scsi_eh_target_reset_handler, .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler, .slave_alloc = zfcp_scsi_slave_alloc, .slave_configure = zfcp_scsi_slave_configure, .slave_destroy = zfcp_scsi_slave_destroy, .change_queue_depth = scsi_change_queue_depth, .host_reset = zfcp_scsi_sysfs_host_reset, .proc_name = "zfcp", .can_queue = 4096, .this_id = -1, .sg_tablesize = (((QDIO_MAX_ELEMENTS_PER_BUFFER - 1) * ZFCP_QDIO_MAX_SBALS_PER_REQ) - 2), /* GCD, adjusted later */ .max_sectors = (((QDIO_MAX_ELEMENTS_PER_BUFFER - 1) * ZFCP_QDIO_MAX_SBALS_PER_REQ) - 2) * 8, /* GCD, adjusted later */ /* report size limit per scatter-gather segment */ .max_segment_size = ZFCP_QDIO_SBALE_LEN, .dma_boundary = ZFCP_QDIO_SBALE_LEN - 1, .shost_attrs = zfcp_sysfs_shost_attrs, .sdev_attrs = zfcp_sysfs_sdev_attrs, .track_queue_depth = 1, .supported_mode = MODE_INITIATOR, }; /** * zfcp_scsi_adapter_register - Register SCSI and FC host with SCSI midlayer * @adapter: The zfcp adapter to register with the SCSI midlayer */ int zfcp_scsi_adapter_register(struct zfcp_adapter *adapter) { struct ccw_dev_id dev_id; if (adapter->scsi_host) return 0; ccw_device_get_id(adapter->ccw_device, &dev_id); /* register adapter as SCSI host with mid layer of SCSI stack */ adapter->scsi_host = scsi_host_alloc(&zfcp_scsi_host_template, sizeof (struct zfcp_adapter *)); if (!adapter->scsi_host) { dev_err(&adapter->ccw_device->dev, "Registering the FCP device with the " "SCSI stack failed\n"); return -EIO; } /* tell the SCSI stack some characteristics of this adapter */ adapter->scsi_host->max_id = 511; adapter->scsi_host->max_lun = 0xFFFFFFFF; adapter->scsi_host->max_channel = 0; adapter->scsi_host->unique_id = dev_id.devno; adapter->scsi_host->max_cmd_len = 16; /* in struct fcp_cmnd */ adapter->scsi_host->transportt = zfcp_scsi_transport_template; adapter->scsi_host->hostdata[0] = (unsigned long) adapter; if (scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev)) { scsi_host_put(adapter->scsi_host); return -EIO; } return 0; } /** * zfcp_scsi_adapter_unregister - Unregister SCSI and FC host from SCSI midlayer * @adapter: The zfcp adapter to unregister. */ void zfcp_scsi_adapter_unregister(struct zfcp_adapter *adapter) { struct Scsi_Host *shost; struct zfcp_port *port; shost = adapter->scsi_host; if (!shost) return; read_lock_irq(&adapter->port_list_lock); list_for_each_entry(port, &adapter->port_list, list) port->rport = NULL; read_unlock_irq(&adapter->port_list_lock); fc_remove_host(shost); scsi_remove_host(shost); scsi_host_put(shost); adapter->scsi_host = NULL; } static struct fc_host_statistics* zfcp_scsi_init_fc_host_stats(struct zfcp_adapter *adapter) { struct fc_host_statistics *fc_stats; if (!adapter->fc_stats) { fc_stats = kmalloc(sizeof(*fc_stats), GFP_KERNEL); if (!fc_stats) return NULL; adapter->fc_stats = fc_stats; /* freed in adapter_release */ } memset(adapter->fc_stats, 0, sizeof(*adapter->fc_stats)); return adapter->fc_stats; } static void zfcp_scsi_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, struct fsf_qtcb_bottom_port *data, struct fsf_qtcb_bottom_port *old) { fc_stats->seconds_since_last_reset = data->seconds_since_last_reset - old->seconds_since_last_reset; fc_stats->tx_frames = data->tx_frames - old->tx_frames; fc_stats->tx_words = data->tx_words - old->tx_words; fc_stats->rx_frames = data->rx_frames - old->rx_frames; fc_stats->rx_words = data->rx_words - old->rx_words; fc_stats->lip_count = data->lip - old->lip; fc_stats->nos_count = data->nos - old->nos; fc_stats->error_frames = data->error_frames - old->error_frames; fc_stats->dumped_frames = data->dumped_frames - old->dumped_frames; fc_stats->link_failure_count = data->link_failure - old->link_failure; fc_stats->loss_of_sync_count = data->loss_of_sync - old->loss_of_sync; fc_stats->loss_of_signal_count = data->loss_of_signal - old->loss_of_signal; fc_stats->prim_seq_protocol_err_count = data->psp_error_counts - old->psp_error_counts; fc_stats->invalid_tx_word_count = data->invalid_tx_words - old->invalid_tx_words; fc_stats->invalid_crc_count = data->invalid_crcs - old->invalid_crcs; fc_stats->fcp_input_requests = data->input_requests - old->input_requests; fc_stats->fcp_output_requests = data->output_requests - old->output_requests; fc_stats->fcp_control_requests = data->control_requests - old->control_requests; fc_stats->fcp_input_megabytes = data->input_mb - old->input_mb; fc_stats->fcp_output_megabytes = data->output_mb - old->output_mb; } static void zfcp_scsi_set_fc_host_stats(struct fc_host_statistics *fc_stats, struct fsf_qtcb_bottom_port *data) { fc_stats->seconds_since_last_reset = data->seconds_since_last_reset; fc_stats->tx_frames = data->tx_frames; fc_stats->tx_words = data->tx_words; fc_stats->rx_frames = data->rx_frames; fc_stats->rx_words = data->rx_words; fc_stats->lip_count = data->lip; fc_stats->nos_count = data->nos; fc_stats->error_frames = data->error_frames; fc_stats->dumped_frames = data->dumped_frames; fc_stats->link_failure_count = data->link_failure; fc_stats->loss_of_sync_count = data->loss_of_sync; fc_stats->loss_of_signal_count = data->loss_of_signal; fc_stats->prim_seq_protocol_err_count = data->psp_error_counts; fc_stats->invalid_tx_word_count = data->invalid_tx_words; fc_stats->invalid_crc_count = data->invalid_crcs; fc_stats->fcp_input_requests = data->input_requests; fc_stats->fcp_output_requests = data->output_requests; fc_stats->fcp_control_requests = data->control_requests; fc_stats->fcp_input_megabytes = data->input_mb; fc_stats->fcp_output_megabytes = data->output_mb; }
/** * zfcp_erp_adapter_shutdown - Shutdown adapter. * @adapter: Adapter to shut down. * @clear: Status flags to clear. * @id: Id for debug trace event. * @ref: Reference for debug trace event. */ void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, char *id, void *ref) { int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref); }
/* * function: zfcp_qdio_handler_error_check * * purpose: called by the response handler to determine error condition * * returns: error flag * */ static inline int zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status, unsigned int qdio_error, unsigned int siga_error) { int retval = 0; if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_TRACE)) { if (status & QDIO_STATUS_INBOUND_INT) { ZFCP_LOG_TRACE("status is" " QDIO_STATUS_INBOUND_INT \n"); } if (status & QDIO_STATUS_OUTBOUND_INT) { ZFCP_LOG_TRACE("status is" " QDIO_STATUS_OUTBOUND_INT \n"); } } // if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_TRACE)) if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) { retval = -EIO; ZFCP_LOG_FLAGS(1, "QDIO_STATUS_LOOK_FOR_ERROR \n"); ZFCP_LOG_INFO("QDIO problem occurred (status=0x%x, " "qdio_error=0x%x, siga_error=0x%x)\n", status, qdio_error, siga_error); if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION) { ZFCP_LOG_FLAGS(2, "QDIO_STATUS_ACTIVATE_CHECK_CONDITION\n"); } if (status & QDIO_STATUS_MORE_THAN_ONE_QDIO_ERROR) { ZFCP_LOG_FLAGS(2, "QDIO_STATUS_MORE_THAN_ONE_QDIO_ERROR\n"); } if (status & QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR) { ZFCP_LOG_FLAGS(2, "QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR\n"); } if (siga_error & QDIO_SIGA_ERROR_ACCESS_EXCEPTION) { ZFCP_LOG_FLAGS(2, "QDIO_SIGA_ERROR_ACCESS_EXCEPTION\n"); } if (siga_error & QDIO_SIGA_ERROR_B_BIT_SET) { ZFCP_LOG_FLAGS(2, "QDIO_SIGA_ERROR_B_BIT_SET\n"); } switch (qdio_error) { case 0: ZFCP_LOG_FLAGS(3, "QDIO_OK"); break; case SLSB_P_INPUT_ERROR: ZFCP_LOG_FLAGS(1, "SLSB_P_INPUT_ERROR\n"); break; case SLSB_P_OUTPUT_ERROR: ZFCP_LOG_FLAGS(1, "SLSB_P_OUTPUT_ERROR\n"); break; default: ZFCP_LOG_NORMAL("bug: unknown QDIO error 0x%x\n", qdio_error); break; } /* Restarting IO on the failed adapter from scratch */ debug_text_event(adapter->erp_dbf, 1, "qdio_err"); /* * Since we have been using this adapter, it is save to assume * that it is not failed but recoverable. The card seems to * report link-up events by self-initiated queue shutdown. * That is why we need to clear the the link-down flag * which is set again in case we have missed by a mile. */ zfcp_erp_adapter_reopen( adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED); } return retval; }
static void zfcp_scsi_forget_cmnds(struct zfcp_scsi_dev *zsdev, u8 tm_flags) { struct zfcp_adapter *adapter = zsdev->port->adapter; struct zfcp_scsi_req_filter filter = { .tmf_scope = FCP_TMF_TGT_RESET, .port_handle = zsdev->port->handle, }; unsigned long flags; if (tm_flags == FCP_TMF_LUN_RESET) { filter.tmf_scope = FCP_TMF_LUN_RESET; filter.lun_handle = zsdev->lun_handle; } /* * abort_lock secures against other processings - in the abort-function * and normal cmnd-handler - of (struct zfcp_fsf_req *)->data */ write_lock_irqsave(&adapter->abort_lock, flags); zfcp_reqlist_apply_for_all(adapter->req_list, zfcp_scsi_forget_cmnd, &filter); write_unlock_irqrestore(&adapter->abort_lock, flags); } static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; struct zfcp_fsf_req *fsf_req = NULL; int retval = SUCCESS, ret; int retry = 3; while (retry--) { fsf_req = zfcp_fsf_fcp_task_mgmt(scpnt, tm_flags); if (fsf_req) break; zfcp_erp_wait(adapter); ret = fc_block_scsi_eh(scpnt); if (ret) return ret; if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_RUNNING)) { zfcp_dbf_scsi_devreset("nres", scpnt, tm_flags); return SUCCESS; } } if (!fsf_req) return FAILED; wait_for_completion(&fsf_req->completion); if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags); retval = FAILED; } else { zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags); zfcp_scsi_forget_cmnds(zfcp_sdev, tm_flags); } zfcp_fsf_req_free(fsf_req); return retval; } static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) { return zfcp_task_mgmt_function(scpnt, FCP_TMF_LUN_RESET); } static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) { return zfcp_task_mgmt_function(scpnt, FCP_TMF_TGT_RESET); } static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; int ret; zfcp_erp_adapter_reopen(adapter, 0, "schrh_1"); zfcp_erp_wait(adapter); ret = fc_block_scsi_eh(scpnt); if (ret) return ret; return SUCCESS; } struct scsi_transport_template *zfcp_scsi_transport_template; static struct scsi_host_template zfcp_scsi_host_template = { .module = THIS_MODULE, .name = "zfcp", .queuecommand = zfcp_scsi_queuecommand, .eh_abort_handler = zfcp_scsi_eh_abort_handler, .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler, .eh_target_reset_handler = zfcp_scsi_eh_target_reset_handler, .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler, .slave_alloc = zfcp_scsi_slave_alloc, .slave_configure = zfcp_scsi_slave_configure, .slave_destroy = zfcp_scsi_slave_destroy, .change_queue_depth = scsi_change_queue_depth, .proc_name = "zfcp", .can_queue = 4096, .this_id = -1, .sg_tablesize = (((QDIO_MAX_ELEMENTS_PER_BUFFER - 1) * ZFCP_QDIO_MAX_SBALS_PER_REQ) - 2), /* GCD, adjusted later */ .max_sectors = (((QDIO_MAX_ELEMENTS_PER_BUFFER - 1) * ZFCP_QDIO_MAX_SBALS_PER_REQ) - 2) * 8, /* GCD, adjusted later */ .dma_boundary = ZFCP_QDIO_SBALE_LEN - 1, .use_clustering = 1, .shost_attrs = zfcp_sysfs_shost_attrs, .sdev_attrs = zfcp_sysfs_sdev_attrs, .track_queue_depth = 1, }; /** * zfcp_scsi_adapter_register - Register SCSI and FC host with SCSI midlayer * @adapter: The zfcp adapter to register with the SCSI midlayer */ int zfcp_scsi_adapter_register(struct zfcp_adapter *adapter) { struct ccw_dev_id dev_id; if (adapter->scsi_host) return 0; ccw_device_get_id(adapter->ccw_device, &dev_id); /* register adapter as SCSI host with mid layer of SCSI stack */ adapter->scsi_host = scsi_host_alloc(&zfcp_scsi_host_template, sizeof (struct zfcp_adapter *)); if (!adapter->scsi_host) { dev_err(&adapter->ccw_device->dev, "Registering the FCP device with the " "SCSI stack failed\n"); return -EIO; } /* tell the SCSI stack some characteristics of this adapter */ adapter->scsi_host->max_id = 511; adapter->scsi_host->max_lun = 0xFFFFFFFF; adapter->scsi_host->max_channel = 0; adapter->scsi_host->unique_id = dev_id.devno; adapter->scsi_host->max_cmd_len = 16; /* in struct fcp_cmnd */ adapter->scsi_host->transportt = zfcp_scsi_transport_template; adapter->scsi_host->hostdata[0] = (unsigned long) adapter; if (scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev)) { scsi_host_put(adapter->scsi_host); return -EIO; } return 0; } /** * zfcp_scsi_adapter_unregister - Unregister SCSI and FC host from SCSI midlayer * @adapter: The zfcp adapter to unregister. */ void zfcp_scsi_adapter_unregister(struct zfcp_adapter *adapter) { struct Scsi_Host *shost; struct zfcp_port *port; shost = adapter->scsi_host; if (!shost) return; read_lock_irq(&adapter->port_list_lock); list_for_each_entry(port, &adapter->port_list, list) port->rport = NULL; read_unlock_irq(&adapter->port_list_lock); fc_remove_host(shost); scsi_remove_host(shost); scsi_host_put(shost); adapter->scsi_host = NULL; } static struct fc_host_statistics* zfcp_init_fc_host_stats(struct zfcp_adapter *adapter) { struct fc_host_statistics *fc_stats; if (!adapter->fc_stats) { fc_stats = kmalloc(sizeof(*fc_stats), GFP_KERNEL); if (!fc_stats) return NULL; adapter->fc_stats = fc_stats; /* freed in adapter_release */ } memset(adapter->fc_stats, 0, sizeof(*adapter->fc_stats)); return adapter->fc_stats; } static void zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, struct fsf_qtcb_bottom_port *data, struct fsf_qtcb_bottom_port *old) { fc_stats->seconds_since_last_reset = data->seconds_since_last_reset - old->seconds_since_last_reset; fc_stats->tx_frames = data->tx_frames - old->tx_frames; fc_stats->tx_words = data->tx_words - old->tx_words; fc_stats->rx_frames = data->rx_frames - old->rx_frames; fc_stats->rx_words = data->rx_words - old->rx_words; fc_stats->lip_count = data->lip - old->lip; fc_stats->nos_count = data->nos - old->nos; fc_stats->error_frames = data->error_frames - old->error_frames; fc_stats->dumped_frames = data->dumped_frames - old->dumped_frames; fc_stats->link_failure_count = data->link_failure - old->link_failure; fc_stats->loss_of_sync_count = data->loss_of_sync - old->loss_of_sync; fc_stats->loss_of_signal_count = data->loss_of_signal - old->loss_of_signal; fc_stats->prim_seq_protocol_err_count = data->psp_error_counts - old->psp_error_counts; fc_stats->invalid_tx_word_count = data->invalid_tx_words - old->invalid_tx_words; fc_stats->invalid_crc_count = data->invalid_crcs - old->invalid_crcs; fc_stats->fcp_input_requests = data->input_requests - old->input_requests; fc_stats->fcp_output_requests = data->output_requests - old->output_requests; fc_stats->fcp_control_requests = data->control_requests - old->control_requests; fc_stats->fcp_input_megabytes = data->input_mb - old->input_mb; fc_stats->fcp_output_megabytes = data->output_mb - old->output_mb; } static void zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats, struct fsf_qtcb_bottom_port *data) { fc_stats->seconds_since_last_reset = data->seconds_since_last_reset; fc_stats->tx_frames = data->tx_frames; fc_stats->tx_words = data->tx_words; fc_stats->rx_frames = data->rx_frames; fc_stats->rx_words = data->rx_words; fc_stats->lip_count = data->lip; fc_stats->nos_count = data->nos; fc_stats->error_frames = data->error_frames; fc_stats->dumped_frames = data->dumped_frames; fc_stats->link_failure_count = data->link_failure; fc_stats->loss_of_sync_count = data->loss_of_sync; fc_stats->loss_of_signal_count = data->loss_of_signal; fc_stats->prim_seq_protocol_err_count = data->psp_error_counts; fc_stats->invalid_tx_word_count = data->invalid_tx_words; fc_stats->invalid_crc_count = data->invalid_crcs; fc_stats->fcp_input_requests = data->input_requests; fc_stats->fcp_output_requests = data->output_requests; fc_stats->fcp_control_requests = data->control_requests; fc_stats->fcp_input_megabytes = data->input_mb; fc_stats->fcp_output_megabytes = data->output_mb; }