diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/s390/scsi/zfcp_ccw.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/s390/scsi/zfcp_ccw.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_ccw.c | 182 |
1 files changed, 83 insertions, 99 deletions
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index e08339428ecf..ce1cc7a11fb4 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c | |||
@@ -3,38 +3,45 @@ | |||
3 | * | 3 | * |
4 | * Registration and callback for the s390 common I/O layer. | 4 | * Registration and callback for the s390 common I/O layer. |
5 | * | 5 | * |
6 | * Copyright IBM Corporation 2002, 2009 | 6 | * Copyright IBM Corporation 2002, 2010 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #define KMSG_COMPONENT "zfcp" | 9 | #define KMSG_COMPONENT "zfcp" |
10 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | 10 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
11 | 11 | ||
12 | #include "zfcp_ext.h" | 12 | #include "zfcp_ext.h" |
13 | #include "zfcp_reqlist.h" | ||
13 | 14 | ||
14 | #define ZFCP_MODEL_PRIV 0x4 | 15 | #define ZFCP_MODEL_PRIV 0x4 |
15 | 16 | ||
16 | static int zfcp_ccw_suspend(struct ccw_device *cdev) | 17 | static DEFINE_SPINLOCK(zfcp_ccw_adapter_ref_lock); |
17 | 18 | ||
19 | struct zfcp_adapter *zfcp_ccw_adapter_by_cdev(struct ccw_device *cdev) | ||
18 | { | 20 | { |
19 | struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); | 21 | struct zfcp_adapter *adapter; |
20 | 22 | unsigned long flags; | |
21 | if (!adapter) | ||
22 | return 0; | ||
23 | |||
24 | mutex_lock(&zfcp_data.config_mutex); | ||
25 | 23 | ||
26 | zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL); | 24 | spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags); |
27 | zfcp_erp_wait(adapter); | 25 | adapter = dev_get_drvdata(&cdev->dev); |
26 | if (adapter) | ||
27 | kref_get(&adapter->ref); | ||
28 | spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags); | ||
29 | return adapter; | ||
30 | } | ||
28 | 31 | ||
29 | mutex_unlock(&zfcp_data.config_mutex); | 32 | void zfcp_ccw_adapter_put(struct zfcp_adapter *adapter) |
33 | { | ||
34 | unsigned long flags; | ||
30 | 35 | ||
31 | return 0; | 36 | spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags); |
37 | kref_put(&adapter->ref, zfcp_adapter_release); | ||
38 | spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags); | ||
32 | } | 39 | } |
33 | 40 | ||
34 | static int zfcp_ccw_activate(struct ccw_device *cdev) | 41 | static int zfcp_ccw_activate(struct ccw_device *cdev) |
35 | 42 | ||
36 | { | 43 | { |
37 | struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); | 44 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
38 | 45 | ||
39 | if (!adapter) | 46 | if (!adapter) |
40 | return 0; | 47 | return 0; |
@@ -46,6 +53,8 @@ static int zfcp_ccw_activate(struct ccw_device *cdev) | |||
46 | zfcp_erp_wait(adapter); | 53 | zfcp_erp_wait(adapter); |
47 | flush_work(&adapter->scan_work); | 54 | flush_work(&adapter->scan_work); |
48 | 55 | ||
56 | zfcp_ccw_adapter_put(adapter); | ||
57 | |||
49 | return 0; | 58 | return 0; |
50 | } | 59 | } |
51 | 60 | ||
@@ -67,28 +76,28 @@ int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter) | |||
67 | 76 | ||
68 | /** | 77 | /** |
69 | * zfcp_ccw_probe - probe function of zfcp driver | 78 | * zfcp_ccw_probe - probe function of zfcp driver |
70 | * @ccw_device: pointer to belonging ccw device | 79 | * @cdev: pointer to belonging ccw device |
71 | * | 80 | * |
72 | * This function gets called by the common i/o layer for each FCP | 81 | * This function gets called by the common i/o layer for each FCP |
73 | * device found on the current system. This is only a stub to make cio | 82 | * device found on the current system. This is only a stub to make cio |
74 | * work: To only allocate adapter resources for devices actually used, | 83 | * work: To only allocate adapter resources for devices actually used, |
75 | * the allocation is deferred to the first call to ccw_set_online. | 84 | * the allocation is deferred to the first call to ccw_set_online. |
76 | */ | 85 | */ |
77 | static int zfcp_ccw_probe(struct ccw_device *ccw_device) | 86 | static int zfcp_ccw_probe(struct ccw_device *cdev) |
78 | { | 87 | { |
79 | return 0; | 88 | return 0; |
80 | } | 89 | } |
81 | 90 | ||
82 | /** | 91 | /** |
83 | * zfcp_ccw_remove - remove function of zfcp driver | 92 | * zfcp_ccw_remove - remove function of zfcp driver |
84 | * @ccw_device: pointer to belonging ccw device | 93 | * @cdev: pointer to belonging ccw device |
85 | * | 94 | * |
86 | * This function gets called by the common i/o layer and removes an adapter | 95 | * This function gets called by the common i/o layer and removes an adapter |
87 | * from the system. Task of this function is to get rid of all units and | 96 | * from the system. Task of this function is to get rid of all units and |
88 | * ports that belong to this adapter. And in addition all resources of this | 97 | * ports that belong to this adapter. And in addition all resources of this |
89 | * adapter will be freed too. | 98 | * adapter will be freed too. |
90 | */ | 99 | */ |
91 | static void zfcp_ccw_remove(struct ccw_device *ccw_device) | 100 | static void zfcp_ccw_remove(struct ccw_device *cdev) |
92 | { | 101 | { |
93 | struct zfcp_adapter *adapter; | 102 | struct zfcp_adapter *adapter; |
94 | struct zfcp_port *port, *p; | 103 | struct zfcp_port *port, *p; |
@@ -96,49 +105,35 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) | |||
96 | LIST_HEAD(unit_remove_lh); | 105 | LIST_HEAD(unit_remove_lh); |
97 | LIST_HEAD(port_remove_lh); | 106 | LIST_HEAD(port_remove_lh); |
98 | 107 | ||
99 | ccw_device_set_offline(ccw_device); | 108 | ccw_device_set_offline(cdev); |
100 | 109 | ||
101 | mutex_lock(&zfcp_data.config_mutex); | 110 | adapter = zfcp_ccw_adapter_by_cdev(cdev); |
102 | adapter = dev_get_drvdata(&ccw_device->dev); | ||
103 | if (!adapter) | 111 | if (!adapter) |
104 | goto out; | 112 | return; |
105 | mutex_unlock(&zfcp_data.config_mutex); | ||
106 | 113 | ||
107 | cancel_work_sync(&adapter->scan_work); | 114 | write_lock_irq(&adapter->port_list_lock); |
108 | 115 | list_for_each_entry_safe(port, p, &adapter->port_list, list) { | |
109 | mutex_lock(&zfcp_data.config_mutex); | 116 | write_lock(&port->unit_list_lock); |
110 | 117 | list_for_each_entry_safe(unit, u, &port->unit_list, list) | |
111 | /* this also removes the scsi devices, so call it first */ | ||
112 | zfcp_adapter_scsi_unregister(adapter); | ||
113 | |||
114 | write_lock_irq(&zfcp_data.config_lock); | ||
115 | list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { | ||
116 | list_for_each_entry_safe(unit, u, &port->unit_list_head, list) { | ||
117 | list_move(&unit->list, &unit_remove_lh); | 118 | list_move(&unit->list, &unit_remove_lh); |
118 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, | 119 | write_unlock(&port->unit_list_lock); |
119 | &unit->status); | ||
120 | } | ||
121 | list_move(&port->list, &port_remove_lh); | 120 | list_move(&port->list, &port_remove_lh); |
122 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | ||
123 | } | 121 | } |
124 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | 122 | write_unlock_irq(&adapter->port_list_lock); |
125 | write_unlock_irq(&zfcp_data.config_lock); | 123 | zfcp_ccw_adapter_put(adapter); /* put from zfcp_ccw_adapter_by_cdev */ |
126 | 124 | ||
127 | list_for_each_entry_safe(port, p, &port_remove_lh, list) { | 125 | list_for_each_entry_safe(unit, u, &unit_remove_lh, list) |
128 | list_for_each_entry_safe(unit, u, &unit_remove_lh, list) | 126 | zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs); |
129 | zfcp_unit_dequeue(unit); | ||
130 | zfcp_port_dequeue(port); | ||
131 | } | ||
132 | wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); | ||
133 | zfcp_adapter_dequeue(adapter); | ||
134 | 127 | ||
135 | out: | 128 | list_for_each_entry_safe(port, p, &port_remove_lh, list) |
136 | mutex_unlock(&zfcp_data.config_mutex); | 129 | zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs); |
130 | |||
131 | zfcp_adapter_unregister(adapter); | ||
137 | } | 132 | } |
138 | 133 | ||
139 | /** | 134 | /** |
140 | * zfcp_ccw_set_online - set_online function of zfcp driver | 135 | * zfcp_ccw_set_online - set_online function of zfcp driver |
141 | * @ccw_device: pointer to belonging ccw device | 136 | * @cdev: pointer to belonging ccw device |
142 | * | 137 | * |
143 | * This function gets called by the common i/o layer and sets an | 138 | * This function gets called by the common i/o layer and sets an |
144 | * adapter into state online. The first call will allocate all | 139 | * adapter into state online. The first call will allocate all |
@@ -149,27 +144,24 @@ out: | |||
149 | * the SCSI stack, that the QDIO queues will be set up and that the | 144 | * the SCSI stack, that the QDIO queues will be set up and that the |
150 | * adapter will be opened. | 145 | * adapter will be opened. |
151 | */ | 146 | */ |
152 | static int zfcp_ccw_set_online(struct ccw_device *ccw_device) | 147 | static int zfcp_ccw_set_online(struct ccw_device *cdev) |
153 | { | 148 | { |
154 | struct zfcp_adapter *adapter; | 149 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
155 | int ret = 0; | ||
156 | |||
157 | mutex_lock(&zfcp_data.config_mutex); | ||
158 | adapter = dev_get_drvdata(&ccw_device->dev); | ||
159 | 150 | ||
160 | if (!adapter) { | 151 | if (!adapter) { |
161 | ret = zfcp_adapter_enqueue(ccw_device); | 152 | adapter = zfcp_adapter_enqueue(cdev); |
162 | if (ret) { | 153 | |
163 | dev_err(&ccw_device->dev, | 154 | if (IS_ERR(adapter)) { |
155 | dev_err(&cdev->dev, | ||
164 | "Setting up data structures for the " | 156 | "Setting up data structures for the " |
165 | "FCP adapter failed\n"); | 157 | "FCP adapter failed\n"); |
166 | goto out; | 158 | return PTR_ERR(adapter); |
167 | } | 159 | } |
168 | adapter = dev_get_drvdata(&ccw_device->dev); | 160 | kref_get(&adapter->ref); |
169 | } | 161 | } |
170 | 162 | ||
171 | /* initialize request counter */ | 163 | /* initialize request counter */ |
172 | BUG_ON(!zfcp_reqlist_isempty(adapter)); | 164 | BUG_ON(!zfcp_reqlist_isempty(adapter->req_list)); |
173 | adapter->req_no = 0; | 165 | adapter->req_no = 0; |
174 | 166 | ||
175 | zfcp_erp_modify_adapter_status(adapter, "ccsonl1", NULL, | 167 | zfcp_erp_modify_adapter_status(adapter, "ccsonl1", NULL, |
@@ -177,58 +169,61 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device) | |||
177 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, | 169 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, |
178 | "ccsonl2", NULL); | 170 | "ccsonl2", NULL); |
179 | zfcp_erp_wait(adapter); | 171 | zfcp_erp_wait(adapter); |
180 | out: | 172 | |
181 | mutex_unlock(&zfcp_data.config_mutex); | 173 | flush_work(&adapter->scan_work); |
182 | if (!ret) | 174 | |
183 | flush_work(&adapter->scan_work); | 175 | zfcp_ccw_adapter_put(adapter); |
184 | return ret; | 176 | return 0; |
185 | } | 177 | } |
186 | 178 | ||
187 | /** | 179 | /** |
188 | * zfcp_ccw_set_offline - set_offline function of zfcp driver | 180 | * zfcp_ccw_set_offline - set_offline function of zfcp driver |
189 | * @ccw_device: pointer to belonging ccw device | 181 | * @cdev: pointer to belonging ccw device |
190 | * | 182 | * |
191 | * This function gets called by the common i/o layer and sets an adapter | 183 | * This function gets called by the common i/o layer and sets an adapter |
192 | * into state offline. | 184 | * into state offline. |
193 | */ | 185 | */ |
194 | static int zfcp_ccw_set_offline(struct ccw_device *ccw_device) | 186 | static int zfcp_ccw_set_offline(struct ccw_device *cdev) |
195 | { | 187 | { |
196 | struct zfcp_adapter *adapter; | 188 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
189 | |||
190 | if (!adapter) | ||
191 | return 0; | ||
197 | 192 | ||
198 | mutex_lock(&zfcp_data.config_mutex); | ||
199 | adapter = dev_get_drvdata(&ccw_device->dev); | ||
200 | zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL); | 193 | zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL); |
201 | zfcp_erp_wait(adapter); | 194 | zfcp_erp_wait(adapter); |
202 | mutex_unlock(&zfcp_data.config_mutex); | 195 | |
196 | zfcp_ccw_adapter_put(adapter); | ||
203 | return 0; | 197 | return 0; |
204 | } | 198 | } |
205 | 199 | ||
206 | /** | 200 | /** |
207 | * zfcp_ccw_notify - ccw notify function | 201 | * zfcp_ccw_notify - ccw notify function |
208 | * @ccw_device: pointer to belonging ccw device | 202 | * @cdev: pointer to belonging ccw device |
209 | * @event: indicates if adapter was detached or attached | 203 | * @event: indicates if adapter was detached or attached |
210 | * | 204 | * |
211 | * This function gets called by the common i/o layer if an adapter has gone | 205 | * This function gets called by the common i/o layer if an adapter has gone |
212 | * or reappeared. | 206 | * or reappeared. |
213 | */ | 207 | */ |
214 | static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) | 208 | static int zfcp_ccw_notify(struct ccw_device *cdev, int event) |
215 | { | 209 | { |
216 | struct zfcp_adapter *adapter = dev_get_drvdata(&ccw_device->dev); | 210 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
211 | |||
212 | if (!adapter) | ||
213 | return 1; | ||
217 | 214 | ||
218 | switch (event) { | 215 | switch (event) { |
219 | case CIO_GONE: | 216 | case CIO_GONE: |
220 | dev_warn(&adapter->ccw_device->dev, | 217 | dev_warn(&cdev->dev, "The FCP device has been detached\n"); |
221 | "The FCP device has been detached\n"); | ||
222 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL); | 218 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL); |
223 | break; | 219 | break; |
224 | case CIO_NO_PATH: | 220 | case CIO_NO_PATH: |
225 | dev_warn(&adapter->ccw_device->dev, | 221 | dev_warn(&cdev->dev, |
226 | "The CHPID for the FCP device is offline\n"); | 222 | "The CHPID for the FCP device is offline\n"); |
227 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL); | 223 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL); |
228 | break; | 224 | break; |
229 | case CIO_OPER: | 225 | case CIO_OPER: |
230 | dev_info(&adapter->ccw_device->dev, | 226 | dev_info(&cdev->dev, "The FCP device is operational again\n"); |
231 | "The FCP device is operational again\n"); | ||
232 | zfcp_erp_modify_adapter_status(adapter, "ccnoti3", NULL, | 227 | zfcp_erp_modify_adapter_status(adapter, "ccnoti3", NULL, |
233 | ZFCP_STATUS_COMMON_RUNNING, | 228 | ZFCP_STATUS_COMMON_RUNNING, |
234 | ZFCP_SET); | 229 | ZFCP_SET); |
@@ -236,11 +231,13 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) | |||
236 | "ccnoti4", NULL); | 231 | "ccnoti4", NULL); |
237 | break; | 232 | break; |
238 | case CIO_BOXED: | 233 | case CIO_BOXED: |
239 | dev_warn(&adapter->ccw_device->dev, "The FCP device " | 234 | dev_warn(&cdev->dev, "The FCP device did not respond within " |
240 | "did not respond within the specified time\n"); | 235 | "the specified time\n"); |
241 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL); | 236 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL); |
242 | break; | 237 | break; |
243 | } | 238 | } |
239 | |||
240 | zfcp_ccw_adapter_put(adapter); | ||
244 | return 1; | 241 | return 1; |
245 | } | 242 | } |
246 | 243 | ||
@@ -250,18 +247,16 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) | |||
250 | */ | 247 | */ |
251 | static void zfcp_ccw_shutdown(struct ccw_device *cdev) | 248 | static void zfcp_ccw_shutdown(struct ccw_device *cdev) |
252 | { | 249 | { |
253 | struct zfcp_adapter *adapter; | 250 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
254 | 251 | ||
255 | mutex_lock(&zfcp_data.config_mutex); | ||
256 | adapter = dev_get_drvdata(&cdev->dev); | ||
257 | if (!adapter) | 252 | if (!adapter) |
258 | goto out; | 253 | return; |
259 | 254 | ||
260 | zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL); | 255 | zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL); |
261 | zfcp_erp_wait(adapter); | 256 | zfcp_erp_wait(adapter); |
262 | zfcp_erp_thread_kill(adapter); | 257 | zfcp_erp_thread_kill(adapter); |
263 | out: | 258 | |
264 | mutex_unlock(&zfcp_data.config_mutex); | 259 | zfcp_ccw_adapter_put(adapter); |
265 | } | 260 | } |
266 | 261 | ||
267 | struct ccw_driver zfcp_ccw_driver = { | 262 | struct ccw_driver zfcp_ccw_driver = { |
@@ -274,18 +269,7 @@ struct ccw_driver zfcp_ccw_driver = { | |||
274 | .set_offline = zfcp_ccw_set_offline, | 269 | .set_offline = zfcp_ccw_set_offline, |
275 | .notify = zfcp_ccw_notify, | 270 | .notify = zfcp_ccw_notify, |
276 | .shutdown = zfcp_ccw_shutdown, | 271 | .shutdown = zfcp_ccw_shutdown, |
277 | .freeze = zfcp_ccw_suspend, | 272 | .freeze = zfcp_ccw_set_offline, |
278 | .thaw = zfcp_ccw_activate, | 273 | .thaw = zfcp_ccw_activate, |
279 | .restore = zfcp_ccw_activate, | 274 | .restore = zfcp_ccw_activate, |
280 | }; | 275 | }; |
281 | |||
282 | /** | ||
283 | * zfcp_ccw_register - ccw register function | ||
284 | * | ||
285 | * Registers the driver at the common i/o layer. This function will be called | ||
286 | * at module load time/system start. | ||
287 | */ | ||
288 | int __init zfcp_ccw_register(void) | ||
289 | { | ||
290 | return ccw_driver_register(&zfcp_ccw_driver); | ||
291 | } | ||