diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ccw.c | 80 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_cfdc.c | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.c | 22 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.h | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 4 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 23 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 59 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_qdio.c | 16 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_sysfs.c | 18 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_unit.c | 36 |
13 files changed, 223 insertions, 43 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index aff8621de806..f6adde44f226 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -519,6 +519,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, | |||
519 | 519 | ||
520 | rwlock_init(&port->unit_list_lock); | 520 | rwlock_init(&port->unit_list_lock); |
521 | INIT_LIST_HEAD(&port->unit_list); | 521 | INIT_LIST_HEAD(&port->unit_list); |
522 | atomic_set(&port->units, 0); | ||
522 | 523 | ||
523 | INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup); | 524 | INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup); |
524 | INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); | 525 | INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); |
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index e37f04551948..f2dd3a0a39eb 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c | |||
@@ -39,19 +39,25 @@ void zfcp_ccw_adapter_put(struct zfcp_adapter *adapter) | |||
39 | spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags); | 39 | spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags); |
40 | } | 40 | } |
41 | 41 | ||
42 | static int zfcp_ccw_activate(struct ccw_device *cdev) | 42 | /** |
43 | 43 | * zfcp_ccw_activate - activate adapter and wait for it to finish | |
44 | * @cdev: pointer to belonging ccw device | ||
45 | * @clear: Status flags to clear. | ||
46 | * @tag: s390dbf trace record tag | ||
47 | */ | ||
48 | static int zfcp_ccw_activate(struct ccw_device *cdev, int clear, char *tag) | ||
44 | { | 49 | { |
45 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); | 50 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
46 | 51 | ||
47 | if (!adapter) | 52 | if (!adapter) |
48 | return 0; | 53 | return 0; |
49 | 54 | ||
55 | zfcp_erp_clear_adapter_status(adapter, clear); | ||
50 | zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); | 56 | zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING); |
51 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, | 57 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, |
52 | "ccresu2"); | 58 | tag); |
53 | zfcp_erp_wait(adapter); | 59 | zfcp_erp_wait(adapter); |
54 | flush_work(&adapter->scan_work); | 60 | flush_work(&adapter->scan_work); /* ok to call even if nothing queued */ |
55 | 61 | ||
56 | zfcp_ccw_adapter_put(adapter); | 62 | zfcp_ccw_adapter_put(adapter); |
57 | 63 | ||
@@ -164,26 +170,34 @@ static int zfcp_ccw_set_online(struct ccw_device *cdev) | |||
164 | BUG_ON(!zfcp_reqlist_isempty(adapter->req_list)); | 170 | BUG_ON(!zfcp_reqlist_isempty(adapter->req_list)); |
165 | adapter->req_no = 0; | 171 | adapter->req_no = 0; |
166 | 172 | ||
167 | zfcp_ccw_activate(cdev); | 173 | zfcp_ccw_activate(cdev, 0, "ccsonl1"); |
174 | /* scan for remote ports | ||
175 | either at the end of any successful adapter recovery | ||
176 | or only after the adapter recovery for setting a device online */ | ||
177 | zfcp_fc_inverse_conditional_port_scan(adapter); | ||
178 | flush_work(&adapter->scan_work); /* ok to call even if nothing queued */ | ||
168 | zfcp_ccw_adapter_put(adapter); | 179 | zfcp_ccw_adapter_put(adapter); |
169 | return 0; | 180 | return 0; |
170 | } | 181 | } |
171 | 182 | ||
172 | /** | 183 | /** |
173 | * zfcp_ccw_set_offline - set_offline function of zfcp driver | 184 | * zfcp_ccw_offline_sync - shut down adapter and wait for it to finish |
174 | * @cdev: pointer to belonging ccw device | 185 | * @cdev: pointer to belonging ccw device |
186 | * @set: Status flags to set. | ||
187 | * @tag: s390dbf trace record tag | ||
175 | * | 188 | * |
176 | * This function gets called by the common i/o layer and sets an adapter | 189 | * This function gets called by the common i/o layer and sets an adapter |
177 | * into state offline. | 190 | * into state offline. |
178 | */ | 191 | */ |
179 | static int zfcp_ccw_set_offline(struct ccw_device *cdev) | 192 | static int zfcp_ccw_offline_sync(struct ccw_device *cdev, int set, char *tag) |
180 | { | 193 | { |
181 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); | 194 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
182 | 195 | ||
183 | if (!adapter) | 196 | if (!adapter) |
184 | return 0; | 197 | return 0; |
185 | 198 | ||
186 | zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1"); | 199 | zfcp_erp_set_adapter_status(adapter, set); |
200 | zfcp_erp_adapter_shutdown(adapter, 0, tag); | ||
187 | zfcp_erp_wait(adapter); | 201 | zfcp_erp_wait(adapter); |
188 | 202 | ||
189 | zfcp_ccw_adapter_put(adapter); | 203 | zfcp_ccw_adapter_put(adapter); |
@@ -191,6 +205,18 @@ static int zfcp_ccw_set_offline(struct ccw_device *cdev) | |||
191 | } | 205 | } |
192 | 206 | ||
193 | /** | 207 | /** |
208 | * zfcp_ccw_set_offline - set_offline function of zfcp driver | ||
209 | * @cdev: pointer to belonging ccw device | ||
210 | * | ||
211 | * This function gets called by the common i/o layer and sets an adapter | ||
212 | * into state offline. | ||
213 | */ | ||
214 | static int zfcp_ccw_set_offline(struct ccw_device *cdev) | ||
215 | { | ||
216 | return zfcp_ccw_offline_sync(cdev, 0, "ccsoff1"); | ||
217 | } | ||
218 | |||
219 | /** | ||
194 | * zfcp_ccw_notify - ccw notify function | 220 | * zfcp_ccw_notify - ccw notify function |
195 | * @cdev: pointer to belonging ccw device | 221 | * @cdev: pointer to belonging ccw device |
196 | * @event: indicates if adapter was detached or attached | 222 | * @event: indicates if adapter was detached or attached |
@@ -207,6 +233,11 @@ static int zfcp_ccw_notify(struct ccw_device *cdev, int event) | |||
207 | 233 | ||
208 | switch (event) { | 234 | switch (event) { |
209 | case CIO_GONE: | 235 | case CIO_GONE: |
236 | if (atomic_read(&adapter->status) & | ||
237 | ZFCP_STATUS_ADAPTER_SUSPENDED) { /* notification ignore */ | ||
238 | zfcp_dbf_hba_basic("ccnigo1", adapter); | ||
239 | break; | ||
240 | } | ||
210 | dev_warn(&cdev->dev, "The FCP device has been detached\n"); | 241 | dev_warn(&cdev->dev, "The FCP device has been detached\n"); |
211 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1"); | 242 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1"); |
212 | break; | 243 | break; |
@@ -216,6 +247,11 @@ static int zfcp_ccw_notify(struct ccw_device *cdev, int event) | |||
216 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2"); | 247 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2"); |
217 | break; | 248 | break; |
218 | case CIO_OPER: | 249 | case CIO_OPER: |
250 | if (atomic_read(&adapter->status) & | ||
251 | ZFCP_STATUS_ADAPTER_SUSPENDED) { /* notification ignore */ | ||
252 | zfcp_dbf_hba_basic("ccniop1", adapter); | ||
253 | break; | ||
254 | } | ||
219 | dev_info(&cdev->dev, "The FCP device is operational again\n"); | 255 | dev_info(&cdev->dev, "The FCP device is operational again\n"); |
220 | zfcp_erp_set_adapter_status(adapter, | 256 | zfcp_erp_set_adapter_status(adapter, |
221 | ZFCP_STATUS_COMMON_RUNNING); | 257 | ZFCP_STATUS_COMMON_RUNNING); |
@@ -251,6 +287,28 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev) | |||
251 | zfcp_ccw_adapter_put(adapter); | 287 | zfcp_ccw_adapter_put(adapter); |
252 | } | 288 | } |
253 | 289 | ||
290 | static int zfcp_ccw_suspend(struct ccw_device *cdev) | ||
291 | { | ||
292 | zfcp_ccw_offline_sync(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccsusp1"); | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static int zfcp_ccw_thaw(struct ccw_device *cdev) | ||
297 | { | ||
298 | /* trace records for thaw and final shutdown during suspend | ||
299 | can only be found in system dump until the end of suspend | ||
300 | but not after resume because it's based on the memory image | ||
301 | right after the very first suspend (freeze) callback */ | ||
302 | zfcp_ccw_activate(cdev, 0, "ccthaw1"); | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int zfcp_ccw_resume(struct ccw_device *cdev) | ||
307 | { | ||
308 | zfcp_ccw_activate(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccresu1"); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
254 | struct ccw_driver zfcp_ccw_driver = { | 312 | struct ccw_driver zfcp_ccw_driver = { |
255 | .driver = { | 313 | .driver = { |
256 | .owner = THIS_MODULE, | 314 | .owner = THIS_MODULE, |
@@ -263,7 +321,7 @@ struct ccw_driver zfcp_ccw_driver = { | |||
263 | .set_offline = zfcp_ccw_set_offline, | 321 | .set_offline = zfcp_ccw_set_offline, |
264 | .notify = zfcp_ccw_notify, | 322 | .notify = zfcp_ccw_notify, |
265 | .shutdown = zfcp_ccw_shutdown, | 323 | .shutdown = zfcp_ccw_shutdown, |
266 | .freeze = zfcp_ccw_set_offline, | 324 | .freeze = zfcp_ccw_suspend, |
267 | .thaw = zfcp_ccw_activate, | 325 | .thaw = zfcp_ccw_thaw, |
268 | .restore = zfcp_ccw_activate, | 326 | .restore = zfcp_ccw_resume, |
269 | }; | 327 | }; |
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index fbd8b4db6025..49b82e46629e 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c | |||
@@ -293,7 +293,7 @@ void zfcp_cfdc_adapter_access_changed(struct zfcp_adapter *adapter) | |||
293 | } | 293 | } |
294 | read_unlock_irqrestore(&adapter->port_list_lock, flags); | 294 | read_unlock_irqrestore(&adapter->port_list_lock, flags); |
295 | 295 | ||
296 | shost_for_each_device(sdev, port->adapter->scsi_host) { | 296 | shost_for_each_device(sdev, adapter->scsi_host) { |
297 | zfcp_sdev = sdev_to_zfcp(sdev); | 297 | zfcp_sdev = sdev_to_zfcp(sdev); |
298 | status = atomic_read(&zfcp_sdev->status); | 298 | status = atomic_read(&zfcp_sdev->status); |
299 | if ((status & ZFCP_STATUS_COMMON_ACCESS_DENIED) || | 299 | if ((status & ZFCP_STATUS_COMMON_ACCESS_DENIED) || |
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 3c1d22097ad0..e1a8cc2526e7 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c | |||
@@ -191,7 +191,7 @@ void zfcp_dbf_hba_def_err(struct zfcp_adapter *adapter, u64 req_id, u16 scount, | |||
191 | length = min((u16)sizeof(struct qdio_buffer), | 191 | length = min((u16)sizeof(struct qdio_buffer), |
192 | (u16)ZFCP_DBF_PAY_MAX_REC); | 192 | (u16)ZFCP_DBF_PAY_MAX_REC); |
193 | 193 | ||
194 | while ((char *)pl[payload->counter] && payload->counter < scount) { | 194 | while (payload->counter < scount && (char *)pl[payload->counter]) { |
195 | memcpy(payload->data, (char *)pl[payload->counter], length); | 195 | memcpy(payload->data, (char *)pl[payload->counter], length); |
196 | debug_event(dbf->pay, 1, payload, zfcp_dbf_plen(length)); | 196 | debug_event(dbf->pay, 1, payload, zfcp_dbf_plen(length)); |
197 | payload->counter++; | 197 | payload->counter++; |
@@ -200,6 +200,26 @@ void zfcp_dbf_hba_def_err(struct zfcp_adapter *adapter, u64 req_id, u16 scount, | |||
200 | spin_unlock_irqrestore(&dbf->pay_lock, flags); | 200 | spin_unlock_irqrestore(&dbf->pay_lock, flags); |
201 | } | 201 | } |
202 | 202 | ||
203 | /** | ||
204 | * zfcp_dbf_hba_basic - trace event for basic adapter events | ||
205 | * @adapter: pointer to struct zfcp_adapter | ||
206 | */ | ||
207 | void zfcp_dbf_hba_basic(char *tag, struct zfcp_adapter *adapter) | ||
208 | { | ||
209 | struct zfcp_dbf *dbf = adapter->dbf; | ||
210 | struct zfcp_dbf_hba *rec = &dbf->hba_buf; | ||
211 | unsigned long flags; | ||
212 | |||
213 | spin_lock_irqsave(&dbf->hba_lock, flags); | ||
214 | memset(rec, 0, sizeof(*rec)); | ||
215 | |||
216 | memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); | ||
217 | rec->id = ZFCP_DBF_HBA_BASIC; | ||
218 | |||
219 | debug_event(dbf->hba, 1, rec, sizeof(*rec)); | ||
220 | spin_unlock_irqrestore(&dbf->hba_lock, flags); | ||
221 | } | ||
222 | |||
203 | static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec, | 223 | static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec, |
204 | struct zfcp_adapter *adapter, | 224 | struct zfcp_adapter *adapter, |
205 | struct zfcp_port *port, | 225 | struct zfcp_port *port, |
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 714f087eb7a9..3ac7a4b30dd9 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h | |||
@@ -154,6 +154,7 @@ enum zfcp_dbf_hba_id { | |||
154 | ZFCP_DBF_HBA_RES = 1, | 154 | ZFCP_DBF_HBA_RES = 1, |
155 | ZFCP_DBF_HBA_USS = 2, | 155 | ZFCP_DBF_HBA_USS = 2, |
156 | ZFCP_DBF_HBA_BIT = 3, | 156 | ZFCP_DBF_HBA_BIT = 3, |
157 | ZFCP_DBF_HBA_BASIC = 4, | ||
157 | }; | 158 | }; |
158 | 159 | ||
159 | /** | 160 | /** |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 2955e1a3deaf..1305955cbf59 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -77,6 +77,7 @@ struct zfcp_reqlist; | |||
77 | #define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED 0x00000004 | 77 | #define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED 0x00000004 |
78 | #define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008 | 78 | #define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008 |
79 | #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010 | 79 | #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010 |
80 | #define ZFCP_STATUS_ADAPTER_SUSPENDED 0x00000040 | ||
80 | #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 | 81 | #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 |
81 | #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200 | 82 | #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200 |
82 | #define ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED 0x00000400 | 83 | #define ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED 0x00000400 |
@@ -204,6 +205,7 @@ struct zfcp_port { | |||
204 | struct zfcp_adapter *adapter; /* adapter used to access port */ | 205 | struct zfcp_adapter *adapter; /* adapter used to access port */ |
205 | struct list_head unit_list; /* head of logical unit list */ | 206 | struct list_head unit_list; /* head of logical unit list */ |
206 | rwlock_t unit_list_lock; /* unit list lock */ | 207 | rwlock_t unit_list_lock; /* unit list lock */ |
208 | atomic_t units; /* zfcp_unit count */ | ||
207 | atomic_t status; /* status of this remote port */ | 209 | atomic_t status; /* status of this remote port */ |
208 | u64 wwnn; /* WWNN if known */ | 210 | u64 wwnn; /* WWNN if known */ |
209 | u64 wwpn; /* WWPN */ | 211 | u64 wwpn; /* WWPN */ |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 92d3df6ac8ba..4133ab6e20f1 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -1230,7 +1230,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) | |||
1230 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 1230 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
1231 | if (result == ZFCP_ERP_SUCCEEDED) { | 1231 | if (result == ZFCP_ERP_SUCCEEDED) { |
1232 | register_service_level(&adapter->service_level); | 1232 | register_service_level(&adapter->service_level); |
1233 | queue_work(adapter->work_queue, &adapter->scan_work); | 1233 | zfcp_fc_conditional_port_scan(adapter); |
1234 | queue_work(adapter->work_queue, &adapter->ns_up_work); | 1234 | queue_work(adapter->work_queue, &adapter->ns_up_work); |
1235 | } else | 1235 | } else |
1236 | unregister_service_level(&adapter->service_level); | 1236 | unregister_service_level(&adapter->service_level); |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 36f422770ff5..1d3dd3f7d699 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -54,6 +54,7 @@ extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *); | |||
54 | extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *); | 54 | extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *); |
55 | extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *); | 55 | extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *); |
56 | extern void zfcp_dbf_hba_def_err(struct zfcp_adapter *, u64, u16, void **); | 56 | extern void zfcp_dbf_hba_def_err(struct zfcp_adapter *, u64, u16, void **); |
57 | extern void zfcp_dbf_hba_basic(char *, struct zfcp_adapter *); | ||
57 | extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32); | 58 | extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32); |
58 | extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *); | 59 | extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *); |
59 | extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *); | 60 | extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *); |
@@ -98,6 +99,8 @@ extern void zfcp_fc_gs_destroy(struct zfcp_adapter *); | |||
98 | extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *); | 99 | extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *); |
99 | extern int zfcp_fc_timeout_bsg_job(struct fc_bsg_job *); | 100 | extern int zfcp_fc_timeout_bsg_job(struct fc_bsg_job *); |
100 | extern void zfcp_fc_sym_name_update(struct work_struct *); | 101 | extern void zfcp_fc_sym_name_update(struct work_struct *); |
102 | extern void zfcp_fc_conditional_port_scan(struct zfcp_adapter *); | ||
103 | extern void zfcp_fc_inverse_conditional_port_scan(struct zfcp_adapter *); | ||
101 | 104 | ||
102 | /* zfcp_fsf.c */ | 105 | /* zfcp_fsf.c */ |
103 | extern struct kmem_cache *zfcp_fsf_qtcb_cache; | 106 | extern struct kmem_cache *zfcp_fsf_qtcb_cache; |
@@ -158,6 +161,7 @@ extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int); | |||
158 | extern struct attribute_group zfcp_sysfs_unit_attrs; | 161 | extern struct attribute_group zfcp_sysfs_unit_attrs; |
159 | extern struct attribute_group zfcp_sysfs_adapter_attrs; | 162 | extern struct attribute_group zfcp_sysfs_adapter_attrs; |
160 | extern struct attribute_group zfcp_sysfs_port_attrs; | 163 | extern struct attribute_group zfcp_sysfs_port_attrs; |
164 | extern struct mutex zfcp_sysfs_port_units_mutex; | ||
161 | extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; | 165 | extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; |
162 | extern struct device_attribute *zfcp_sysfs_shost_attrs[]; | 166 | extern struct device_attribute *zfcp_sysfs_shost_attrs[]; |
163 | 167 | ||
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 88688a80b2c1..ff598cd68b2d 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -26,6 +26,27 @@ static u32 zfcp_fc_rscn_range_mask[] = { | |||
26 | [ELS_ADDR_FMT_FAB] = 0x000000, | 26 | [ELS_ADDR_FMT_FAB] = 0x000000, |
27 | }; | 27 | }; |
28 | 28 | ||
29 | static bool no_auto_port_rescan; | ||
30 | module_param_named(no_auto_port_rescan, no_auto_port_rescan, bool, 0600); | ||
31 | MODULE_PARM_DESC(no_auto_port_rescan, | ||
32 | "no automatic port_rescan (default off)"); | ||
33 | |||
34 | void zfcp_fc_conditional_port_scan(struct zfcp_adapter *adapter) | ||
35 | { | ||
36 | if (no_auto_port_rescan) | ||
37 | return; | ||
38 | |||
39 | queue_work(adapter->work_queue, &adapter->scan_work); | ||
40 | } | ||
41 | |||
42 | void zfcp_fc_inverse_conditional_port_scan(struct zfcp_adapter *adapter) | ||
43 | { | ||
44 | if (!no_auto_port_rescan) | ||
45 | return; | ||
46 | |||
47 | queue_work(adapter->work_queue, &adapter->scan_work); | ||
48 | } | ||
49 | |||
29 | /** | 50 | /** |
30 | * zfcp_fc_post_event - post event to userspace via fc_transport | 51 | * zfcp_fc_post_event - post event to userspace via fc_transport |
31 | * @work: work struct with enqueued events | 52 | * @work: work struct with enqueued events |
@@ -206,7 +227,7 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) | |||
206 | zfcp_fc_enqueue_event(fsf_req->adapter, FCH_EVT_RSCN, | 227 | zfcp_fc_enqueue_event(fsf_req->adapter, FCH_EVT_RSCN, |
207 | *(u32 *)page); | 228 | *(u32 *)page); |
208 | } | 229 | } |
209 | queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work); | 230 | zfcp_fc_conditional_port_scan(fsf_req->adapter); |
210 | } | 231 | } |
211 | 232 | ||
212 | static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn) | 233 | static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn) |
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index e1c1efc2c5a0..c96320d79fbc 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -219,7 +219,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) | |||
219 | return; | 219 | return; |
220 | } | 220 | } |
221 | 221 | ||
222 | zfcp_dbf_hba_fsf_uss("fssrh_2", req); | 222 | zfcp_dbf_hba_fsf_uss("fssrh_4", req); |
223 | 223 | ||
224 | switch (sr_buf->status_type) { | 224 | switch (sr_buf->status_type) { |
225 | case FSF_STATUS_READ_PORT_CLOSED: | 225 | case FSF_STATUS_READ_PORT_CLOSED: |
@@ -257,7 +257,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) | |||
257 | if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) | 257 | if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) |
258 | zfcp_cfdc_adapter_access_changed(adapter); | 258 | zfcp_cfdc_adapter_access_changed(adapter); |
259 | if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) | 259 | if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) |
260 | queue_work(adapter->work_queue, &adapter->scan_work); | 260 | zfcp_fc_conditional_port_scan(adapter); |
261 | break; | 261 | break; |
262 | case FSF_STATUS_READ_CFDC_UPDATED: | 262 | case FSF_STATUS_READ_CFDC_UPDATED: |
263 | zfcp_cfdc_adapter_access_changed(adapter); | 263 | zfcp_cfdc_adapter_access_changed(adapter); |
@@ -437,6 +437,34 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) | |||
437 | } | 437 | } |
438 | } | 438 | } |
439 | 439 | ||
440 | #define ZFCP_FSF_PORTSPEED_1GBIT (1 << 0) | ||
441 | #define ZFCP_FSF_PORTSPEED_2GBIT (1 << 1) | ||
442 | #define ZFCP_FSF_PORTSPEED_4GBIT (1 << 2) | ||
443 | #define ZFCP_FSF_PORTSPEED_10GBIT (1 << 3) | ||
444 | #define ZFCP_FSF_PORTSPEED_8GBIT (1 << 4) | ||
445 | #define ZFCP_FSF_PORTSPEED_16GBIT (1 << 5) | ||
446 | #define ZFCP_FSF_PORTSPEED_NOT_NEGOTIATED (1 << 15) | ||
447 | |||
448 | static u32 zfcp_fsf_convert_portspeed(u32 fsf_speed) | ||
449 | { | ||
450 | u32 fdmi_speed = 0; | ||
451 | if (fsf_speed & ZFCP_FSF_PORTSPEED_1GBIT) | ||
452 | fdmi_speed |= FC_PORTSPEED_1GBIT; | ||
453 | if (fsf_speed & ZFCP_FSF_PORTSPEED_2GBIT) | ||
454 | fdmi_speed |= FC_PORTSPEED_2GBIT; | ||
455 | if (fsf_speed & ZFCP_FSF_PORTSPEED_4GBIT) | ||
456 | fdmi_speed |= FC_PORTSPEED_4GBIT; | ||
457 | if (fsf_speed & ZFCP_FSF_PORTSPEED_10GBIT) | ||
458 | fdmi_speed |= FC_PORTSPEED_10GBIT; | ||
459 | if (fsf_speed & ZFCP_FSF_PORTSPEED_8GBIT) | ||
460 | fdmi_speed |= FC_PORTSPEED_8GBIT; | ||
461 | if (fsf_speed & ZFCP_FSF_PORTSPEED_16GBIT) | ||
462 | fdmi_speed |= FC_PORTSPEED_16GBIT; | ||
463 | if (fsf_speed & ZFCP_FSF_PORTSPEED_NOT_NEGOTIATED) | ||
464 | fdmi_speed |= FC_PORTSPEED_NOT_NEGOTIATED; | ||
465 | return fdmi_speed; | ||
466 | } | ||
467 | |||
440 | static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) | 468 | static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) |
441 | { | 469 | { |
442 | struct fsf_qtcb_bottom_config *bottom = &req->qtcb->bottom.config; | 470 | struct fsf_qtcb_bottom_config *bottom = &req->qtcb->bottom.config; |
@@ -456,7 +484,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) | |||
456 | fc_host_port_name(shost) = nsp->fl_wwpn; | 484 | fc_host_port_name(shost) = nsp->fl_wwpn; |
457 | fc_host_node_name(shost) = nsp->fl_wwnn; | 485 | fc_host_node_name(shost) = nsp->fl_wwnn; |
458 | fc_host_port_id(shost) = ntoh24(bottom->s_id); | 486 | fc_host_port_id(shost) = ntoh24(bottom->s_id); |
459 | fc_host_speed(shost) = bottom->fc_link_speed; | 487 | fc_host_speed(shost) = |
488 | zfcp_fsf_convert_portspeed(bottom->fc_link_speed); | ||
460 | fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; | 489 | fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; |
461 | 490 | ||
462 | adapter->hydra_version = bottom->adapter_type; | 491 | adapter->hydra_version = bottom->adapter_type; |
@@ -580,7 +609,8 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req) | |||
580 | } else | 609 | } else |
581 | fc_host_permanent_port_name(shost) = fc_host_port_name(shost); | 610 | fc_host_permanent_port_name(shost) = fc_host_port_name(shost); |
582 | fc_host_maxframe_size(shost) = bottom->maximum_frame_size; | 611 | fc_host_maxframe_size(shost) = bottom->maximum_frame_size; |
583 | fc_host_supported_speeds(shost) = bottom->supported_speed; | 612 | fc_host_supported_speeds(shost) = |
613 | zfcp_fsf_convert_portspeed(bottom->supported_speed); | ||
584 | memcpy(fc_host_supported_fc4s(shost), bottom->supported_fc4_types, | 614 | memcpy(fc_host_supported_fc4s(shost), bottom->supported_fc4_types, |
585 | FC_FC4_LIST_SIZE); | 615 | FC_FC4_LIST_SIZE); |
586 | memcpy(fc_host_active_fc4s(shost), bottom->active_fc4_types, | 616 | memcpy(fc_host_active_fc4s(shost), bottom->active_fc4_types, |
@@ -771,12 +801,14 @@ out: | |||
771 | static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) | 801 | static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) |
772 | { | 802 | { |
773 | struct scsi_device *sdev = req->data; | 803 | struct scsi_device *sdev = req->data; |
774 | struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); | 804 | struct zfcp_scsi_dev *zfcp_sdev; |
775 | union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual; | 805 | union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual; |
776 | 806 | ||
777 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) | 807 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
778 | return; | 808 | return; |
779 | 809 | ||
810 | zfcp_sdev = sdev_to_zfcp(sdev); | ||
811 | |||
780 | switch (req->qtcb->header.fsf_status) { | 812 | switch (req->qtcb->header.fsf_status) { |
781 | case FSF_PORT_HANDLE_NOT_VALID: | 813 | case FSF_PORT_HANDLE_NOT_VALID: |
782 | if (fsq->word[0] == fsq->word[1]) { | 814 | if (fsq->word[0] == fsq->word[1]) { |
@@ -885,7 +917,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) | |||
885 | 917 | ||
886 | switch (header->fsf_status) { | 918 | switch (header->fsf_status) { |
887 | case FSF_GOOD: | 919 | case FSF_GOOD: |
888 | zfcp_dbf_san_res("fsscth1", req); | 920 | zfcp_dbf_san_res("fsscth2", req); |
889 | ct->status = 0; | 921 | ct->status = 0; |
890 | break; | 922 | break; |
891 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: | 923 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: |
@@ -1739,13 +1771,15 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) | |||
1739 | { | 1771 | { |
1740 | struct zfcp_adapter *adapter = req->adapter; | 1772 | struct zfcp_adapter *adapter = req->adapter; |
1741 | struct scsi_device *sdev = req->data; | 1773 | struct scsi_device *sdev = req->data; |
1742 | struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); | 1774 | struct zfcp_scsi_dev *zfcp_sdev; |
1743 | struct fsf_qtcb_header *header = &req->qtcb->header; | 1775 | struct fsf_qtcb_header *header = &req->qtcb->header; |
1744 | struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support; | 1776 | struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support; |
1745 | 1777 | ||
1746 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) | 1778 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
1747 | return; | 1779 | return; |
1748 | 1780 | ||
1781 | zfcp_sdev = sdev_to_zfcp(sdev); | ||
1782 | |||
1749 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | | 1783 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | |
1750 | ZFCP_STATUS_COMMON_ACCESS_BOXED | | 1784 | ZFCP_STATUS_COMMON_ACCESS_BOXED | |
1751 | ZFCP_STATUS_LUN_SHARED | | 1785 | ZFCP_STATUS_LUN_SHARED | |
@@ -1856,11 +1890,13 @@ out: | |||
1856 | static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) | 1890 | static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) |
1857 | { | 1891 | { |
1858 | struct scsi_device *sdev = req->data; | 1892 | struct scsi_device *sdev = req->data; |
1859 | struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); | 1893 | struct zfcp_scsi_dev *zfcp_sdev; |
1860 | 1894 | ||
1861 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) | 1895 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
1862 | return; | 1896 | return; |
1863 | 1897 | ||
1898 | zfcp_sdev = sdev_to_zfcp(sdev); | ||
1899 | |||
1864 | switch (req->qtcb->header.fsf_status) { | 1900 | switch (req->qtcb->header.fsf_status) { |
1865 | case FSF_PORT_HANDLE_NOT_VALID: | 1901 | case FSF_PORT_HANDLE_NOT_VALID: |
1866 | zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1"); | 1902 | zfcp_erp_adapter_reopen(zfcp_sdev->port->adapter, 0, "fscuh_1"); |
@@ -1950,7 +1986,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) | |||
1950 | { | 1986 | { |
1951 | struct fsf_qual_latency_info *lat_in; | 1987 | struct fsf_qual_latency_info *lat_in; |
1952 | struct latency_cont *lat = NULL; | 1988 | struct latency_cont *lat = NULL; |
1953 | struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scsi->device); | 1989 | struct zfcp_scsi_dev *zfcp_sdev; |
1954 | struct zfcp_blk_drv_data blktrc; | 1990 | struct zfcp_blk_drv_data blktrc; |
1955 | int ticks = req->adapter->timer_ticks; | 1991 | int ticks = req->adapter->timer_ticks; |
1956 | 1992 | ||
@@ -1965,6 +2001,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) | |||
1965 | 2001 | ||
1966 | if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA && | 2002 | if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA && |
1967 | !(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { | 2003 | !(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { |
2004 | zfcp_sdev = sdev_to_zfcp(scsi->device); | ||
1968 | blktrc.flags |= ZFCP_BLK_LAT_VALID; | 2005 | blktrc.flags |= ZFCP_BLK_LAT_VALID; |
1969 | blktrc.channel_lat = lat_in->channel_lat * ticks; | 2006 | blktrc.channel_lat = lat_in->channel_lat * ticks; |
1970 | blktrc.fabric_lat = lat_in->fabric_lat * ticks; | 2007 | blktrc.fabric_lat = lat_in->fabric_lat * ticks; |
@@ -2002,12 +2039,14 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req) | |||
2002 | { | 2039 | { |
2003 | struct scsi_cmnd *scmnd = req->data; | 2040 | struct scsi_cmnd *scmnd = req->data; |
2004 | struct scsi_device *sdev = scmnd->device; | 2041 | struct scsi_device *sdev = scmnd->device; |
2005 | struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); | 2042 | struct zfcp_scsi_dev *zfcp_sdev; |
2006 | struct fsf_qtcb_header *header = &req->qtcb->header; | 2043 | struct fsf_qtcb_header *header = &req->qtcb->header; |
2007 | 2044 | ||
2008 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) | 2045 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) |
2009 | return; | 2046 | return; |
2010 | 2047 | ||
2048 | zfcp_sdev = sdev_to_zfcp(sdev); | ||
2049 | |||
2011 | switch (header->fsf_status) { | 2050 | switch (header->fsf_status) { |
2012 | case FSF_HANDLE_MISMATCH: | 2051 | case FSF_HANDLE_MISMATCH: |
2013 | case FSF_PORT_HANDLE_NOT_VALID: | 2052 | case FSF_PORT_HANDLE_NOT_VALID: |
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index b9fffc8d94a7..50b5615848f6 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c | |||
@@ -102,18 +102,22 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, | |||
102 | { | 102 | { |
103 | struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; | 103 | struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; |
104 | struct zfcp_adapter *adapter = qdio->adapter; | 104 | struct zfcp_adapter *adapter = qdio->adapter; |
105 | struct qdio_buffer_element *sbale; | ||
106 | int sbal_no, sbal_idx; | 105 | int sbal_no, sbal_idx; |
107 | void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1]; | ||
108 | u64 req_id; | ||
109 | u8 scount; | ||
110 | 106 | ||
111 | if (unlikely(qdio_err)) { | 107 | if (unlikely(qdio_err)) { |
112 | memset(pl, 0, ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *)); | ||
113 | if (zfcp_adapter_multi_buffer_active(adapter)) { | 108 | if (zfcp_adapter_multi_buffer_active(adapter)) { |
109 | void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1]; | ||
110 | struct qdio_buffer_element *sbale; | ||
111 | u64 req_id; | ||
112 | u8 scount; | ||
113 | |||
114 | memset(pl, 0, | ||
115 | ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *)); | ||
114 | sbale = qdio->res_q[idx]->element; | 116 | sbale = qdio->res_q[idx]->element; |
115 | req_id = (u64) sbale->addr; | 117 | req_id = (u64) sbale->addr; |
116 | scount = sbale->scount + 1; /* incl. signaling SBAL */ | 118 | scount = min(sbale->scount + 1, |
119 | ZFCP_QDIO_MAX_SBALS_PER_REQ + 1); | ||
120 | /* incl. signaling SBAL */ | ||
117 | 121 | ||
118 | for (sbal_no = 0; sbal_no < scount; sbal_no++) { | 122 | for (sbal_no = 0; sbal_no < scount; sbal_no++) { |
119 | sbal_idx = (idx + sbal_no) % | 123 | sbal_idx = (idx + sbal_no) % |
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index c66af27b230b..1e0eb089dfba 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c | |||
@@ -227,6 +227,8 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, | |||
227 | static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, | 227 | static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, |
228 | zfcp_sysfs_port_rescan_store); | 228 | zfcp_sysfs_port_rescan_store); |
229 | 229 | ||
230 | DEFINE_MUTEX(zfcp_sysfs_port_units_mutex); | ||
231 | |||
230 | static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, | 232 | static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, |
231 | struct device_attribute *attr, | 233 | struct device_attribute *attr, |
232 | const char *buf, size_t count) | 234 | const char *buf, size_t count) |
@@ -249,6 +251,16 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, | |||
249 | else | 251 | else |
250 | retval = 0; | 252 | retval = 0; |
251 | 253 | ||
254 | mutex_lock(&zfcp_sysfs_port_units_mutex); | ||
255 | if (atomic_read(&port->units) > 0) { | ||
256 | retval = -EBUSY; | ||
257 | mutex_unlock(&zfcp_sysfs_port_units_mutex); | ||
258 | goto out; | ||
259 | } | ||
260 | /* port is about to be removed, so no more unit_add */ | ||
261 | atomic_set(&port->units, -1); | ||
262 | mutex_unlock(&zfcp_sysfs_port_units_mutex); | ||
263 | |||
252 | write_lock_irq(&adapter->port_list_lock); | 264 | write_lock_irq(&adapter->port_list_lock); |
253 | list_del(&port->list); | 265 | list_del(&port->list); |
254 | write_unlock_irq(&adapter->port_list_lock); | 266 | write_unlock_irq(&adapter->port_list_lock); |
@@ -289,12 +301,14 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, | |||
289 | { | 301 | { |
290 | struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); | 302 | struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); |
291 | u64 fcp_lun; | 303 | u64 fcp_lun; |
304 | int retval; | ||
292 | 305 | ||
293 | if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) | 306 | if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) |
294 | return -EINVAL; | 307 | return -EINVAL; |
295 | 308 | ||
296 | if (zfcp_unit_add(port, fcp_lun)) | 309 | retval = zfcp_unit_add(port, fcp_lun); |
297 | return -EINVAL; | 310 | if (retval) |
311 | return retval; | ||
298 | 312 | ||
299 | return count; | 313 | return count; |
300 | } | 314 | } |
diff --git a/drivers/s390/scsi/zfcp_unit.c b/drivers/s390/scsi/zfcp_unit.c index 3f2bff0d3aa2..1cd2b99ab256 100644 --- a/drivers/s390/scsi/zfcp_unit.c +++ b/drivers/s390/scsi/zfcp_unit.c | |||
@@ -104,7 +104,7 @@ static void zfcp_unit_release(struct device *dev) | |||
104 | { | 104 | { |
105 | struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); | 105 | struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev); |
106 | 106 | ||
107 | put_device(&unit->port->dev); | 107 | atomic_dec(&unit->port->units); |
108 | kfree(unit); | 108 | kfree(unit); |
109 | } | 109 | } |
110 | 110 | ||
@@ -119,16 +119,27 @@ static void zfcp_unit_release(struct device *dev) | |||
119 | int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun) | 119 | int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun) |
120 | { | 120 | { |
121 | struct zfcp_unit *unit; | 121 | struct zfcp_unit *unit; |
122 | int retval = 0; | ||
123 | |||
124 | mutex_lock(&zfcp_sysfs_port_units_mutex); | ||
125 | if (atomic_read(&port->units) == -1) { | ||
126 | /* port is already gone */ | ||
127 | retval = -ENODEV; | ||
128 | goto out; | ||
129 | } | ||
122 | 130 | ||
123 | unit = zfcp_unit_find(port, fcp_lun); | 131 | unit = zfcp_unit_find(port, fcp_lun); |
124 | if (unit) { | 132 | if (unit) { |
125 | put_device(&unit->dev); | 133 | put_device(&unit->dev); |
126 | return -EEXIST; | 134 | retval = -EEXIST; |
135 | goto out; | ||
127 | } | 136 | } |
128 | 137 | ||
129 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); | 138 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); |
130 | if (!unit) | 139 | if (!unit) { |
131 | return -ENOMEM; | 140 | retval = -ENOMEM; |
141 | goto out; | ||
142 | } | ||
132 | 143 | ||
133 | unit->port = port; | 144 | unit->port = port; |
134 | unit->fcp_lun = fcp_lun; | 145 | unit->fcp_lun = fcp_lun; |
@@ -139,28 +150,33 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun) | |||
139 | if (dev_set_name(&unit->dev, "0x%016llx", | 150 | if (dev_set_name(&unit->dev, "0x%016llx", |
140 | (unsigned long long) fcp_lun)) { | 151 | (unsigned long long) fcp_lun)) { |
141 | kfree(unit); | 152 | kfree(unit); |
142 | return -ENOMEM; | 153 | retval = -ENOMEM; |
154 | goto out; | ||
143 | } | 155 | } |
144 | 156 | ||
145 | get_device(&port->dev); | ||
146 | |||
147 | if (device_register(&unit->dev)) { | 157 | if (device_register(&unit->dev)) { |
148 | put_device(&unit->dev); | 158 | put_device(&unit->dev); |
149 | return -ENOMEM; | 159 | retval = -ENOMEM; |
160 | goto out; | ||
150 | } | 161 | } |
151 | 162 | ||
152 | if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) { | 163 | if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) { |
153 | device_unregister(&unit->dev); | 164 | device_unregister(&unit->dev); |
154 | return -EINVAL; | 165 | retval = -EINVAL; |
166 | goto out; | ||
155 | } | 167 | } |
156 | 168 | ||
169 | atomic_inc(&port->units); /* under zfcp_sysfs_port_units_mutex ! */ | ||
170 | |||
157 | write_lock_irq(&port->unit_list_lock); | 171 | write_lock_irq(&port->unit_list_lock); |
158 | list_add_tail(&unit->list, &port->unit_list); | 172 | list_add_tail(&unit->list, &port->unit_list); |
159 | write_unlock_irq(&port->unit_list_lock); | 173 | write_unlock_irq(&port->unit_list_lock); |
160 | 174 | ||
161 | zfcp_unit_scsi_scan(unit); | 175 | zfcp_unit_scsi_scan(unit); |
162 | 176 | ||
163 | return 0; | 177 | out: |
178 | mutex_unlock(&zfcp_sysfs_port_units_mutex); | ||
179 | return retval; | ||
164 | } | 180 | } |
165 | 181 | ||
166 | /** | 182 | /** |