static void __init zfcp_init_device_configure(void) { struct zfcp_adapter *adapter; struct zfcp_port *port; struct zfcp_unit *unit; down(&zfcp_data.config_sema); read_lock_irq(&zfcp_data.config_lock); adapter = zfcp_get_adapter_by_busid(zfcp_data.init_busid); if (adapter) zfcp_adapter_get(adapter); read_unlock_irq(&zfcp_data.config_lock); if (!adapter) goto out_adapter; port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0); if (IS_ERR(port)) goto out_port; unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun); if (IS_ERR(unit)) goto out_unit; up(&zfcp_data.config_sema); ccw_device_set_online(adapter->ccw_device); zfcp_erp_wait(adapter); down(&zfcp_data.config_sema); zfcp_unit_put(unit); out_unit: zfcp_port_put(port); out_port: zfcp_adapter_put(adapter); out_adapter: up(&zfcp_data.config_sema); return; }
static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) { struct zfcp_adapter *adapter = act->adapter; struct zfcp_port *port = act->port; struct zfcp_unit *unit = act->unit; switch (act->action) { case ZFCP_ERP_ACTION_REOPEN_UNIT: zfcp_unit_put(unit); break; case ZFCP_ERP_ACTION_REOPEN_PORT: if (result == ZFCP_ERP_SUCCEEDED) zfcp_scsi_schedule_rport_register(port); /* fall through */ case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: zfcp_port_put(port); break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: if (result == ZFCP_ERP_SUCCEEDED) { register_service_level(&adapter->service_level); queue_work(adapter->work_queue, &adapter->scan_work); } else unregister_service_level(&adapter->service_level); zfcp_adapter_put(adapter); break; } }
static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) { struct zfcp_adapter *adapter = act->adapter; struct zfcp_port *port = act->port; struct zfcp_unit *unit = act->unit; switch (act->action) { case ZFCP_ERP_ACTION_REOPEN_UNIT: if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { zfcp_unit_get(unit); if (scsi_queue_work(unit->port->adapter->scsi_host, &unit->scsi_work) <= 0) zfcp_unit_put(unit); } zfcp_unit_put(unit); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: case ZFCP_ERP_ACTION_REOPEN_PORT: if (result == ZFCP_ERP_SUCCEEDED) zfcp_scsi_schedule_rport_register(port); zfcp_port_put(port); break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: if (result == ZFCP_ERP_SUCCEEDED) { register_service_level(&adapter->service_level); schedule_work(&adapter->scan_work); } else unregister_service_level(&adapter->service_level); zfcp_adapter_put(adapter); break; } }
/** * zfcp_sysfs_port_add_store - add a port to sysfs tree * @dev: pointer to belonging device * @buf: pointer to input buffer * @count: number of bytes in buffer * * Store function of the "port_add" attribute of an adapter. */ static ssize_t zfcp_sysfs_port_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { wwn_t wwpn; char *endp; struct zfcp_adapter *adapter; struct zfcp_port *port; int retval = -EINVAL; down(&zfcp_data.config_sema); adapter = dev_get_drvdata(dev); if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { retval = -EBUSY; goto out; } wwpn = simple_strtoull(buf, &endp, 0); if ((endp + 1) < (buf + count)) goto out; port = zfcp_port_enqueue(adapter, wwpn, 0, 0); if (!port) goto out; retval = 0; zfcp_erp_port_reopen(port, 0); zfcp_erp_wait(port->adapter); zfcp_port_put(port); out: up(&zfcp_data.config_sema); return retval ? retval : (ssize_t) count; }
/** * zfcp_port_dequeue - dequeues a port from the port list of the adapter * @port: pointer to struct zfcp_port which should be removed */ void zfcp_port_dequeue(struct zfcp_port *port) { write_lock_irq(&zfcp_data.config_lock); list_del(&port->list); write_unlock_irq(&zfcp_data.config_lock); if (cancel_work_sync(&port->gid_pn_work)) zfcp_port_put(port); if (cancel_work_sync(&port->rport_work)) zfcp_port_put(port); if (cancel_work_sync(&port->test_link_work)) zfcp_port_put(port); wait_event(port->remove_wq, atomic_read(&port->refcount) == 0); zfcp_adapter_put(port->adapter); sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs); device_unregister(&port->sysfs_device); }
static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter) { struct zfcp_port *port; port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0, adapter->peer_d_id); if (IS_ERR(port)) /* error or port already attached */ return; _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL); zfcp_port_put(port); }
/** * zfcp_unit_dequeue - dequeue unit * @unit: pointer to zfcp_unit * * waits until all work is done on unit and removes it then from the unit->list * of the associated port. */ void zfcp_unit_dequeue(struct zfcp_unit *unit) { wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0); write_lock_irq(&zfcp_data.config_lock); list_del(&unit->list); write_unlock_irq(&zfcp_data.config_lock); zfcp_port_put(unit->port); sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs); device_unregister(&unit->sysfs_device); }
/** * zfcp_unit_dequeue - dequeue unit * @unit: pointer to zfcp_unit * * waits until all work is done on unit and removes it then from the unit->list * of the associated port. */ void zfcp_unit_dequeue(struct zfcp_unit *unit) { zfcp_unit_wait(unit); write_lock_irq(&zfcp_data.config_lock); list_del(&unit->list); write_unlock_irq(&zfcp_data.config_lock); unit->port->units--; zfcp_port_put(unit->port); sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs); device_unregister(&unit->sysfs_device); }
static int zfcp_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 (IS_ERR(port)) return PTR_ERR(port); zfcp_port_put(port); return 0; }
void zfcp_erp_port_strategy_open_lookup(struct work_struct *work) { int retval; struct zfcp_port *port = container_of(work, struct zfcp_port, gid_pn_work); retval = zfcp_fc_ns_gid_pn(&port->erp_action); if (retval == -ENOMEM) zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM); port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; if (retval) zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED); zfcp_port_put(port); }
/** * zfcp_sysfs_port_remove_store - remove a port from sysfs tree * @dev: pointer to belonging device * @buf: pointer to input buffer * @count: number of bytes in buffer * * Store function of the "port_remove" attribute of an adapter. */ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct zfcp_adapter *adapter; struct zfcp_port *port; wwn_t wwpn; char *endp; int retval = 0; down(&zfcp_data.config_sema); adapter = dev_get_drvdata(dev); if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { retval = -EBUSY; goto out; } wwpn = simple_strtoull(buf, &endp, 0); if ((endp + 1) < (buf + count)) { retval = -EINVAL; goto out; } write_lock_irq(&zfcp_data.config_lock); port = zfcp_get_port_by_wwpn(adapter, wwpn); if (port && (atomic_read(&port->refcount) == 0)) { zfcp_port_get(port); atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); list_move(&port->list, &adapter->port_remove_lh); } else { port = NULL; } write_unlock_irq(&zfcp_data.config_lock); if (!port) { retval = -ENXIO; goto out; } zfcp_erp_port_shutdown(port, 0); zfcp_erp_wait(adapter); zfcp_port_put(port); zfcp_port_dequeue(port); out: up(&zfcp_data.config_sema); return retval ? retval : (ssize_t) count; }
static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) { struct ccw_device *ccwdev; struct zfcp_adapter *adapter; struct zfcp_port *port; struct zfcp_unit *unit; ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); if (!ccwdev) return; if (ccw_device_set_online(ccwdev)) goto out_ccwdev; mutex_lock(&zfcp_data.config_mutex); adapter = dev_get_drvdata(&ccwdev->dev); if (!adapter) goto out_unlock; zfcp_adapter_get(adapter); port = zfcp_get_port_by_wwpn(adapter, wwpn); if (!port) goto out_port; zfcp_port_get(port); unit = zfcp_unit_enqueue(port, lun); if (IS_ERR(unit)) goto out_unit; mutex_unlock(&zfcp_data.config_mutex); zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL); zfcp_erp_wait(adapter); flush_work(&unit->scsi_work); mutex_lock(&zfcp_data.config_mutex); zfcp_unit_put(unit); out_unit: zfcp_port_put(port); out_port: zfcp_adapter_put(adapter); out_unlock: mutex_unlock(&zfcp_data.config_mutex); out_ccwdev: put_device(&ccwdev->dev); return; }
static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct zfcp_adapter *adapter = dev_get_drvdata(dev); struct zfcp_port *port; u64 wwpn; int retval = 0; LIST_HEAD(port_remove_lh); mutex_lock(&zfcp_data.config_mutex); if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { retval = -EBUSY; goto out; } if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn)) { retval = -EINVAL; goto out; } write_lock_irq(&zfcp_data.config_lock); port = zfcp_get_port_by_wwpn(adapter, wwpn); if (port && (atomic_read(&port->refcount) == 0)) { zfcp_port_get(port); atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); list_move(&port->list, &port_remove_lh); } else port = NULL; write_unlock_irq(&zfcp_data.config_lock); if (!port) { retval = -ENXIO; goto out; } zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL); zfcp_erp_wait(adapter); zfcp_port_put(port); zfcp_port_dequeue(port); out: mutex_unlock(&zfcp_data.config_mutex); return retval ? retval : (ssize_t) count; }
static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) { struct zfcp_adapter *adapter = act->adapter; struct zfcp_port *port = act->port; int p_status = atomic_read(&port->status); switch (act->step) { case ZFCP_ERP_STEP_UNINITIALIZED: case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: case ZFCP_ERP_STEP_PORT_CLOSING: if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) return zfcp_erp_open_ptp_port(act); if (!port->d_id) { zfcp_port_get(port); if (!queue_work(adapter->work_queue, &port->gid_pn_work)) zfcp_port_put(port); return ZFCP_ERP_EXIT; } return zfcp_erp_port_strategy_open_port(act); case ZFCP_ERP_STEP_PORT_OPENING: /* D_ID might have changed during open */ if (p_status & ZFCP_STATUS_COMMON_OPEN) { if (port->d_id) return ZFCP_ERP_SUCCEEDED; else { act->step = ZFCP_ERP_STEP_PORT_CLOSING; return ZFCP_ERP_CONTINUES; } } if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) { port->d_id = 0; _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL); return ZFCP_ERP_EXIT; } /* fall through otherwise */ } return ZFCP_ERP_FAILED; }
static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) { struct zfcp_adapter *adapter; struct zfcp_port *port; struct zfcp_unit *unit; down(&zfcp_data.config_sema); read_lock_irq(&zfcp_data.config_lock); adapter = zfcp_get_adapter_by_busid(busid); if (adapter) zfcp_adapter_get(adapter); read_unlock_irq(&zfcp_data.config_lock); if (!adapter) goto out_adapter; port = zfcp_port_enqueue(adapter, wwpn, 0, 0); if (IS_ERR(port)) goto out_port; unit = zfcp_unit_enqueue(port, lun); if (IS_ERR(unit)) goto out_unit; up(&zfcp_data.config_sema); ccw_device_set_online(adapter->ccw_device); zfcp_erp_wait(adapter); wait_event(adapter->erp_done_wqh, !(atomic_read(&unit->status) & ZFCP_STATUS_UNIT_SCSI_WORK_PENDING)); down(&zfcp_data.config_sema); zfcp_unit_put(unit); out_unit: zfcp_port_put(port); out_port: zfcp_adapter_put(adapter); out_adapter: up(&zfcp_data.config_sema); return; }
static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) { struct zfcp_adapter *adapter; struct zfcp_port *port; struct zfcp_unit *unit; mutex_lock(&zfcp_data.config_mutex); read_lock_irq(&zfcp_data.config_lock); adapter = zfcp_get_adapter_by_busid(busid); if (adapter) zfcp_adapter_get(adapter); read_unlock_irq(&zfcp_data.config_lock); if (!adapter) goto out_adapter; port = zfcp_port_enqueue(adapter, wwpn, 0, 0); if (IS_ERR(port)) goto out_port; unit = zfcp_unit_enqueue(port, lun); if (IS_ERR(unit)) goto out_unit; mutex_unlock(&zfcp_data.config_mutex); ccw_device_set_online(adapter->ccw_device); zfcp_erp_wait(adapter); flush_work(&unit->scsi_work); mutex_lock(&zfcp_data.config_mutex); zfcp_unit_put(unit); out_unit: zfcp_port_put(port); out_port: zfcp_adapter_put(adapter); out_adapter: mutex_unlock(&zfcp_data.config_mutex); return; }