aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/s390/scsi/zfcp_ext.h1
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c9
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c54
-rw-r--r--drivers/s390/scsi/zfcp_unit.c8
4 files changed, 65 insertions, 7 deletions
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index c6acca521ffe..31e8a7240fd7 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -167,6 +167,7 @@ extern const struct attribute_group *zfcp_port_attr_groups[];
167extern struct mutex zfcp_sysfs_port_units_mutex; 167extern struct mutex zfcp_sysfs_port_units_mutex;
168extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; 168extern struct device_attribute *zfcp_sysfs_sdev_attrs[];
169extern struct device_attribute *zfcp_sysfs_shost_attrs[]; 169extern struct device_attribute *zfcp_sysfs_shost_attrs[];
170bool zfcp_sysfs_port_is_removing(const struct zfcp_port *const port);
170 171
171/* zfcp_unit.c */ 172/* zfcp_unit.c */
172extern int zfcp_unit_add(struct zfcp_port *, u64); 173extern int zfcp_unit_add(struct zfcp_port *, u64);
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 221d0dfb8493..e9ded2befa0d 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -129,6 +129,15 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev)
129 129
130 zfcp_sdev->erp_action.port = port; 130 zfcp_sdev->erp_action.port = port;
131 131
132 mutex_lock(&zfcp_sysfs_port_units_mutex);
133 if (zfcp_sysfs_port_is_removing(port)) {
134 /* port is already gone */
135 mutex_unlock(&zfcp_sysfs_port_units_mutex);
136 put_device(&port->dev); /* undo zfcp_get_port_by_wwpn() */
137 return -ENXIO;
138 }
139 mutex_unlock(&zfcp_sysfs_port_units_mutex);
140
132 unit = zfcp_unit_find(port, zfcp_scsi_dev_lun(sdev)); 141 unit = zfcp_unit_find(port, zfcp_scsi_dev_lun(sdev));
133 if (unit) 142 if (unit)
134 put_device(&unit->dev); 143 put_device(&unit->dev);
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index 2d78732b270b..af197e2b3e69 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -235,6 +235,53 @@ static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL,
235 235
236DEFINE_MUTEX(zfcp_sysfs_port_units_mutex); 236DEFINE_MUTEX(zfcp_sysfs_port_units_mutex);
237 237
238static void zfcp_sysfs_port_set_removing(struct zfcp_port *const port)
239{
240 lockdep_assert_held(&zfcp_sysfs_port_units_mutex);
241 atomic_set(&port->units, -1);
242}
243
244bool zfcp_sysfs_port_is_removing(const struct zfcp_port *const port)
245{
246 lockdep_assert_held(&zfcp_sysfs_port_units_mutex);
247 return atomic_read(&port->units) == -1;
248}
249
250static bool zfcp_sysfs_port_in_use(struct zfcp_port *const port)
251{
252 struct zfcp_adapter *const adapter = port->adapter;
253 unsigned long flags;
254 struct scsi_device *sdev;
255 bool in_use = true;
256
257 mutex_lock(&zfcp_sysfs_port_units_mutex);
258 if (atomic_read(&port->units) > 0)
259 goto unlock_port_units_mutex; /* zfcp_unit(s) under port */
260
261 spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
262 __shost_for_each_device(sdev, adapter->scsi_host) {
263 const struct zfcp_scsi_dev *zsdev = sdev_to_zfcp(sdev);
264
265 if (sdev->sdev_state == SDEV_DEL ||
266 sdev->sdev_state == SDEV_CANCEL)
267 continue;
268 if (zsdev->port != port)
269 continue;
270 /* alive scsi_device under port of interest */
271 goto unlock_host_lock;
272 }
273
274 /* port is about to be removed, so no more unit_add or slave_alloc */
275 zfcp_sysfs_port_set_removing(port);
276 in_use = false;
277
278unlock_host_lock:
279 spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
280unlock_port_units_mutex:
281 mutex_unlock(&zfcp_sysfs_port_units_mutex);
282 return in_use;
283}
284
238static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, 285static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
239 struct device_attribute *attr, 286 struct device_attribute *attr,
240 const char *buf, size_t count) 287 const char *buf, size_t count)
@@ -257,16 +304,11 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
257 else 304 else
258 retval = 0; 305 retval = 0;
259 306
260 mutex_lock(&zfcp_sysfs_port_units_mutex); 307 if (zfcp_sysfs_port_in_use(port)) {
261 if (atomic_read(&port->units) > 0) {
262 retval = -EBUSY; 308 retval = -EBUSY;
263 mutex_unlock(&zfcp_sysfs_port_units_mutex);
264 put_device(&port->dev); /* undo zfcp_get_port_by_wwpn() */ 309 put_device(&port->dev); /* undo zfcp_get_port_by_wwpn() */
265 goto out; 310 goto out;
266 } 311 }
267 /* port is about to be removed, so no more unit_add */
268 atomic_set(&port->units, -1);
269 mutex_unlock(&zfcp_sysfs_port_units_mutex);
270 312
271 write_lock_irq(&adapter->port_list_lock); 313 write_lock_irq(&adapter->port_list_lock);
272 list_del(&port->list); 314 list_del(&port->list);
diff --git a/drivers/s390/scsi/zfcp_unit.c b/drivers/s390/scsi/zfcp_unit.c
index 1bf0a0984a09..e67bf7388cae 100644
--- a/drivers/s390/scsi/zfcp_unit.c
+++ b/drivers/s390/scsi/zfcp_unit.c
@@ -124,7 +124,7 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
124 int retval = 0; 124 int retval = 0;
125 125
126 mutex_lock(&zfcp_sysfs_port_units_mutex); 126 mutex_lock(&zfcp_sysfs_port_units_mutex);
127 if (atomic_read(&port->units) == -1) { 127 if (zfcp_sysfs_port_is_removing(port)) {
128 /* port is already gone */ 128 /* port is already gone */
129 retval = -ENODEV; 129 retval = -ENODEV;
130 goto out; 130 goto out;
@@ -168,8 +168,14 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
168 write_lock_irq(&port->unit_list_lock); 168 write_lock_irq(&port->unit_list_lock);
169 list_add_tail(&unit->list, &port->unit_list); 169 list_add_tail(&unit->list, &port->unit_list);
170 write_unlock_irq(&port->unit_list_lock); 170 write_unlock_irq(&port->unit_list_lock);
171 /*
172 * lock order: shost->scan_mutex before zfcp_sysfs_port_units_mutex
173 * due to zfcp_unit_scsi_scan() => zfcp_scsi_slave_alloc()
174 */
175 mutex_unlock(&zfcp_sysfs_port_units_mutex);
171 176
172 zfcp_unit_scsi_scan(unit); 177 zfcp_unit_scsi_scan(unit);
178 return retval;
173 179
174out: 180out:
175 mutex_unlock(&zfcp_sysfs_port_units_mutex); 181 mutex_unlock(&zfcp_sysfs_port_units_mutex);