diff options
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 4 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 3 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 54 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.h | 24 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 3 |
6 files changed, 90 insertions, 0 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 7c01c4c3f6b9..96fa1f536394 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -524,6 +524,10 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
524 | rwlock_init(&adapter->port_list_lock); | 524 | rwlock_init(&adapter->port_list_lock); |
525 | INIT_LIST_HEAD(&adapter->port_list); | 525 | INIT_LIST_HEAD(&adapter->port_list); |
526 | 526 | ||
527 | INIT_LIST_HEAD(&adapter->events.list); | ||
528 | INIT_WORK(&adapter->events.work, zfcp_fc_post_event); | ||
529 | spin_lock_init(&adapter->events.list_lock); | ||
530 | |||
527 | init_waitqueue_head(&adapter->erp_ready_wq); | 531 | init_waitqueue_head(&adapter->erp_ready_wq); |
528 | init_waitqueue_head(&adapter->erp_done_wqh); | 532 | init_waitqueue_head(&adapter->erp_done_wqh); |
529 | 533 | ||
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 86a8725430a4..cb3640c6477c 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <asm/ebcdic.h> | 37 | #include <asm/ebcdic.h> |
38 | #include <asm/sysinfo.h> | 38 | #include <asm/sysinfo.h> |
39 | #include "zfcp_fsf.h" | 39 | #include "zfcp_fsf.h" |
40 | #include "zfcp_fc.h" | ||
40 | #include "zfcp_qdio.h" | 41 | #include "zfcp_qdio.h" |
41 | 42 | ||
42 | struct zfcp_reqlist; | 43 | struct zfcp_reqlist; |
@@ -190,6 +191,7 @@ struct zfcp_adapter { | |||
190 | struct service_level service_level; | 191 | struct service_level service_level; |
191 | struct workqueue_struct *work_queue; | 192 | struct workqueue_struct *work_queue; |
192 | struct device_dma_parameters dma_parms; | 193 | struct device_dma_parameters dma_parms; |
194 | struct zfcp_fc_events events; | ||
193 | }; | 195 | }; |
194 | 196 | ||
195 | struct zfcp_port { | 197 | struct zfcp_port { |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 3aab0f5544d4..a8bb7488dc98 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -96,6 +96,9 @@ extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *, | |||
96 | extern void zfcp_erp_timeout_handler(unsigned long); | 96 | extern void zfcp_erp_timeout_handler(unsigned long); |
97 | 97 | ||
98 | /* zfcp_fc.c */ | 98 | /* zfcp_fc.c */ |
99 | extern void zfcp_fc_enqueue_event(struct zfcp_adapter *, | ||
100 | enum fc_host_event_code event_code, u32); | ||
101 | extern void zfcp_fc_post_event(struct work_struct *); | ||
99 | extern void zfcp_fc_scan_ports(struct work_struct *); | 102 | extern void zfcp_fc_scan_ports(struct work_struct *); |
100 | extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); | 103 | extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); |
101 | extern void zfcp_fc_port_did_lookup(struct work_struct *); | 104 | extern void zfcp_fc_port_did_lookup(struct work_struct *); |
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 6f8ab43a4856..6f3ed2b9a349 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -23,6 +23,58 @@ static u32 zfcp_fc_rscn_range_mask[] = { | |||
23 | [ELS_ADDR_FMT_FAB] = 0x000000, | 23 | [ELS_ADDR_FMT_FAB] = 0x000000, |
24 | }; | 24 | }; |
25 | 25 | ||
26 | /** | ||
27 | * zfcp_fc_post_event - post event to userspace via fc_transport | ||
28 | * @work: work struct with enqueued events | ||
29 | */ | ||
30 | void zfcp_fc_post_event(struct work_struct *work) | ||
31 | { | ||
32 | struct zfcp_fc_event *event = NULL, *tmp = NULL; | ||
33 | LIST_HEAD(tmp_lh); | ||
34 | struct zfcp_fc_events *events = container_of(work, | ||
35 | struct zfcp_fc_events, work); | ||
36 | struct zfcp_adapter *adapter = container_of(events, struct zfcp_adapter, | ||
37 | events); | ||
38 | |||
39 | spin_lock_bh(&events->list_lock); | ||
40 | list_splice_init(&events->list, &tmp_lh); | ||
41 | spin_unlock_bh(&events->list_lock); | ||
42 | |||
43 | list_for_each_entry_safe(event, tmp, &tmp_lh, list) { | ||
44 | fc_host_post_event(adapter->scsi_host, fc_get_event_number(), | ||
45 | event->code, event->data); | ||
46 | list_del(&event->list); | ||
47 | kfree(event); | ||
48 | } | ||
49 | |||
50 | } | ||
51 | |||
52 | /** | ||
53 | * zfcp_fc_enqueue_event - safely enqueue FC HBA API event from irq context | ||
54 | * @adapter: The adapter where to enqueue the event | ||
55 | * @event_code: The event code (as defined in fc_host_event_code in | ||
56 | * scsi_transport_fc.h) | ||
57 | * @event_data: The event data (e.g. n_port page in case of els) | ||
58 | */ | ||
59 | void zfcp_fc_enqueue_event(struct zfcp_adapter *adapter, | ||
60 | enum fc_host_event_code event_code, u32 event_data) | ||
61 | { | ||
62 | struct zfcp_fc_event *event; | ||
63 | |||
64 | event = kmalloc(sizeof(struct zfcp_fc_event), GFP_ATOMIC); | ||
65 | if (!event) | ||
66 | return; | ||
67 | |||
68 | event->code = event_code; | ||
69 | event->data = event_data; | ||
70 | |||
71 | spin_lock(&adapter->events.list_lock); | ||
72 | list_add_tail(&event->list, &adapter->events.list); | ||
73 | spin_unlock(&adapter->events.list_lock); | ||
74 | |||
75 | queue_work(adapter->work_queue, &adapter->events.work); | ||
76 | } | ||
77 | |||
26 | static int zfcp_fc_wka_port_get(struct zfcp_fc_wka_port *wka_port) | 78 | static int zfcp_fc_wka_port_get(struct zfcp_fc_wka_port *wka_port) |
27 | { | 79 | { |
28 | if (mutex_lock_interruptible(&wka_port->mutex)) | 80 | if (mutex_lock_interruptible(&wka_port->mutex)) |
@@ -148,6 +200,8 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) | |||
148 | afmt = page->rscn_page_flags & ELS_RSCN_ADDR_FMT_MASK; | 200 | afmt = page->rscn_page_flags & ELS_RSCN_ADDR_FMT_MASK; |
149 | _zfcp_fc_incoming_rscn(fsf_req, zfcp_fc_rscn_range_mask[afmt], | 201 | _zfcp_fc_incoming_rscn(fsf_req, zfcp_fc_rscn_range_mask[afmt], |
150 | page); | 202 | page); |
203 | zfcp_fc_enqueue_event(fsf_req->adapter, FCH_EVT_RSCN, | ||
204 | *(u32 *)page); | ||
151 | } | 205 | } |
152 | queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work); | 206 | queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work); |
153 | } | 207 | } |
diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h index 0747b087390d..85c37d2b82c2 100644 --- a/drivers/s390/scsi/zfcp_fc.h +++ b/drivers/s390/scsi/zfcp_fc.h | |||
@@ -30,6 +30,30 @@ | |||
30 | #define ZFCP_FC_CTELS_TMO (2 * FC_DEF_R_A_TOV / 1000) | 30 | #define ZFCP_FC_CTELS_TMO (2 * FC_DEF_R_A_TOV / 1000) |
31 | 31 | ||
32 | /** | 32 | /** |
33 | * struct zfcp_fc_event - FC HBAAPI event for internal queueing from irq context | ||
34 | * @code: Event code | ||
35 | * @data: Event data | ||
36 | * @list: list_head for zfcp_fc_events list | ||
37 | */ | ||
38 | struct zfcp_fc_event { | ||
39 | enum fc_host_event_code code; | ||
40 | u32 data; | ||
41 | struct list_head list; | ||
42 | }; | ||
43 | |||
44 | /** | ||
45 | * struct zfcp_fc_events - Infrastructure for posting FC events from irq context | ||
46 | * @list: List for queueing of events from irq context to workqueue | ||
47 | * @list_lock: Lock for event list | ||
48 | * @work: work_struct for forwarding events in workqueue | ||
49 | */ | ||
50 | struct zfcp_fc_events { | ||
51 | struct list_head list; | ||
52 | spinlock_t list_lock; | ||
53 | struct work_struct work; | ||
54 | }; | ||
55 | |||
56 | /** | ||
33 | * struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request | 57 | * struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request |
34 | * @ct_hdr: FC GS common transport header | 58 | * @ct_hdr: FC GS common transport header |
35 | * @gid_pn: GID_PN request | 59 | * @gid_pn: GID_PN request |
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 0710c59b80ae..63402fd5f9ae 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -274,6 +274,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) | |||
274 | break; | 274 | break; |
275 | case FSF_STATUS_READ_LINK_DOWN: | 275 | case FSF_STATUS_READ_LINK_DOWN: |
276 | zfcp_fsf_status_read_link_down(req); | 276 | zfcp_fsf_status_read_link_down(req); |
277 | zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKDOWN, 0); | ||
277 | break; | 278 | break; |
278 | case FSF_STATUS_READ_LINK_UP: | 279 | case FSF_STATUS_READ_LINK_UP: |
279 | dev_info(&adapter->ccw_device->dev, | 280 | dev_info(&adapter->ccw_device->dev, |
@@ -286,6 +287,8 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) | |||
286 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | | 287 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | |
287 | ZFCP_STATUS_COMMON_ERP_FAILED, | 288 | ZFCP_STATUS_COMMON_ERP_FAILED, |
288 | "fssrh_2", req); | 289 | "fssrh_2", req); |
290 | zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKUP, 0); | ||
291 | |||
289 | break; | 292 | break; |
290 | case FSF_STATUS_READ_NOTIFICATION_LOST: | 293 | case FSF_STATUS_READ_NOTIFICATION_LOST: |
291 | if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) | 294 | if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) |