PageRenderTime 71ms CodeModel.GetById 60ms app.highlight 10ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/s390/scsi/zfcp_unit.c

https://bitbucket.org/wisechild/galaxy-nexus
C | 244 lines | 132 code | 38 blank | 74 comment | 15 complexity | bbbe7e21ae9581cf1d70046f3cbb6c7d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1/*
  2 * zfcp device driver
  3 *
  4 * Tracking of manually configured LUNs and helper functions to
  5 * register the LUNs with the SCSI midlayer.
  6 *
  7 * Copyright IBM Corporation 2010
  8 */
  9
 10#include "zfcp_def.h"
 11#include "zfcp_ext.h"
 12
 13/**
 14 * zfcp_unit_scsi_scan - Register LUN with SCSI midlayer
 15 * @unit: The zfcp LUN/unit to register
 16 *
 17 * When the SCSI midlayer is not allowed to automatically scan and
 18 * attach SCSI devices, zfcp has to register the single devices with
 19 * the SCSI midlayer.
 20 */
 21void zfcp_unit_scsi_scan(struct zfcp_unit *unit)
 22{
 23	struct fc_rport *rport = unit->port->rport;
 24	unsigned int lun;
 25
 26	lun = scsilun_to_int((struct scsi_lun *) &unit->fcp_lun);
 27
 28	if (rport && rport->port_state == FC_PORTSTATE_ONLINE)
 29		scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, lun, 1);
 30}
 31
 32static void zfcp_unit_scsi_scan_work(struct work_struct *work)
 33{
 34	struct zfcp_unit *unit = container_of(work, struct zfcp_unit,
 35					      scsi_work);
 36
 37	zfcp_unit_scsi_scan(unit);
 38	put_device(&unit->dev);
 39}
 40
 41/**
 42 * zfcp_unit_queue_scsi_scan - Register configured units on port
 43 * @port: The zfcp_port where to register units
 44 *
 45 * After opening a port, all units configured on this port have to be
 46 * registered with the SCSI midlayer. This function should be called
 47 * after calling fc_remote_port_add, so that the fc_rport is already
 48 * ONLINE and the call to scsi_scan_target runs the same way as the
 49 * call in the FC transport class.
 50 */
 51void zfcp_unit_queue_scsi_scan(struct zfcp_port *port)
 52{
 53	struct zfcp_unit *unit;
 54
 55	read_lock_irq(&port->unit_list_lock);
 56	list_for_each_entry(unit, &port->unit_list, list) {
 57		get_device(&unit->dev);
 58		if (scsi_queue_work(port->adapter->scsi_host,
 59				    &unit->scsi_work) <= 0)
 60			put_device(&unit->dev);
 61	}
 62	read_unlock_irq(&port->unit_list_lock);
 63}
 64
 65static struct zfcp_unit *_zfcp_unit_find(struct zfcp_port *port, u64 fcp_lun)
 66{
 67	struct zfcp_unit *unit;
 68
 69	list_for_each_entry(unit, &port->unit_list, list)
 70		if (unit->fcp_lun == fcp_lun) {
 71			get_device(&unit->dev);
 72			return unit;
 73		}
 74
 75	return NULL;
 76}
 77
 78/**
 79 * zfcp_unit_find - Find and return zfcp_unit with specified FCP LUN
 80 * @port: zfcp_port where to look for the unit
 81 * @fcp_lun: 64 Bit FCP LUN used to identify the zfcp_unit
 82 *
 83 * If zfcp_unit is found, a reference is acquired that has to be
 84 * released later.
 85 *
 86 * Returns: Pointer to the zfcp_unit, or NULL if there is no zfcp_unit
 87 *          with the specified FCP LUN.
 88 */
 89struct zfcp_unit *zfcp_unit_find(struct zfcp_port *port, u64 fcp_lun)
 90{
 91	struct zfcp_unit *unit;
 92
 93	read_lock_irq(&port->unit_list_lock);
 94	unit = _zfcp_unit_find(port, fcp_lun);
 95	read_unlock_irq(&port->unit_list_lock);
 96	return unit;
 97}
 98
 99/**
100 * zfcp_unit_release - Drop reference to zfcp_port and free memory of zfcp_unit.
101 * @dev: pointer to device in zfcp_unit
102 */
103static void zfcp_unit_release(struct device *dev)
104{
105	struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev);
106
107	put_device(&unit->port->dev);
108	kfree(unit);
109}
110
111/**
112 * zfcp_unit_enqueue - enqueue unit to unit list of a port.
113 * @port: pointer to port where unit is added
114 * @fcp_lun: FCP LUN of unit to be enqueued
115 * Returns: 0 success
116 *
117 * Sets up some unit internal structures and creates sysfs entry.
118 */
119int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
120{
121	struct zfcp_unit *unit;
122
123	unit = zfcp_unit_find(port, fcp_lun);
124	if (unit) {
125		put_device(&unit->dev);
126		return -EEXIST;
127	}
128
129	unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
130	if (!unit)
131		return -ENOMEM;
132
133	unit->port = port;
134	unit->fcp_lun = fcp_lun;
135	unit->dev.parent = &port->dev;
136	unit->dev.release = zfcp_unit_release;
137	INIT_WORK(&unit->scsi_work, zfcp_unit_scsi_scan_work);
138
139	if (dev_set_name(&unit->dev, "0x%016llx",
140			 (unsigned long long) fcp_lun)) {
141		kfree(unit);
142		return -ENOMEM;
143	}
144
145	get_device(&port->dev);
146
147	if (device_register(&unit->dev)) {
148		put_device(&unit->dev);
149		return -ENOMEM;
150	}
151
152	if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) {
153		device_unregister(&unit->dev);
154		return -EINVAL;
155	}
156
157	write_lock_irq(&port->unit_list_lock);
158	list_add_tail(&unit->list, &port->unit_list);
159	write_unlock_irq(&port->unit_list_lock);
160
161	zfcp_unit_scsi_scan(unit);
162
163	return 0;
164}
165
166/**
167 * zfcp_unit_sdev - Return SCSI device for zfcp_unit
168 * @unit: The zfcp_unit where to get the SCSI device for
169 *
170 * Returns: scsi_device pointer on success, NULL if there is no SCSI
171 *          device for this zfcp_unit
172 *
173 * On success, the caller also holds a reference to the SCSI device
174 * that must be released with scsi_device_put.
175 */
176struct scsi_device *zfcp_unit_sdev(struct zfcp_unit *unit)
177{
178	struct Scsi_Host *shost;
179	struct zfcp_port *port;
180	unsigned int lun;
181
182	lun = scsilun_to_int((struct scsi_lun *) &unit->fcp_lun);
183	port = unit->port;
184	shost = port->adapter->scsi_host;
185	return scsi_device_lookup(shost, 0, port->starget_id, lun);
186}
187
188/**
189 * zfcp_unit_sdev_status - Return zfcp LUN status for SCSI device
190 * @unit: The unit to lookup the SCSI device for
191 *
192 * Returns the zfcp LUN status field of the SCSI device if the SCSI device
193 * for the zfcp_unit exists, 0 otherwise.
194 */
195unsigned int zfcp_unit_sdev_status(struct zfcp_unit *unit)
196{
197	unsigned int status = 0;
198	struct scsi_device *sdev;
199	struct zfcp_scsi_dev *zfcp_sdev;
200
201	sdev = zfcp_unit_sdev(unit);
202	if (sdev) {
203		zfcp_sdev = sdev_to_zfcp(sdev);
204		status = atomic_read(&zfcp_sdev->status);
205		scsi_device_put(sdev);
206	}
207
208	return status;
209}
210
211/**
212 * zfcp_unit_remove - Remove entry from list of configured units
213 * @port: The port where to remove the unit from the configuration
214 * @fcp_lun: The 64 bit LUN of the unit to remove
215 *
216 * Returns: -EINVAL if a unit with the specified LUN does not exist,
217 *          0 on success.
218 */
219int zfcp_unit_remove(struct zfcp_port *port, u64 fcp_lun)
220{
221	struct zfcp_unit *unit;
222	struct scsi_device *sdev;
223
224	write_lock_irq(&port->unit_list_lock);
225	unit = _zfcp_unit_find(port, fcp_lun);
226	if (unit)
227		list_del(&unit->list);
228	write_unlock_irq(&port->unit_list_lock);
229
230	if (!unit)
231		return -EINVAL;
232
233	sdev = zfcp_unit_sdev(unit);
234	if (sdev) {
235		scsi_remove_device(sdev);
236		scsi_device_put(sdev);
237	}
238
239	put_device(&unit->dev);
240
241	zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs);
242
243	return 0;
244}