static void __devexit fnic_remove(struct pci_dev *pdev) { struct fnic *fnic = pci_get_drvdata(pdev); unsigned long flags; spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->stop_rx_link_events = 1; spin_unlock_irqrestore(&fnic->fnic_lock, flags); if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI) del_timer_sync(&fnic->notify_timer); flush_workqueue(fnic_event_queue); skb_queue_purge(&fnic->frame_queue); fc_fabric_logoff(fnic->lport); spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->in_remove = 1; spin_unlock_irqrestore(&fnic->fnic_lock, flags); fc_lport_destroy(fnic->lport); fnic_cleanup(fnic); BUG_ON(!skb_queue_empty(&fnic->frame_queue)); spin_lock_irqsave(&fnic_list_lock, flags); list_del(&fnic->list); spin_unlock_irqrestore(&fnic_list_lock, flags); fc_remove_host(fnic->lport->host); scsi_remove_host(fnic->lport->host); fc_exch_mgr_free(fnic->lport); vnic_dev_notify_unset(fnic->vdev); fnic_free_vnic_resources(fnic); fnic_free_intr(fnic); fnic_clear_intr_mode(fnic); vnic_dev_close(fnic->vdev); vnic_dev_unregister(fnic->vdev); fnic_iounmap(fnic); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); scsi_host_put(fnic->lport->host); }
/** * 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 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; }
static void fnic_remove(struct pci_dev *pdev) { struct fnic *fnic = pci_get_drvdata(pdev); struct fc_lport *lp = fnic->lport; unsigned long flags; /* * Mark state so that the workqueue thread stops forwarding * received frames and link events to the local port. ISR and * other threads that can queue work items will also stop * creating work items on the fnic workqueue */ spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->stop_rx_link_events = 1; spin_unlock_irqrestore(&fnic->fnic_lock, flags); if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI) del_timer_sync(&fnic->notify_timer); /* * Flush the fnic event queue. After this call, there should * be no event queued for this fnic device in the workqueue */ flush_workqueue(fnic_event_queue); skb_queue_purge(&fnic->frame_queue); skb_queue_purge(&fnic->tx_queue); if (fnic->config.flags & VFCF_FIP_CAPABLE) { del_timer_sync(&fnic->fip_timer); skb_queue_purge(&fnic->fip_frame_queue); fnic_fcoe_reset_vlans(fnic); fnic_fcoe_evlist_free(fnic); } /* * Log off the fabric. This stops all remote ports, dns port, * logs off the fabric. This flushes all rport, disc, lport work * before returning */ fc_fabric_logoff(fnic->lport); spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->in_remove = 1; spin_unlock_irqrestore(&fnic->fnic_lock, flags); fcoe_ctlr_destroy(&fnic->ctlr); fc_lport_destroy(lp); fnic_stats_debugfs_remove(fnic); /* * This stops the fnic device, masks all interrupts. Completed * CQ entries are drained. Posted WQ/RQ/Copy-WQ entries are * cleaned up */ fnic_cleanup(fnic); BUG_ON(!skb_queue_empty(&fnic->frame_queue)); BUG_ON(!skb_queue_empty(&fnic->tx_queue)); spin_lock_irqsave(&fnic_list_lock, flags); list_del(&fnic->list); spin_unlock_irqrestore(&fnic_list_lock, flags); fc_remove_host(fnic->lport->host); scsi_remove_host(fnic->lport->host); fc_exch_mgr_free(fnic->lport); vnic_dev_notify_unset(fnic->vdev); fnic_free_intr(fnic); fnic_free_vnic_resources(fnic); fnic_clear_intr_mode(fnic); vnic_dev_close(fnic->vdev); vnic_dev_unregister(fnic->vdev); fnic_iounmap(fnic); pci_release_regions(pdev); pci_disable_device(pdev); scsi_host_put(lp->host); }
static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct Scsi_Host *host; struct fc_lport *lp; struct fnic *fnic; mempool_t *pool; int err; int i; unsigned long flags; /* * Allocate SCSI Host and set up association between host, * local port, and fnic */ lp = libfc_host_alloc(&fnic_host_template, sizeof(struct fnic)); if (!lp) { printk(KERN_ERR PFX "Unable to alloc libfc local port\n"); err = -ENOMEM; goto err_out; } host = lp->host; fnic = lport_priv(lp); fnic->lport = lp; fnic->ctlr.lp = lp; snprintf(fnic->name, sizeof(fnic->name) - 1, "%s%d", DRV_NAME, host->host_no); host->transportt = fnic_fc_transport; err = fnic_stats_debugfs_init(fnic); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Failed to initialize debugfs for stats\n"); fnic_stats_debugfs_remove(fnic); } /* Setup PCI resources */ pci_set_drvdata(pdev, fnic); fnic->pdev = pdev; err = pci_enable_device(pdev); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Cannot enable PCI device, aborting.\n"); goto err_out_free_hba; } err = pci_request_regions(pdev, DRV_NAME); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Cannot enable PCI resources, aborting\n"); goto err_out_disable_device; } pci_set_master(pdev); /* Query PCI controller on system for DMA addressing * limitation for the device. Try 64-bit first, and * fail to 32-bit. */ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); if (err) { err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "No usable DMA configuration " "aborting\n"); goto err_out_release_regions; } err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Unable to obtain 32-bit DMA " "for consistent allocations, aborting.\n"); goto err_out_release_regions; } } else { err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Unable to obtain 64-bit DMA " "for consistent allocations, aborting.\n"); goto err_out_release_regions; } } /* Map vNIC resources from BAR0 */ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { shost_printk(KERN_ERR, fnic->lport->host, "BAR0 not memory-map'able, aborting.\n"); err = -ENODEV; goto err_out_release_regions; } fnic->bar0.vaddr = pci_iomap(pdev, 0, 0); fnic->bar0.bus_addr = pci_resource_start(pdev, 0); fnic->bar0.len = pci_resource_len(pdev, 0); if (!fnic->bar0.vaddr) { shost_printk(KERN_ERR, fnic->lport->host, "Cannot memory-map BAR0 res hdr, " "aborting.\n"); err = -ENODEV; goto err_out_release_regions; } fnic->vdev = vnic_dev_register(NULL, fnic, pdev, &fnic->bar0); if (!fnic->vdev) { shost_printk(KERN_ERR, fnic->lport->host, "vNIC registration failed, " "aborting.\n"); err = -ENODEV; goto err_out_iounmap; } err = fnic_dev_wait(fnic->vdev, vnic_dev_open, vnic_dev_open_done, 0); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "vNIC dev open failed, aborting.\n"); goto err_out_vnic_unregister; } err = vnic_dev_init(fnic->vdev, 0); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "vNIC dev init failed, aborting.\n"); goto err_out_dev_close; } err = vnic_dev_mac_addr(fnic->vdev, fnic->ctlr.ctl_src_addr); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "vNIC get MAC addr failed \n"); goto err_out_dev_close; } /* set data_src for point-to-point mode and to keep it non-zero */ memcpy(fnic->data_src_addr, fnic->ctlr.ctl_src_addr, ETH_ALEN); /* Get vNIC configuration */ err = fnic_get_vnic_config(fnic); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Get vNIC configuration failed, " "aborting.\n"); goto err_out_dev_close; } /* Configure Maximum Outstanding IO reqs*/ if (fnic->config.io_throttle_count != FNIC_UCSM_DFLT_THROTTLE_CNT_BLD) { host->can_queue = min_t(u32, FNIC_MAX_IO_REQ, max_t(u32, FNIC_MIN_IO_REQ, fnic->config.io_throttle_count)); } fnic->fnic_max_tag_id = host->can_queue; err = scsi_init_shared_tag_map(host, fnic->fnic_max_tag_id); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Unable to alloc shared tag map\n"); goto err_out_dev_close; } host->max_lun = fnic->config.luns_per_tgt; host->max_id = FNIC_MAX_FCP_TARGET; host->max_cmd_len = FCOE_MAX_CMD_LEN; fnic_get_res_counts(fnic); err = fnic_set_intr_mode(fnic); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Failed to set intr mode, " "aborting.\n"); goto err_out_dev_close; } err = fnic_alloc_vnic_resources(fnic); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Failed to alloc vNIC resources, " "aborting.\n"); goto err_out_clear_intr; } /* initialize all fnic locks */ spin_lock_init(&fnic->fnic_lock); for (i = 0; i < FNIC_WQ_MAX; i++) spin_lock_init(&fnic->wq_lock[i]); for (i = 0; i < FNIC_WQ_COPY_MAX; i++) { spin_lock_init(&fnic->wq_copy_lock[i]); fnic->wq_copy_desc_low[i] = DESC_CLEAN_LOW_WATERMARK; fnic->fw_ack_recd[i] = 0; fnic->fw_ack_index[i] = -1; } for (i = 0; i < FNIC_IO_LOCKS; i++) spin_lock_init(&fnic->io_req_lock[i]); fnic->io_req_pool = mempool_create_slab_pool(2, fnic_io_req_cache); if (!fnic->io_req_pool) goto err_out_free_resources; pool = mempool_create_slab_pool(2, fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); if (!pool) goto err_out_free_ioreq_pool; fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT] = pool; pool = mempool_create_slab_pool(2, fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); if (!pool) goto err_out_free_dflt_pool; fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX] = pool; /* setup vlan config, hw inserts vlan header */ fnic->vlan_hw_insert = 1; fnic->vlan_id = 0; /* Initialize the FIP fcoe_ctrl struct */ fnic->ctlr.send = fnic_eth_send; fnic->ctlr.update_mac = fnic_update_mac; fnic->ctlr.get_src_addr = fnic_get_mac; if (fnic->config.flags & VFCF_FIP_CAPABLE) { shost_printk(KERN_INFO, fnic->lport->host, "firmware supports FIP\n"); /* enable directed and multicast */ vnic_dev_packet_filter(fnic->vdev, 1, 1, 0, 0, 0); vnic_dev_add_addr(fnic->vdev, FIP_ALL_ENODE_MACS); vnic_dev_add_addr(fnic->vdev, fnic->ctlr.ctl_src_addr); fnic->set_vlan = fnic_set_vlan; fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_AUTO); setup_timer(&fnic->fip_timer, fnic_fip_notify_timer, (unsigned long)fnic); spin_lock_init(&fnic->vlans_lock); INIT_WORK(&fnic->fip_frame_work, fnic_handle_fip_frame); INIT_WORK(&fnic->event_work, fnic_handle_event); skb_queue_head_init(&fnic->fip_frame_queue); INIT_LIST_HEAD(&fnic->evlist); INIT_LIST_HEAD(&fnic->vlans); } else { shost_printk(KERN_INFO, fnic->lport->host, "firmware uses non-FIP mode\n"); fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_NON_FIP); } fnic->state = FNIC_IN_FC_MODE; atomic_set(&fnic->in_flight, 0); fnic->state_flags = FNIC_FLAGS_NONE; /* Enable hardware stripping of vlan header on ingress */ fnic_set_nic_config(fnic, 0, 0, 0, 0, 0, 0, 1); /* Setup notification buffer area */ err = fnic_notify_set(fnic); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Failed to alloc notify buffer, aborting.\n"); goto err_out_free_max_pool; } /* Setup notify timer when using MSI interrupts */ if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI) setup_timer(&fnic->notify_timer, fnic_notify_timer, (unsigned long)fnic); /* allocate RQ buffers and post them to RQ*/ for (i = 0; i < fnic->rq_count; i++) { err = vnic_rq_fill(&fnic->rq[i], fnic_alloc_rq_frame); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "fnic_alloc_rq_frame can't alloc " "frame\n"); goto err_out_free_rq_buf; } } /* * Initialization done with PCI system, hardware, firmware. * Add host to SCSI */ err = scsi_add_host(lp->host, &pdev->dev); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "fnic: scsi_add_host failed...exiting\n"); goto err_out_free_rq_buf; } /* Start local port initiatialization */ lp->link_up = 0; lp->max_retry_count = fnic->config.flogi_retries; lp->max_rport_retry_count = fnic->config.plogi_retries; lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | FCP_SPPF_CONF_COMPL); if (fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR) lp->service_params |= FCP_SPPF_RETRY; lp->boot_time = jiffies; lp->e_d_tov = fnic->config.ed_tov; lp->r_a_tov = fnic->config.ra_tov; lp->link_supported_speeds = FC_PORTSPEED_10GBIT; fc_set_wwnn(lp, fnic->config.node_wwn); fc_set_wwpn(lp, fnic->config.port_wwn); fcoe_libfc_config(lp, &fnic->ctlr, &fnic_transport_template, 0); if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START, FCPIO_HOST_EXCH_RANGE_END, NULL)) { err = -ENOMEM; goto err_out_remove_scsi_host; } fc_lport_init_stats(lp); fnic->stats_reset_time = jiffies; fc_lport_config(lp); if (fc_set_mfs(lp, fnic->config.maxdatafieldsize + sizeof(struct fc_frame_header))) { err = -EINVAL; goto err_out_free_exch_mgr; } fc_host_maxframe_size(lp->host) = lp->mfs; fc_host_dev_loss_tmo(lp->host) = fnic->config.port_down_timeout / 1000; sprintf(fc_host_symbolic_name(lp->host), DRV_NAME " v" DRV_VERSION " over %s", fnic->name); spin_lock_irqsave(&fnic_list_lock, flags); list_add_tail(&fnic->list, &fnic_list); spin_unlock_irqrestore(&fnic_list_lock, flags); INIT_WORK(&fnic->link_work, fnic_handle_link); INIT_WORK(&fnic->frame_work, fnic_handle_frame); skb_queue_head_init(&fnic->frame_queue); skb_queue_head_init(&fnic->tx_queue); /* Enable all queues */ for (i = 0; i < fnic->raw_wq_count; i++) vnic_wq_enable(&fnic->wq[i]); for (i = 0; i < fnic->rq_count; i++) vnic_rq_enable(&fnic->rq[i]); for (i = 0; i < fnic->wq_copy_count; i++) vnic_wq_copy_enable(&fnic->wq_copy[i]); fc_fabric_login(lp); vnic_dev_enable(fnic->vdev); err = fnic_request_intr(fnic); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Unable to request irq.\n"); goto err_out_free_exch_mgr; } for (i = 0; i < fnic->intr_count; i++) vnic_intr_unmask(&fnic->intr[i]); fnic_notify_timer_start(fnic); return 0; err_out_free_exch_mgr: fc_exch_mgr_free(lp); err_out_remove_scsi_host: fc_remove_host(lp->host); scsi_remove_host(lp->host); err_out_free_rq_buf: for (i = 0; i < fnic->rq_count; i++) vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf); vnic_dev_notify_unset(fnic->vdev); err_out_free_max_pool: mempool_destroy(fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX]); err_out_free_dflt_pool: mempool_destroy(fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT]); err_out_free_ioreq_pool: mempool_destroy(fnic->io_req_pool); err_out_free_resources: fnic_free_vnic_resources(fnic); err_out_clear_intr: fnic_clear_intr_mode(fnic); err_out_dev_close: vnic_dev_close(fnic->vdev); err_out_vnic_unregister: vnic_dev_unregister(fnic->vdev); err_out_iounmap: fnic_iounmap(fnic); err_out_release_regions: pci_release_regions(pdev); err_out_disable_device: pci_disable_device(pdev); err_out_free_hba: fnic_stats_debugfs_remove(fnic); scsi_host_put(lp->host); err_out: return err; }
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; }
/* * fcoe_sw_destroy - FCoE software HBA tear-down function * @netdev: ptr to the associated net_device * * Returns: 0 if link is OK for use by FCoE. */ static int fcoe_sw_destroy(struct net_device *netdev) { int cpu; struct fc_lport *lp = NULL; struct fcoe_softc *fc; u8 flogi_maddr[ETH_ALEN]; BUG_ON(!netdev); printk(KERN_DEBUG "fcoe_sw_destroy:interface on %s\n", netdev->name); lp = fcoe_hostlist_lookup(netdev); if (!lp) return -ENODEV; fc = fcoe_softc(lp); /* Logout of the fabric */ fc_fabric_logoff(lp); /* Remove the instance from fcoe's list */ fcoe_hostlist_remove(lp); /* Don't listen for Ethernet packets anymore */ dev_remove_pack(&fc->fcoe_packet_type); /* Cleanup the fc_lport */ fc_lport_destroy(lp); fc_fcp_destroy(lp); /* Detach from the scsi-ml */ fc_remove_host(lp->host); scsi_remove_host(lp->host); /* There are no more rports or I/O, free the EM */ if (lp->emp) fc_exch_mgr_free(lp->emp); /* Delete secondary MAC addresses */ rtnl_lock(); memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) dev_unicast_delete(fc->real_dev, fc->data_src_addr, ETH_ALEN); rtnl_unlock(); /* Free the per-CPU revieve threads */ fcoe_percpu_clean(lp); /* Free existing skbs */ fcoe_clean_pending_queue(lp); /* Free memory used by statistical counters */ for_each_online_cpu(cpu) kfree(lp->dev_stats[cpu]); /* Release the net_device and Scsi_Host */ dev_put(fc->real_dev); scsi_host_put(lp->host); return 0; }
static int __devinit fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct Scsi_Host *host; struct fc_lport *lp; struct fnic *fnic; mempool_t *pool; int err; int i; unsigned long flags; /* * Allocate SCSI Host and set up association between host, * local port, and fnic */ host = scsi_host_alloc(&fnic_host_template, sizeof(struct fc_lport) + sizeof(struct fnic)); if (!host) { printk(KERN_ERR PFX "Unable to alloc SCSI host\n"); err = -ENOMEM; goto err_out; } lp = shost_priv(host); lp->host = host; fnic = lport_priv(lp); fnic->lport = lp; snprintf(fnic->name, sizeof(fnic->name) - 1, "%s%d", DRV_NAME, host->host_no); host->transportt = fnic_fc_transport; err = scsi_init_shared_tag_map(host, FNIC_MAX_IO_REQ); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Unable to alloc shared tag map\n"); goto err_out_free_hba; } /* Setup PCI resources */ pci_set_drvdata(pdev, fnic); fnic->pdev = pdev; err = pci_enable_device(pdev); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Cannot enable PCI device, aborting.\n"); goto err_out_free_hba; } err = pci_request_regions(pdev, DRV_NAME); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Cannot enable PCI resources, aborting\n"); goto err_out_disable_device; } pci_set_master(pdev); /* Query PCI controller on system for DMA addressing * limitation for the device. Try 40-bit first, and * fail to 32-bit. */ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(40)); if (err) { err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "No usable DMA configuration " "aborting\n"); goto err_out_release_regions; } err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Unable to obtain 32-bit DMA " "for consistent allocations, aborting.\n"); goto err_out_release_regions; } } else { err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(40)); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Unable to obtain 40-bit DMA " "for consistent allocations, aborting.\n"); goto err_out_release_regions; } } /* Map vNIC resources from BAR0 */ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { shost_printk(KERN_ERR, fnic->lport->host, "BAR0 not memory-map'able, aborting.\n"); err = -ENODEV; goto err_out_release_regions; } fnic->bar0.vaddr = pci_iomap(pdev, 0, 0); fnic->bar0.bus_addr = pci_resource_start(pdev, 0); fnic->bar0.len = pci_resource_len(pdev, 0); if (!fnic->bar0.vaddr) { shost_printk(KERN_ERR, fnic->lport->host, "Cannot memory-map BAR0 res hdr, " "aborting.\n"); err = -ENODEV; goto err_out_release_regions; } fnic->vdev = vnic_dev_register(NULL, fnic, pdev, &fnic->bar0); if (!fnic->vdev) { shost_printk(KERN_ERR, fnic->lport->host, "vNIC registration failed, " "aborting.\n"); err = -ENODEV; goto err_out_iounmap; } err = fnic_dev_wait(fnic->vdev, vnic_dev_open, vnic_dev_open_done, 0); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "vNIC dev open failed, aborting.\n"); goto err_out_vnic_unregister; } err = vnic_dev_init(fnic->vdev, 0); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "vNIC dev init failed, aborting.\n"); goto err_out_dev_close; } err = vnic_dev_mac_addr(fnic->vdev, fnic->mac_addr); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "vNIC get MAC addr failed \n"); goto err_out_dev_close; } /* Get vNIC configuration */ err = fnic_get_vnic_config(fnic); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Get vNIC configuration failed, " "aborting.\n"); goto err_out_dev_close; } host->max_lun = fnic->config.luns_per_tgt; host->max_id = FNIC_MAX_FCP_TARGET; fnic_get_res_counts(fnic); err = fnic_set_intr_mode(fnic); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Failed to set intr mode, " "aborting.\n"); goto err_out_dev_close; } err = fnic_request_intr(fnic); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Unable to request irq.\n"); goto err_out_clear_intr; } err = fnic_alloc_vnic_resources(fnic); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Failed to alloc vNIC resources, " "aborting.\n"); goto err_out_free_intr; } /* initialize all fnic locks */ spin_lock_init(&fnic->fnic_lock); for (i = 0; i < FNIC_WQ_MAX; i++) spin_lock_init(&fnic->wq_lock[i]); for (i = 0; i < FNIC_WQ_COPY_MAX; i++) { spin_lock_init(&fnic->wq_copy_lock[i]); fnic->wq_copy_desc_low[i] = DESC_CLEAN_LOW_WATERMARK; fnic->fw_ack_recd[i] = 0; fnic->fw_ack_index[i] = -1; } for (i = 0; i < FNIC_IO_LOCKS; i++) spin_lock_init(&fnic->io_req_lock[i]); fnic->io_req_pool = mempool_create_slab_pool(2, fnic_io_req_cache); if (!fnic->io_req_pool) goto err_out_free_resources; pool = mempool_create(2, fnic_alloc_slab_dma, mempool_free_slab, fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); if (!pool) goto err_out_free_ioreq_pool; fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT] = pool; pool = mempool_create(2, fnic_alloc_slab_dma, mempool_free_slab, fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); if (!pool) goto err_out_free_dflt_pool; fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX] = pool; /* setup vlan config, hw inserts vlan header */ fnic->vlan_hw_insert = 1; fnic->vlan_id = 0; fnic->flogi_oxid = FC_XID_UNKNOWN; fnic->flogi = NULL; fnic->flogi_resp = NULL; fnic->state = FNIC_IN_FC_MODE; /* Enable hardware stripping of vlan header on ingress */ fnic_set_nic_config(fnic, 0, 0, 0, 0, 0, 0, 1); /* Setup notification buffer area */ err = fnic_notify_set(fnic); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "Failed to alloc notify buffer, aborting.\n"); goto err_out_free_max_pool; } /* Setup notify timer when using MSI interrupts */ if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI) setup_timer(&fnic->notify_timer, fnic_notify_timer, (unsigned long)fnic); /* allocate RQ buffers and post them to RQ*/ for (i = 0; i < fnic->rq_count; i++) { err = vnic_rq_fill(&fnic->rq[i], fnic_alloc_rq_frame); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "fnic_alloc_rq_frame can't alloc " "frame\n"); goto err_out_free_rq_buf; } } /* * Initialization done with PCI system, hardware, firmware. * Add host to SCSI */ err = scsi_add_host(lp->host, &pdev->dev); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "fnic: scsi_add_host failed...exiting\n"); goto err_out_free_rq_buf; } /* Start local port initiatialization */ lp->link_up = 0; lp->tt = fnic_transport_template; lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START, FCPIO_HOST_EXCH_RANGE_END); if (!lp->emp) { err = -ENOMEM; goto err_out_remove_scsi_host; } lp->max_retry_count = fnic->config.flogi_retries; lp->max_rport_retry_count = fnic->config.plogi_retries; lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | FCP_SPPF_CONF_COMPL); if (fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR) lp->service_params |= FCP_SPPF_RETRY; lp->boot_time = jiffies; lp->e_d_tov = fnic->config.ed_tov; lp->r_a_tov = fnic->config.ra_tov; lp->link_supported_speeds = FC_PORTSPEED_10GBIT; fc_set_wwnn(lp, fnic->config.node_wwn); fc_set_wwpn(lp, fnic->config.port_wwn); fc_exch_init(lp); fc_lport_init(lp); fc_elsct_init(lp); fc_rport_init(lp); fc_disc_init(lp); fc_lport_config(lp); if (fc_set_mfs(lp, fnic->config.maxdatafieldsize + sizeof(struct fc_frame_header))) { err = -EINVAL; goto err_out_free_exch_mgr; } fc_host_maxframe_size(lp->host) = lp->mfs; sprintf(fc_host_symbolic_name(lp->host), DRV_NAME " v" DRV_VERSION " over %s", fnic->name); spin_lock_irqsave(&fnic_list_lock, flags); list_add_tail(&fnic->list, &fnic_list); spin_unlock_irqrestore(&fnic_list_lock, flags); INIT_WORK(&fnic->link_work, fnic_handle_link); INIT_WORK(&fnic->frame_work, fnic_handle_frame); skb_queue_head_init(&fnic->frame_queue); /* Enable all queues */ for (i = 0; i < fnic->raw_wq_count; i++) vnic_wq_enable(&fnic->wq[i]); for (i = 0; i < fnic->rq_count; i++) vnic_rq_enable(&fnic->rq[i]); for (i = 0; i < fnic->wq_copy_count; i++) vnic_wq_copy_enable(&fnic->wq_copy[i]); fc_fabric_login(lp); vnic_dev_enable(fnic->vdev); for (i = 0; i < fnic->intr_count; i++) vnic_intr_unmask(&fnic->intr[i]); fnic_notify_timer_start(fnic); return 0; err_out_free_exch_mgr: fc_exch_mgr_free(lp->emp); err_out_remove_scsi_host: fc_remove_host(fnic->lport->host); scsi_remove_host(fnic->lport->host); err_out_free_rq_buf: for (i = 0; i < fnic->rq_count; i++) vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf); vnic_dev_notify_unset(fnic->vdev); err_out_free_max_pool: mempool_destroy(fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX]); err_out_free_dflt_pool: mempool_destroy(fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT]); err_out_free_ioreq_pool: mempool_destroy(fnic->io_req_pool); err_out_free_resources: fnic_free_vnic_resources(fnic); err_out_free_intr: fnic_free_intr(fnic); err_out_clear_intr: fnic_clear_intr_mode(fnic); err_out_dev_close: vnic_dev_close(fnic->vdev); err_out_vnic_unregister: vnic_dev_unregister(fnic->vdev); err_out_iounmap: fnic_iounmap(fnic); err_out_release_regions: pci_release_regions(pdev); err_out_disable_device: pci_disable_device(pdev); err_out_free_hba: scsi_host_put(lp->host); err_out: return err; }