📄 zfcp_aux.c
字号:
return -ENOMEM; adapter->pool.data_gid_pn = mempool_create(ZFCP_POOL_DATA_GID_PN_NR, zfcp_mempool_alloc, zfcp_mempool_free, (void *) sizeof(struct zfcp_gid_pn_data)); if (NULL == adapter->pool.data_gid_pn) return -ENOMEM; return 0;}/** * zfcp_free_low_mem_buffers - free memory pools of an adapter * @adapter: pointer to zfcp_adapter for which memory pools should be freed * locking: zfcp_data.config_sema must be held */static voidzfcp_free_low_mem_buffers(struct zfcp_adapter *adapter){ if (adapter->pool.fsf_req_erp) mempool_destroy(adapter->pool.fsf_req_erp); if (adapter->pool.fsf_req_scsi) mempool_destroy(adapter->pool.fsf_req_scsi); if (adapter->pool.fsf_req_abort) mempool_destroy(adapter->pool.fsf_req_abort); if (adapter->pool.fsf_req_status_read) mempool_destroy(adapter->pool.fsf_req_status_read); if (adapter->pool.data_status_read) mempool_destroy(adapter->pool.data_status_read); if (adapter->pool.data_gid_pn) mempool_destroy(adapter->pool.data_gid_pn);}voidzfcp_dummy_release(struct device *dev){ return;}/* * Enqueues an adapter at the end of the adapter list in the driver data. * All adapter internal structures are set up. * Proc-fs entries are also created. * * returns: 0 if a new adapter was successfully enqueued * ZFCP_KNOWN if an adapter with this devno was already present * -ENOMEM if alloc failed * locks: config_sema must be held to serialise changes to the adapter list */struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device){ int retval = 0; struct zfcp_adapter *adapter; /* * Note: It is safe to release the list_lock, as any list changes * are protected by the config_sema, which must be held to get here */ /* try to allocate new adapter data structure (zeroed) */ adapter = kmalloc(sizeof (struct zfcp_adapter), GFP_KERNEL); if (!adapter) { ZFCP_LOG_INFO("error: allocation of base adapter " "structure failed\n"); goto out; } memset(adapter, 0, sizeof (struct zfcp_adapter)); ccw_device->handler = NULL; /* save ccw_device pointer */ adapter->ccw_device = ccw_device; retval = zfcp_qdio_allocate_queues(adapter); if (retval) goto queues_alloc_failed; retval = zfcp_qdio_allocate(adapter); if (retval) goto qdio_allocate_failed; retval = zfcp_allocate_low_mem_buffers(adapter); if (retval) { ZFCP_LOG_INFO("error: pool allocation failed\n"); goto failed_low_mem_buffers; } /* initialise reference count stuff */ atomic_set(&adapter->refcount, 0); init_waitqueue_head(&adapter->remove_wq); /* initialise list of ports */ INIT_LIST_HEAD(&adapter->port_list_head); /* initialise list of ports to be removed */ INIT_LIST_HEAD(&adapter->port_remove_lh); /* initialize list of fsf requests */ spin_lock_init(&adapter->fsf_req_list_lock); INIT_LIST_HEAD(&adapter->fsf_req_list_head); /* initialize debug locks */ spin_lock_init(&adapter->erp_dbf_lock); spin_lock_init(&adapter->hba_dbf_lock); spin_lock_init(&adapter->san_dbf_lock); spin_lock_init(&adapter->scsi_dbf_lock); /* initialize error recovery stuff */ rwlock_init(&adapter->erp_lock); sema_init(&adapter->erp_ready_sem, 0); INIT_LIST_HEAD(&adapter->erp_ready_head); INIT_LIST_HEAD(&adapter->erp_running_head); /* initialize abort lock */ rwlock_init(&adapter->abort_lock); /* initialise some erp stuff */ init_waitqueue_head(&adapter->erp_thread_wqh); init_waitqueue_head(&adapter->erp_done_wqh); /* initialize lock of associated request queue */ rwlock_init(&adapter->request_queue.queue_lock); /* intitialise SCSI ER timer */ init_timer(&adapter->scsi_er_timer); /* set FC service class used per default */ adapter->fc_service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT; sprintf(adapter->name, "%s", zfcp_get_busid_by_adapter(adapter)); ASCEBC(adapter->name, strlen(adapter->name)); /* mark adapter unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); adapter->ccw_device = ccw_device; dev_set_drvdata(&ccw_device->dev, adapter); if (zfcp_sysfs_adapter_create_files(&ccw_device->dev)) goto sysfs_failed; adapter->generic_services.parent = &adapter->ccw_device->dev; adapter->generic_services.release = zfcp_dummy_release; snprintf(adapter->generic_services.bus_id, BUS_ID_SIZE, "generic_services"); if (device_register(&adapter->generic_services)) goto generic_services_failed; /* put allocated adapter at list tail */ write_lock_irq(&zfcp_data.config_lock); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); list_add_tail(&adapter->list, &zfcp_data.adapter_list_head); write_unlock_irq(&zfcp_data.config_lock); zfcp_data.adapters++; goto out; generic_services_failed: zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); sysfs_failed: dev_set_drvdata(&ccw_device->dev, NULL); failed_low_mem_buffers: zfcp_free_low_mem_buffers(adapter); if (qdio_free(ccw_device) != 0) ZFCP_LOG_NORMAL("bug: qdio_free for adapter %s failed\n", zfcp_get_busid_by_adapter(adapter)); qdio_allocate_failed: zfcp_qdio_free_queues(adapter); queues_alloc_failed: kfree(adapter); adapter = NULL; out: return adapter;}/* * returns: 0 - struct zfcp_adapter data structure successfully removed * !0 - struct zfcp_adapter data structure could not be removed * (e.g. still used) * locks: adapter list write lock is assumed to be held by caller * adapter->fsf_req_list_lock is taken and released within this * function and must not be held on entry */voidzfcp_adapter_dequeue(struct zfcp_adapter *adapter){ int retval = 0; unsigned long flags; device_unregister(&adapter->generic_services); zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); dev_set_drvdata(&adapter->ccw_device->dev, NULL); /* sanity check: no pending FSF requests */ spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); retval = !list_empty(&adapter->fsf_req_list_head); spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); if (retval) { ZFCP_LOG_NORMAL("bug: adapter %s (%p) still in use, " "%i requests outstanding\n", zfcp_get_busid_by_adapter(adapter), adapter, atomic_read(&adapter->fsf_reqs_active)); retval = -EBUSY; goto out; } /* remove specified adapter data structure from list */ write_lock_irq(&zfcp_data.config_lock); list_del(&adapter->list); write_unlock_irq(&zfcp_data.config_lock); /* decrease number of adapters in list */ zfcp_data.adapters--; ZFCP_LOG_TRACE("adapter %s (%p) removed from list, " "%i adapters still in list\n", zfcp_get_busid_by_adapter(adapter), adapter, zfcp_data.adapters); retval = qdio_free(adapter->ccw_device); if (retval) ZFCP_LOG_NORMAL("bug: qdio_free for adapter %s failed\n", zfcp_get_busid_by_adapter(adapter)); zfcp_free_low_mem_buffers(adapter); /* free memory of adapter data structure and queues */ zfcp_qdio_free_queues(adapter); ZFCP_LOG_TRACE("freeing adapter structure\n"); kfree(adapter); out: return;}/** * zfcp_port_enqueue - enqueue port to port list of adapter * @adapter: adapter where remote port is added * @wwpn: WWPN of the remote port to be enqueued * @status: initial status for the port * @d_id: destination id of the remote port to be enqueued * Return: pointer to enqueued port on success, NULL on error * Locks: config_sema must be held to serialize changes to the port list * * All port internal structures are set up and the sysfs entry is generated. * d_id is used to enqueue ports with a well known address like the Directory * Service for nameserver lookup. */struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, u32 d_id){ struct zfcp_port *port; int check_wwpn; check_wwpn = !(status & ZFCP_STATUS_PORT_NO_WWPN); /* * check that there is no port with this WWPN already in list */ if (check_wwpn) { read_lock_irq(&zfcp_data.config_lock); port = zfcp_get_port_by_wwpn(adapter, wwpn); read_unlock_irq(&zfcp_data.config_lock); if (port) return NULL; } port = kmalloc(sizeof (struct zfcp_port), GFP_KERNEL); if (!port) return NULL; memset(port, 0, sizeof (struct zfcp_port)); /* initialise reference count stuff */ atomic_set(&port->refcount, 0); init_waitqueue_head(&port->remove_wq); INIT_LIST_HEAD(&port->unit_list_head); INIT_LIST_HEAD(&port->unit_remove_lh); port->adapter = adapter; if (check_wwpn) port->wwpn = wwpn; atomic_set_mask(status, &port->status); /* setup for sysfs registration */ if (status & ZFCP_STATUS_PORT_WKA) { switch (d_id) { case ZFCP_DID_DIRECTORY_SERVICE: snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "directory"); break; case ZFCP_DID_MANAGEMENT_SERVICE: snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "management"); break; case ZFCP_DID_KEY_DISTRIBUTION_SERVICE: snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "key_distribution"); break; case ZFCP_DID_ALIAS_SERVICE: snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "alias"); break; case ZFCP_DID_TIME_SERVICE: snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "time"); break; default: kfree(port); return NULL; } port->d_id = d_id; port->sysfs_device.parent = &adapter->generic_services; } else { snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", wwpn); port->sysfs_device.parent = &adapter->ccw_device->dev; } port->sysfs_device.release = zfcp_sysfs_port_release; dev_set_drvdata(&port->sysfs_device, port); /* mark port unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); if (device_register(&port->sysfs_device)) { kfree(port); return NULL; } if (zfcp_sysfs_port_create_files(&port->sysfs_device, status)) { device_unregister(&port->sysfs_device); return NULL; } zfcp_port_get(port); write_lock_irq(&zfcp_data.config_lock); list_add_tail(&port->list, &adapter->port_list_head); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status); if (d_id == ZFCP_DID_DIRECTORY_SERVICE) if (!adapter->nameserver_port) adapter->nameserver_port = port; adapter->ports++; write_unlock_irq(&zfcp_data.config_lock); zfcp_adapter_get(adapter); return port;}voidzfcp_port_dequeue(struct zfcp_port *port){ zfcp_port_wait(port); write_lock_irq(&zfcp_data.config_lock); list_del(&port->list); port->adapter->ports--; write_unlock_irq(&zfcp_data.config_lock); if (port->rport) fc_remote_port_delete(port->rport); port->rport = NULL; zfcp_adapter_put(port->adapter); zfcp_sysfs_port_remove_files(&port->sysfs_device, atomic_read(&port->status)); device_unregister(&port->sysfs_device);}/* Enqueues a nameserver port */intzfcp_nameserver_enqueue(struct zfcp_adapter *adapter){ struct zfcp_port *port; port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, ZFCP_DID_DIRECTORY_SERVICE); if (!port) { ZFCP_LOG_INFO("error: enqueue of nameserver port for " "adapter %s failed\n", zfcp_get_busid_by_adapter(adapter)); return -ENXIO; } zfcp_port_put(port); return 0;}#undef ZFCP_LOG_AREA/****************************************************************//******* Fibre Channel Standard related Functions **************//****************************************************************/#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FCvoidzfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter, struct fsf_status_read_buffer *status_buffer){ struct fcp_rscn_head *fcp_rscn_head; struct fcp_rscn_element *fcp_rscn_element; struct zfcp_port *port; u16 i; u16 no_entries; u32 range_mask; unsigned long flags; fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload; fcp_rscn_element = (struct fcp_rscn_element *) status_buffer->payload; /* see FC-FS */ no_entries = (fcp_rscn_head->payload_len / 4); for (i = 1; i < no_entries; i++) { /* skip head and start with 1st element */ fcp_rscn_element++; switch (fcp_rscn_element->addr_format) { case ZFCP_PORT_ADDRESS: range_mask = ZFCP_PORTS_RANGE_PORT; break; case ZFCP_AREA_ADDRESS: range_mask = ZFCP_PORTS_RANGE_AREA; break; case ZFCP_DOMAIN_ADDRESS: range_mask = ZFCP_PORTS_RANGE_DOMAIN; break; case ZFCP_FABRIC_ADDRESS: range_mask = ZFCP_PORTS_RANGE_FABRIC; break; default: ZFCP_LOG_INFO("incoming RSCN with unknown " "address format\n"); continue; } read_lock_irqsave(&zfcp_data.config_lock, flags); list_for_each_entry(port, &adapter->port_list_head, list) { if (atomic_test_mask (ZFCP_STATUS_PORT_WKA, &port->status)) continue; /* Do we know this port? If not skip it. */ if (!atomic_test_mask
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -