diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 1 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 9 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_sysfs.c | 54 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_unit.c | 8 |
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[]; | |||
| 167 | extern struct mutex zfcp_sysfs_port_units_mutex; | 167 | extern struct mutex zfcp_sysfs_port_units_mutex; |
| 168 | extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; | 168 | extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; |
| 169 | extern struct device_attribute *zfcp_sysfs_shost_attrs[]; | 169 | extern struct device_attribute *zfcp_sysfs_shost_attrs[]; |
| 170 | bool zfcp_sysfs_port_is_removing(const struct zfcp_port *const port); | ||
| 170 | 171 | ||
| 171 | /* zfcp_unit.c */ | 172 | /* zfcp_unit.c */ |
| 172 | extern int zfcp_unit_add(struct zfcp_port *, u64); | 173 | extern 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 | ||
| 236 | DEFINE_MUTEX(zfcp_sysfs_port_units_mutex); | 236 | DEFINE_MUTEX(zfcp_sysfs_port_units_mutex); |
| 237 | 237 | ||
| 238 | static 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 | |||
| 244 | bool 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 | |||
| 250 | static 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 | |||
| 278 | unlock_host_lock: | ||
| 279 | spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags); | ||
| 280 | unlock_port_units_mutex: | ||
| 281 | mutex_unlock(&zfcp_sysfs_port_units_mutex); | ||
| 282 | return in_use; | ||
| 283 | } | ||
| 284 | |||
| 238 | static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, | 285 | static 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 | ||
| 174 | out: | 180 | out: |
| 175 | mutex_unlock(&zfcp_sysfs_port_units_mutex); | 181 | mutex_unlock(&zfcp_sysfs_port_units_mutex); |
