diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-15 21:58:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-15 21:58:04 -0400 |
commit | 89a93f2f4834f8c126e8d9dd6b368d0b9e21ec3d (patch) | |
tree | e731456fec0cab1225ad3e806dc8d3efefa0a78b /drivers/s390 | |
parent | 260eddf4391f162a69d1d163729249635fa7a78f (diff) | |
parent | fe9233fb6914a0eb20166c967e3020f7f0fba2c9 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (102 commits)
[SCSI] scsi_dh: fix kconfig related build errors
[SCSI] sym53c8xx: Fix bogus sym_que_entry re-implementation of container_of
[SCSI] scsi_cmnd.h: remove double inclusion of linux/blkdev.h
[SCSI] make struct scsi_{host,target}_type static
[SCSI] fix locking in host use of blk_plug_device()
[SCSI] zfcp: Cleanup external header file
[SCSI] zfcp: Cleanup code in zfcp_erp.c
[SCSI] zfcp: zfcp_fsf cleanup.
[SCSI] zfcp: consolidate sysfs things into one file.
[SCSI] zfcp: Cleanup of code in zfcp_aux.c
[SCSI] zfcp: Cleanup of code in zfcp_scsi.c
[SCSI] zfcp: Move status accessors from zfcp to SCSI include file.
[SCSI] zfcp: Small QDIO cleanups
[SCSI] zfcp: Adapter reopen for large number of unsolicited status
[SCSI] zfcp: Fix error checking for ELS ADISC requests
[SCSI] zfcp: wait until adapter is finished with ERP during auto-port
[SCSI] ibmvfc: IBM Power Virtual Fibre Channel Adapter Client Driver
[SCSI] sg: Add target reset support
[SCSI] lib: Add support for the T10 (SCSI) Data Integrity Field CRC
[SCSI] sd: Move scsi_disk() accessor function to sd.h
...
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/scsi/Makefile | 3 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 1689 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ccw.c | 152 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_cfdc.c | 259 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.c | 90 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.h | 12 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 341 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 3824 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 301 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 567 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 5573 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.h | 70 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_qdio.c | 811 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 784 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_sysfs.c | 496 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_sysfs_adapter.c | 270 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_sysfs_driver.c | 106 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_sysfs_port.c | 295 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_sysfs_unit.c | 167 |
19 files changed, 5379 insertions, 10431 deletions
diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index d6a78f1a2f16..cb301cc6178c 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile | |||
@@ -3,7 +3,6 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ | 5 | zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ |
6 | zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \ | 6 | zfcp_fsf.o zfcp_dbf.o zfcp_sysfs.o zfcp_fc.o zfcp_cfdc.o |
7 | zfcp_sysfs_unit.o zfcp_sysfs_driver.o | ||
8 | 7 | ||
9 | obj-$(CONFIG_ZFCP) += zfcp.o | 8 | obj-$(CONFIG_ZFCP) += zfcp.o |
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 8c7e2b778ef1..90abfd06ed55 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -1,22 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Module interface and handling of zfcp data structures. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | /* | 9 | /* |
@@ -31,93 +18,25 @@ | |||
31 | * Maxim Shchetynin | 18 | * Maxim Shchetynin |
32 | * Volker Sameske | 19 | * Volker Sameske |
33 | * Ralph Wuerthner | 20 | * Ralph Wuerthner |
21 | * Michael Loehr | ||
22 | * Swen Schillig | ||
23 | * Christof Schmitt | ||
24 | * Martin Petermann | ||
25 | * Sven Schuetz | ||
34 | */ | 26 | */ |
35 | 27 | ||
28 | #include <linux/miscdevice.h> | ||
36 | #include "zfcp_ext.h" | 29 | #include "zfcp_ext.h" |
37 | 30 | ||
38 | /* accumulated log level (module parameter) */ | ||
39 | static u32 loglevel = ZFCP_LOG_LEVEL_DEFAULTS; | ||
40 | static char *device; | 31 | static char *device; |
41 | /*********************** FUNCTION PROTOTYPES *********************************/ | ||
42 | |||
43 | /* written against the module interface */ | ||
44 | static int __init zfcp_module_init(void); | ||
45 | |||
46 | /* FCP related */ | ||
47 | static void zfcp_ns_gid_pn_handler(unsigned long); | ||
48 | |||
49 | /* miscellaneous */ | ||
50 | static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); | ||
51 | static void zfcp_sg_list_free(struct zfcp_sg_list *); | ||
52 | static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, | ||
53 | void __user *, size_t); | ||
54 | static int zfcp_sg_list_copy_to_user(void __user *, | ||
55 | struct zfcp_sg_list *, size_t); | ||
56 | static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long); | ||
57 | |||
58 | #define ZFCP_CFDC_IOC_MAGIC 0xDD | ||
59 | #define ZFCP_CFDC_IOC \ | ||
60 | _IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_sense_data) | ||
61 | |||
62 | |||
63 | static const struct file_operations zfcp_cfdc_fops = { | ||
64 | .unlocked_ioctl = zfcp_cfdc_dev_ioctl, | ||
65 | #ifdef CONFIG_COMPAT | ||
66 | .compat_ioctl = zfcp_cfdc_dev_ioctl | ||
67 | #endif | ||
68 | }; | ||
69 | |||
70 | static struct miscdevice zfcp_cfdc_misc = { | ||
71 | .minor = ZFCP_CFDC_DEV_MINOR, | ||
72 | .name = ZFCP_CFDC_DEV_NAME, | ||
73 | .fops = &zfcp_cfdc_fops | ||
74 | }; | ||
75 | |||
76 | /*********************** KERNEL/MODULE PARAMETERS ***************************/ | ||
77 | |||
78 | /* declare driver module init/cleanup functions */ | ||
79 | module_init(zfcp_module_init); | ||
80 | 32 | ||
81 | MODULE_AUTHOR("IBM Deutschland Entwicklung GmbH - linux390@de.ibm.com"); | 33 | MODULE_AUTHOR("IBM Deutschland Entwicklung GmbH - linux390@de.ibm.com"); |
82 | MODULE_DESCRIPTION | 34 | MODULE_DESCRIPTION("FCP HBA driver"); |
83 | ("FCP (SCSI over Fibre Channel) HBA driver for IBM System z9 and zSeries"); | ||
84 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL"); |
85 | 36 | ||
86 | module_param(device, charp, 0400); | 37 | module_param(device, charp, 0400); |
87 | MODULE_PARM_DESC(device, "specify initial device"); | 38 | MODULE_PARM_DESC(device, "specify initial device"); |
88 | 39 | ||
89 | module_param(loglevel, uint, 0400); | ||
90 | MODULE_PARM_DESC(loglevel, | ||
91 | "log levels, 8 nibbles: " | ||
92 | "FC ERP QDIO CIO Config FSF SCSI Other, " | ||
93 | "levels: 0=none 1=normal 2=devel 3=trace"); | ||
94 | |||
95 | /****************************************************************/ | ||
96 | /************** Functions without logging ***********************/ | ||
97 | /****************************************************************/ | ||
98 | |||
99 | void | ||
100 | _zfcp_hex_dump(char *addr, int count) | ||
101 | { | ||
102 | int i; | ||
103 | for (i = 0; i < count; i++) { | ||
104 | printk("%02x", addr[i]); | ||
105 | if ((i % 4) == 3) | ||
106 | printk(" "); | ||
107 | if ((i % 32) == 31) | ||
108 | printk("\n"); | ||
109 | } | ||
110 | if (((i-1) % 32) != 31) | ||
111 | printk("\n"); | ||
112 | } | ||
113 | |||
114 | |||
115 | /****************************************************************/ | ||
116 | /****** Functions to handle the request ID hash table ********/ | ||
117 | /****************************************************************/ | ||
118 | |||
119 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF | ||
120 | |||
121 | static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) | 40 | static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) |
122 | { | 41 | { |
123 | int idx; | 42 | int idx; |
@@ -132,11 +51,12 @@ static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) | |||
132 | return 0; | 51 | return 0; |
133 | } | 52 | } |
134 | 53 | ||
135 | static void zfcp_reqlist_free(struct zfcp_adapter *adapter) | 54 | /** |
136 | { | 55 | * zfcp_reqlist_isempty - is the request list empty |
137 | kfree(adapter->req_list); | 56 | * @adapter: pointer to struct zfcp_adapter |
138 | } | 57 | * |
139 | 58 | * Returns: true if list is empty, false otherwise | |
59 | */ | ||
140 | int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) | 60 | int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) |
141 | { | 61 | { |
142 | unsigned int idx; | 62 | unsigned int idx; |
@@ -147,62 +67,58 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) | |||
147 | return 1; | 67 | return 1; |
148 | } | 68 | } |
149 | 69 | ||
150 | #undef ZFCP_LOG_AREA | 70 | static int __init zfcp_device_setup(char *devstr) |
151 | |||
152 | /****************************************************************/ | ||
153 | /************** Uncategorised Functions *************************/ | ||
154 | /****************************************************************/ | ||
155 | |||
156 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER | ||
157 | |||
158 | /** | ||
159 | * zfcp_device_setup - setup function | ||
160 | * @str: pointer to parameter string | ||
161 | * | ||
162 | * Parse "device=..." parameter string. | ||
163 | */ | ||
164 | static int __init | ||
165 | zfcp_device_setup(char *devstr) | ||
166 | { | 71 | { |
167 | char *tmp, *str; | 72 | char *token; |
168 | size_t len; | 73 | char *str; |
169 | 74 | ||
170 | if (!devstr) | 75 | if (!devstr) |
171 | return 0; | 76 | return 0; |
172 | 77 | ||
173 | len = strlen(devstr) + 1; | 78 | /* duplicate devstr and keep the original for sysfs presentation*/ |
174 | str = kmalloc(len, GFP_KERNEL); | 79 | str = kmalloc(strlen(devstr) + 1, GFP_KERNEL); |
175 | if (!str) | 80 | if (!str) |
176 | goto err_out; | 81 | return 0; |
177 | memcpy(str, devstr, len); | ||
178 | 82 | ||
179 | tmp = strchr(str, ','); | 83 | strcpy(str, devstr); |
180 | if (!tmp) | ||
181 | goto err_out; | ||
182 | *tmp++ = '\0'; | ||
183 | strncpy(zfcp_data.init_busid, str, BUS_ID_SIZE); | ||
184 | zfcp_data.init_busid[BUS_ID_SIZE-1] = '\0'; | ||
185 | 84 | ||
186 | zfcp_data.init_wwpn = simple_strtoull(tmp, &tmp, 0); | 85 | token = strsep(&str, ","); |
187 | if (*tmp++ != ',') | 86 | if (!token || strlen(token) >= BUS_ID_SIZE) |
188 | goto err_out; | 87 | goto err_out; |
189 | if (*tmp == '\0') | 88 | strncpy(zfcp_data.init_busid, token, BUS_ID_SIZE); |
89 | |||
90 | token = strsep(&str, ","); | ||
91 | if (!token || strict_strtoull(token, 0, &zfcp_data.init_wwpn)) | ||
190 | goto err_out; | 92 | goto err_out; |
191 | 93 | ||
192 | zfcp_data.init_fcp_lun = simple_strtoull(tmp, &tmp, 0); | 94 | token = strsep(&str, ","); |
193 | if (*tmp != '\0') | 95 | if (!token || strict_strtoull(token, 0, &zfcp_data.init_fcp_lun)) |
194 | goto err_out; | 96 | goto err_out; |
97 | |||
195 | kfree(str); | 98 | kfree(str); |
196 | return 1; | 99 | return 1; |
197 | 100 | ||
198 | err_out: | 101 | err_out: |
199 | ZFCP_LOG_NORMAL("Parse error for device parameter string %s\n", str); | ||
200 | kfree(str); | 102 | kfree(str); |
103 | pr_err("zfcp: Parse error for device parameter string %s, " | ||
104 | "device not attached.\n", devstr); | ||
201 | return 0; | 105 | return 0; |
202 | } | 106 | } |
203 | 107 | ||
204 | static void __init | 108 | static struct zfcp_adapter *zfcp_get_adapter_by_busid(char *bus_id) |
205 | zfcp_init_device_configure(void) | 109 | { |
110 | struct zfcp_adapter *adapter; | ||
111 | |||
112 | list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) | ||
113 | if ((strncmp(bus_id, adapter->ccw_device->dev.bus_id, | ||
114 | BUS_ID_SIZE) == 0) && | ||
115 | !(atomic_read(&adapter->status) & | ||
116 | ZFCP_STATUS_COMMON_REMOVE)) | ||
117 | return adapter; | ||
118 | return NULL; | ||
119 | } | ||
120 | |||
121 | static void __init zfcp_init_device_configure(void) | ||
206 | { | 122 | { |
207 | struct zfcp_adapter *adapter; | 123 | struct zfcp_adapter *adapter; |
208 | struct zfcp_port *port; | 124 | struct zfcp_port *port; |
@@ -215,101 +131,75 @@ zfcp_init_device_configure(void) | |||
215 | zfcp_adapter_get(adapter); | 131 | zfcp_adapter_get(adapter); |
216 | read_unlock_irq(&zfcp_data.config_lock); | 132 | read_unlock_irq(&zfcp_data.config_lock); |
217 | 133 | ||
218 | if (adapter == NULL) | 134 | if (!adapter) |
219 | goto out_adapter; | 135 | goto out_adapter; |
220 | port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0); | 136 | port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0); |
221 | if (!port) | 137 | if (IS_ERR(port)) |
222 | goto out_port; | 138 | goto out_port; |
223 | unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun); | 139 | unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun); |
224 | if (!unit) | 140 | if (IS_ERR(unit)) |
225 | goto out_unit; | 141 | goto out_unit; |
226 | up(&zfcp_data.config_sema); | 142 | up(&zfcp_data.config_sema); |
227 | ccw_device_set_online(adapter->ccw_device); | 143 | ccw_device_set_online(adapter->ccw_device); |
228 | zfcp_erp_wait(adapter); | 144 | zfcp_erp_wait(adapter); |
229 | down(&zfcp_data.config_sema); | 145 | down(&zfcp_data.config_sema); |
230 | zfcp_unit_put(unit); | 146 | zfcp_unit_put(unit); |
231 | out_unit: | 147 | out_unit: |
232 | zfcp_port_put(port); | 148 | zfcp_port_put(port); |
233 | out_port: | 149 | out_port: |
234 | zfcp_adapter_put(adapter); | 150 | zfcp_adapter_put(adapter); |
235 | out_adapter: | 151 | out_adapter: |
236 | up(&zfcp_data.config_sema); | 152 | up(&zfcp_data.config_sema); |
237 | return; | 153 | return; |
238 | } | 154 | } |
239 | 155 | ||
240 | static int calc_alignment(int size) | 156 | static struct kmem_cache *zfcp_cache_create(int size, char *name) |
241 | { | 157 | { |
242 | int align = 1; | 158 | int align = 1; |
243 | |||
244 | if (!size) | ||
245 | return 0; | ||
246 | |||
247 | while ((size - align) > 0) | 159 | while ((size - align) > 0) |
248 | align <<= 1; | 160 | align <<= 1; |
249 | 161 | return kmem_cache_create(name , size, align, 0, NULL); | |
250 | return align; | ||
251 | } | 162 | } |
252 | 163 | ||
253 | static int __init | 164 | static int __init zfcp_module_init(void) |
254 | zfcp_module_init(void) | ||
255 | { | 165 | { |
256 | int retval = -ENOMEM; | 166 | int retval = -ENOMEM; |
257 | int size, align; | ||
258 | 167 | ||
259 | size = sizeof(struct zfcp_fsf_req_qtcb); | 168 | zfcp_data.fsf_req_qtcb_cache = zfcp_cache_create( |
260 | align = calc_alignment(size); | 169 | sizeof(struct zfcp_fsf_req_qtcb), "zfcp_fsf"); |
261 | zfcp_data.fsf_req_qtcb_cache = | ||
262 | kmem_cache_create("zfcp_fsf", size, align, 0, NULL); | ||
263 | if (!zfcp_data.fsf_req_qtcb_cache) | 170 | if (!zfcp_data.fsf_req_qtcb_cache) |
264 | goto out; | 171 | goto out; |
265 | 172 | ||
266 | size = sizeof(struct fsf_status_read_buffer); | 173 | zfcp_data.sr_buffer_cache = zfcp_cache_create( |
267 | align = calc_alignment(size); | 174 | sizeof(struct fsf_status_read_buffer), "zfcp_sr"); |
268 | zfcp_data.sr_buffer_cache = | ||
269 | kmem_cache_create("zfcp_sr", size, align, 0, NULL); | ||
270 | if (!zfcp_data.sr_buffer_cache) | 175 | if (!zfcp_data.sr_buffer_cache) |
271 | goto out_sr_cache; | 176 | goto out_sr_cache; |
272 | 177 | ||
273 | size = sizeof(struct zfcp_gid_pn_data); | 178 | zfcp_data.gid_pn_cache = zfcp_cache_create( |
274 | align = calc_alignment(size); | 179 | sizeof(struct zfcp_gid_pn_data), "zfcp_gid"); |
275 | zfcp_data.gid_pn_cache = | ||
276 | kmem_cache_create("zfcp_gid", size, align, 0, NULL); | ||
277 | if (!zfcp_data.gid_pn_cache) | 180 | if (!zfcp_data.gid_pn_cache) |
278 | goto out_gid_cache; | 181 | goto out_gid_cache; |
279 | 182 | ||
280 | atomic_set(&zfcp_data.loglevel, loglevel); | ||
281 | |||
282 | /* initialize adapter list */ | ||
283 | INIT_LIST_HEAD(&zfcp_data.adapter_list_head); | 183 | INIT_LIST_HEAD(&zfcp_data.adapter_list_head); |
284 | |||
285 | /* initialize adapters to be removed list head */ | ||
286 | INIT_LIST_HEAD(&zfcp_data.adapter_remove_lh); | 184 | INIT_LIST_HEAD(&zfcp_data.adapter_remove_lh); |
287 | 185 | ||
186 | sema_init(&zfcp_data.config_sema, 1); | ||
187 | rwlock_init(&zfcp_data.config_lock); | ||
188 | |||
288 | zfcp_data.scsi_transport_template = | 189 | zfcp_data.scsi_transport_template = |
289 | fc_attach_transport(&zfcp_transport_functions); | 190 | fc_attach_transport(&zfcp_transport_functions); |
290 | if (!zfcp_data.scsi_transport_template) | 191 | if (!zfcp_data.scsi_transport_template) |
291 | goto out_transport; | 192 | goto out_transport; |
292 | 193 | ||
293 | retval = misc_register(&zfcp_cfdc_misc); | 194 | retval = misc_register(&zfcp_cfdc_misc); |
294 | if (retval != 0) { | 195 | if (retval) { |
295 | ZFCP_LOG_INFO("registration of misc device " | 196 | pr_err("zfcp: registration of misc device zfcp_cfdc failed\n"); |
296 | "zfcp_cfdc failed\n"); | ||
297 | goto out_misc; | 197 | goto out_misc; |
298 | } | 198 | } |
299 | 199 | ||
300 | ZFCP_LOG_TRACE("major/minor for zfcp_cfdc: %d/%d\n", | ||
301 | ZFCP_CFDC_DEV_MAJOR, zfcp_cfdc_misc.minor); | ||
302 | |||
303 | /* Initialise proc semaphores */ | ||
304 | sema_init(&zfcp_data.config_sema, 1); | ||
305 | |||
306 | /* initialise configuration rw lock */ | ||
307 | rwlock_init(&zfcp_data.config_lock); | ||
308 | |||
309 | /* setup dynamic I/O */ | ||
310 | retval = zfcp_ccw_register(); | 200 | retval = zfcp_ccw_register(); |
311 | if (retval) { | 201 | if (retval) { |
312 | ZFCP_LOG_NORMAL("registration with common I/O layer failed\n"); | 202 | pr_err("zfcp: Registration with common I/O layer failed.\n"); |
313 | goto out_ccw_register; | 203 | goto out_ccw_register; |
314 | } | 204 | } |
315 | 205 | ||
@@ -318,527 +208,88 @@ zfcp_module_init(void) | |||
318 | 208 | ||
319 | goto out; | 209 | goto out; |
320 | 210 | ||
321 | out_ccw_register: | 211 | out_ccw_register: |
322 | misc_deregister(&zfcp_cfdc_misc); | 212 | misc_deregister(&zfcp_cfdc_misc); |
323 | out_misc: | 213 | out_misc: |
324 | fc_release_transport(zfcp_data.scsi_transport_template); | 214 | fc_release_transport(zfcp_data.scsi_transport_template); |
325 | out_transport: | 215 | out_transport: |
326 | kmem_cache_destroy(zfcp_data.gid_pn_cache); | 216 | kmem_cache_destroy(zfcp_data.gid_pn_cache); |
327 | out_gid_cache: | 217 | out_gid_cache: |
328 | kmem_cache_destroy(zfcp_data.sr_buffer_cache); | 218 | kmem_cache_destroy(zfcp_data.sr_buffer_cache); |
329 | out_sr_cache: | 219 | out_sr_cache: |
330 | kmem_cache_destroy(zfcp_data.fsf_req_qtcb_cache); | 220 | kmem_cache_destroy(zfcp_data.fsf_req_qtcb_cache); |
331 | out: | 221 | out: |
332 | return retval; | 222 | return retval; |
333 | } | 223 | } |
334 | 224 | ||
335 | /* | 225 | module_init(zfcp_module_init); |
336 | * function: zfcp_cfdc_dev_ioctl | ||
337 | * | ||
338 | * purpose: Handle control file upload/download transaction via IOCTL | ||
339 | * interface | ||
340 | * | ||
341 | * returns: 0 - Operation completed successfuly | ||
342 | * -ENOTTY - Unknown IOCTL command | ||
343 | * -EINVAL - Invalid sense data record | ||
344 | * -ENXIO - The FCP adapter is not available | ||
345 | * -EOPNOTSUPP - The FCP adapter does not have CFDC support | ||
346 | * -ENOMEM - Insufficient memory | ||
347 | * -EFAULT - User space memory I/O operation fault | ||
348 | * -EPERM - Cannot create or queue FSF request or create SBALs | ||
349 | * -ERESTARTSYS- Received signal (is mapped to EAGAIN by VFS) | ||
350 | */ | ||
351 | static long | ||
352 | zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, | ||
353 | unsigned long buffer) | ||
354 | { | ||
355 | struct zfcp_cfdc_sense_data *sense_data, __user *sense_data_user; | ||
356 | struct zfcp_adapter *adapter = NULL; | ||
357 | struct zfcp_fsf_req *fsf_req = NULL; | ||
358 | struct zfcp_sg_list *sg_list = NULL; | ||
359 | u32 fsf_command, option; | ||
360 | char *bus_id = NULL; | ||
361 | int retval = 0; | ||
362 | |||
363 | sense_data = kmalloc(sizeof(struct zfcp_cfdc_sense_data), GFP_KERNEL); | ||
364 | if (sense_data == NULL) { | ||
365 | retval = -ENOMEM; | ||
366 | goto out; | ||
367 | } | ||
368 | |||
369 | sg_list = kzalloc(sizeof(struct zfcp_sg_list), GFP_KERNEL); | ||
370 | if (sg_list == NULL) { | ||
371 | retval = -ENOMEM; | ||
372 | goto out; | ||
373 | } | ||
374 | |||
375 | if (command != ZFCP_CFDC_IOC) { | ||
376 | ZFCP_LOG_INFO("IOC request code 0x%x invalid\n", command); | ||
377 | retval = -ENOTTY; | ||
378 | goto out; | ||
379 | } | ||
380 | |||
381 | if ((sense_data_user = (void __user *) buffer) == NULL) { | ||
382 | ZFCP_LOG_INFO("sense data record is required\n"); | ||
383 | retval = -EINVAL; | ||
384 | goto out; | ||
385 | } | ||
386 | |||
387 | retval = copy_from_user(sense_data, sense_data_user, | ||
388 | sizeof(struct zfcp_cfdc_sense_data)); | ||
389 | if (retval) { | ||
390 | retval = -EFAULT; | ||
391 | goto out; | ||
392 | } | ||
393 | |||
394 | if (sense_data->signature != ZFCP_CFDC_SIGNATURE) { | ||
395 | ZFCP_LOG_INFO("invalid sense data request signature 0x%08x\n", | ||
396 | ZFCP_CFDC_SIGNATURE); | ||
397 | retval = -EINVAL; | ||
398 | goto out; | ||
399 | } | ||
400 | |||
401 | switch (sense_data->command) { | ||
402 | |||
403 | case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL: | ||
404 | fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
405 | option = FSF_CFDC_OPTION_NORMAL_MODE; | ||
406 | break; | ||
407 | |||
408 | case ZFCP_CFDC_CMND_DOWNLOAD_FORCE: | ||
409 | fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
410 | option = FSF_CFDC_OPTION_FORCE; | ||
411 | break; | ||
412 | |||
413 | case ZFCP_CFDC_CMND_FULL_ACCESS: | ||
414 | fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
415 | option = FSF_CFDC_OPTION_FULL_ACCESS; | ||
416 | break; | ||
417 | |||
418 | case ZFCP_CFDC_CMND_RESTRICTED_ACCESS: | ||
419 | fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
420 | option = FSF_CFDC_OPTION_RESTRICTED_ACCESS; | ||
421 | break; | ||
422 | |||
423 | case ZFCP_CFDC_CMND_UPLOAD: | ||
424 | fsf_command = FSF_QTCB_UPLOAD_CONTROL_FILE; | ||
425 | option = 0; | ||
426 | break; | ||
427 | |||
428 | default: | ||
429 | ZFCP_LOG_INFO("invalid command code 0x%08x\n", | ||
430 | sense_data->command); | ||
431 | retval = -EINVAL; | ||
432 | goto out; | ||
433 | } | ||
434 | |||
435 | bus_id = kmalloc(BUS_ID_SIZE, GFP_KERNEL); | ||
436 | if (bus_id == NULL) { | ||
437 | retval = -ENOMEM; | ||
438 | goto out; | ||
439 | } | ||
440 | snprintf(bus_id, BUS_ID_SIZE, "%d.%d.%04x", | ||
441 | (sense_data->devno >> 24), | ||
442 | (sense_data->devno >> 16) & 0xFF, | ||
443 | (sense_data->devno & 0xFFFF)); | ||
444 | |||
445 | read_lock_irq(&zfcp_data.config_lock); | ||
446 | adapter = zfcp_get_adapter_by_busid(bus_id); | ||
447 | if (adapter) | ||
448 | zfcp_adapter_get(adapter); | ||
449 | read_unlock_irq(&zfcp_data.config_lock); | ||
450 | |||
451 | kfree(bus_id); | ||
452 | |||
453 | if (adapter == NULL) { | ||
454 | ZFCP_LOG_INFO("invalid adapter\n"); | ||
455 | retval = -ENXIO; | ||
456 | goto out; | ||
457 | } | ||
458 | |||
459 | if (sense_data->command & ZFCP_CFDC_WITH_CONTROL_FILE) { | ||
460 | retval = zfcp_sg_list_alloc(sg_list, | ||
461 | ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); | ||
462 | if (retval) { | ||
463 | retval = -ENOMEM; | ||
464 | goto out; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | if ((sense_data->command & ZFCP_CFDC_DOWNLOAD) && | ||
469 | (sense_data->command & ZFCP_CFDC_WITH_CONTROL_FILE)) { | ||
470 | retval = zfcp_sg_list_copy_from_user( | ||
471 | sg_list, &sense_data_user->control_file, | ||
472 | ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); | ||
473 | if (retval) { | ||
474 | retval = -EFAULT; | ||
475 | goto out; | ||
476 | } | ||
477 | } | ||
478 | |||
479 | retval = zfcp_fsf_control_file(adapter, &fsf_req, fsf_command, | ||
480 | option, sg_list); | ||
481 | if (retval) | ||
482 | goto out; | ||
483 | |||
484 | if ((fsf_req->qtcb->prefix.prot_status != FSF_PROT_GOOD) && | ||
485 | (fsf_req->qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { | ||
486 | retval = -ENXIO; | ||
487 | goto out; | ||
488 | } | ||
489 | |||
490 | sense_data->fsf_status = fsf_req->qtcb->header.fsf_status; | ||
491 | memcpy(&sense_data->fsf_status_qual, | ||
492 | &fsf_req->qtcb->header.fsf_status_qual, | ||
493 | sizeof(union fsf_status_qual)); | ||
494 | memcpy(&sense_data->payloads, &fsf_req->qtcb->bottom.support.els, 256); | ||
495 | |||
496 | retval = copy_to_user(sense_data_user, sense_data, | ||
497 | sizeof(struct zfcp_cfdc_sense_data)); | ||
498 | if (retval) { | ||
499 | retval = -EFAULT; | ||
500 | goto out; | ||
501 | } | ||
502 | |||
503 | if (sense_data->command & ZFCP_CFDC_UPLOAD) { | ||
504 | retval = zfcp_sg_list_copy_to_user( | ||
505 | &sense_data_user->control_file, sg_list, | ||
506 | ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); | ||
507 | if (retval) { | ||
508 | retval = -EFAULT; | ||
509 | goto out; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | out: | ||
514 | if (fsf_req != NULL) | ||
515 | zfcp_fsf_req_free(fsf_req); | ||
516 | |||
517 | if ((adapter != NULL) && (retval != -ENXIO)) | ||
518 | zfcp_adapter_put(adapter); | ||
519 | |||
520 | if (sg_list != NULL) { | ||
521 | zfcp_sg_list_free(sg_list); | ||
522 | kfree(sg_list); | ||
523 | } | ||
524 | |||
525 | kfree(sense_data); | ||
526 | |||
527 | return retval; | ||
528 | } | ||
529 | |||
530 | |||
531 | /** | ||
532 | * zfcp_sg_list_alloc - create a scatter-gather list of the specified size | ||
533 | * @sg_list: structure describing a scatter gather list | ||
534 | * @size: size of scatter-gather list | ||
535 | * Return: 0 on success, else -ENOMEM | ||
536 | * | ||
537 | * In sg_list->sg a pointer to the created scatter-gather list is returned, | ||
538 | * or NULL if we run out of memory. sg_list->count specifies the number of | ||
539 | * elements of the scatter-gather list. The maximum size of a single element | ||
540 | * in the scatter-gather list is PAGE_SIZE. | ||
541 | */ | ||
542 | static int | ||
543 | zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) | ||
544 | { | ||
545 | struct scatterlist *sg; | ||
546 | unsigned int i; | ||
547 | int retval = 0; | ||
548 | void *address; | ||
549 | |||
550 | BUG_ON(sg_list == NULL); | ||
551 | |||
552 | sg_list->count = size >> PAGE_SHIFT; | ||
553 | if (size & ~PAGE_MASK) | ||
554 | sg_list->count++; | ||
555 | sg_list->sg = kcalloc(sg_list->count, sizeof(struct scatterlist), | ||
556 | GFP_KERNEL); | ||
557 | if (sg_list->sg == NULL) { | ||
558 | sg_list->count = 0; | ||
559 | retval = -ENOMEM; | ||
560 | goto out; | ||
561 | } | ||
562 | sg_init_table(sg_list->sg, sg_list->count); | ||
563 | |||
564 | for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) { | ||
565 | address = (void *) get_zeroed_page(GFP_KERNEL); | ||
566 | if (address == NULL) { | ||
567 | sg_list->count = i; | ||
568 | zfcp_sg_list_free(sg_list); | ||
569 | retval = -ENOMEM; | ||
570 | goto out; | ||
571 | } | ||
572 | zfcp_address_to_sg(address, sg, min(size, PAGE_SIZE)); | ||
573 | size -= sg->length; | ||
574 | } | ||
575 | |||
576 | out: | ||
577 | return retval; | ||
578 | } | ||
579 | |||
580 | |||
581 | /** | ||
582 | * zfcp_sg_list_free - free memory of a scatter-gather list | ||
583 | * @sg_list: structure describing a scatter-gather list | ||
584 | * | ||
585 | * Memory for each element in the scatter-gather list is freed. | ||
586 | * Finally sg_list->sg is freed itself and sg_list->count is reset. | ||
587 | */ | ||
588 | static void | ||
589 | zfcp_sg_list_free(struct zfcp_sg_list *sg_list) | ||
590 | { | ||
591 | struct scatterlist *sg; | ||
592 | unsigned int i; | ||
593 | |||
594 | BUG_ON(sg_list == NULL); | ||
595 | |||
596 | for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) | ||
597 | free_page((unsigned long) zfcp_sg_to_address(sg)); | ||
598 | |||
599 | sg_list->count = 0; | ||
600 | kfree(sg_list->sg); | ||
601 | } | ||
602 | |||
603 | /** | ||
604 | * zfcp_sg_size - determine size of a scatter-gather list | ||
605 | * @sg: array of (struct scatterlist) | ||
606 | * @sg_count: elements in array | ||
607 | * Return: size of entire scatter-gather list | ||
608 | */ | ||
609 | static size_t zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count) | ||
610 | { | ||
611 | unsigned int i; | ||
612 | struct scatterlist *p; | ||
613 | size_t size; | ||
614 | |||
615 | size = 0; | ||
616 | for (i = 0, p = sg; i < sg_count; i++, p++) { | ||
617 | BUG_ON(p == NULL); | ||
618 | size += p->length; | ||
619 | } | ||
620 | |||
621 | return size; | ||
622 | } | ||
623 | |||
624 | |||
625 | /** | ||
626 | * zfcp_sg_list_copy_from_user -copy data from user space to scatter-gather list | ||
627 | * @sg_list: structure describing a scatter-gather list | ||
628 | * @user_buffer: pointer to buffer in user space | ||
629 | * @size: number of bytes to be copied | ||
630 | * Return: 0 on success, -EFAULT if copy_from_user fails. | ||
631 | */ | ||
632 | static int | ||
633 | zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, | ||
634 | void __user *user_buffer, | ||
635 | size_t size) | ||
636 | { | ||
637 | struct scatterlist *sg; | ||
638 | unsigned int length; | ||
639 | void *zfcp_buffer; | ||
640 | int retval = 0; | ||
641 | |||
642 | BUG_ON(sg_list == NULL); | ||
643 | |||
644 | if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) | ||
645 | return -EFAULT; | ||
646 | |||
647 | for (sg = sg_list->sg; size > 0; sg++) { | ||
648 | length = min((unsigned int)size, sg->length); | ||
649 | zfcp_buffer = zfcp_sg_to_address(sg); | ||
650 | if (copy_from_user(zfcp_buffer, user_buffer, length)) { | ||
651 | retval = -EFAULT; | ||
652 | goto out; | ||
653 | } | ||
654 | user_buffer += length; | ||
655 | size -= length; | ||
656 | } | ||
657 | |||
658 | out: | ||
659 | return retval; | ||
660 | } | ||
661 | |||
662 | |||
663 | /** | ||
664 | * zfcp_sg_list_copy_to_user - copy data from scatter-gather list to user space | ||
665 | * @user_buffer: pointer to buffer in user space | ||
666 | * @sg_list: structure describing a scatter-gather list | ||
667 | * @size: number of bytes to be copied | ||
668 | * Return: 0 on success, -EFAULT if copy_to_user fails | ||
669 | */ | ||
670 | static int | ||
671 | zfcp_sg_list_copy_to_user(void __user *user_buffer, | ||
672 | struct zfcp_sg_list *sg_list, | ||
673 | size_t size) | ||
674 | { | ||
675 | struct scatterlist *sg; | ||
676 | unsigned int length; | ||
677 | void *zfcp_buffer; | ||
678 | int retval = 0; | ||
679 | |||
680 | BUG_ON(sg_list == NULL); | ||
681 | |||
682 | if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) | ||
683 | return -EFAULT; | ||
684 | |||
685 | for (sg = sg_list->sg; size > 0; sg++) { | ||
686 | length = min((unsigned int) size, sg->length); | ||
687 | zfcp_buffer = zfcp_sg_to_address(sg); | ||
688 | if (copy_to_user(user_buffer, zfcp_buffer, length)) { | ||
689 | retval = -EFAULT; | ||
690 | goto out; | ||
691 | } | ||
692 | user_buffer += length; | ||
693 | size -= length; | ||
694 | } | ||
695 | |||
696 | out: | ||
697 | return retval; | ||
698 | } | ||
699 | |||
700 | |||
701 | #undef ZFCP_LOG_AREA | ||
702 | |||
703 | /****************************************************************/ | ||
704 | /****** Functions for configuration/set-up of structures ********/ | ||
705 | /****************************************************************/ | ||
706 | |||
707 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG | ||
708 | 226 | ||
709 | /** | 227 | /** |
710 | * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN | 228 | * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN |
711 | * @port: pointer to port to search for unit | 229 | * @port: pointer to port to search for unit |
712 | * @fcp_lun: FCP LUN to search for | 230 | * @fcp_lun: FCP LUN to search for |
713 | * Traverse list of all units of a port and return pointer to a unit | 231 | * |
714 | * with the given FCP LUN. | 232 | * Returns: pointer to zfcp_unit or NULL |
715 | */ | 233 | */ |
716 | struct zfcp_unit * | 234 | struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, |
717 | zfcp_get_unit_by_lun(struct zfcp_port *port, fcp_lun_t fcp_lun) | 235 | fcp_lun_t fcp_lun) |
718 | { | 236 | { |
719 | struct zfcp_unit *unit; | 237 | struct zfcp_unit *unit; |
720 | int found = 0; | ||
721 | 238 | ||
722 | list_for_each_entry(unit, &port->unit_list_head, list) { | 239 | list_for_each_entry(unit, &port->unit_list_head, list) |
723 | if ((unit->fcp_lun == fcp_lun) && | 240 | if ((unit->fcp_lun == fcp_lun) && |
724 | !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status)) | 241 | !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) |
725 | { | 242 | return unit; |
726 | found = 1; | 243 | return NULL; |
727 | break; | ||
728 | } | ||
729 | } | ||
730 | return found ? unit : NULL; | ||
731 | } | 244 | } |
732 | 245 | ||
733 | /** | 246 | /** |
734 | * zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn | 247 | * zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn |
735 | * @adapter: pointer to adapter to search for port | 248 | * @adapter: pointer to adapter to search for port |
736 | * @wwpn: wwpn to search for | 249 | * @wwpn: wwpn to search for |
737 | * Traverse list of all ports of an adapter and return pointer to a port | 250 | * |
738 | * with the given wwpn. | 251 | * Returns: pointer to zfcp_port or NULL |
739 | */ | ||
740 | struct zfcp_port * | ||
741 | zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, wwn_t wwpn) | ||
742 | { | ||
743 | struct zfcp_port *port; | ||
744 | int found = 0; | ||
745 | |||
746 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
747 | if ((port->wwpn == wwpn) && | ||
748 | !(atomic_read(&port->status) & | ||
749 | (ZFCP_STATUS_PORT_NO_WWPN | ZFCP_STATUS_COMMON_REMOVE))) { | ||
750 | found = 1; | ||
751 | break; | ||
752 | } | ||
753 | } | ||
754 | return found ? port : NULL; | ||
755 | } | ||
756 | |||
757 | /** | ||
758 | * zfcp_get_port_by_did - find port in port list of adapter by d_id | ||
759 | * @adapter: pointer to adapter to search for port | ||
760 | * @d_id: d_id to search for | ||
761 | * Traverse list of all ports of an adapter and return pointer to a port | ||
762 | * with the given d_id. | ||
763 | */ | 252 | */ |
764 | struct zfcp_port * | 253 | struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, |
765 | zfcp_get_port_by_did(struct zfcp_adapter *adapter, u32 d_id) | 254 | wwn_t wwpn) |
766 | { | 255 | { |
767 | struct zfcp_port *port; | 256 | struct zfcp_port *port; |
768 | int found = 0; | ||
769 | 257 | ||
770 | list_for_each_entry(port, &adapter->port_list_head, list) { | 258 | list_for_each_entry(port, &adapter->port_list_head, list) |
771 | if ((port->d_id == d_id) && | 259 | if ((port->wwpn == wwpn) && !(atomic_read(&port->status) & |
772 | !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) | 260 | (ZFCP_STATUS_PORT_NO_WWPN | ZFCP_STATUS_COMMON_REMOVE))) |
773 | { | 261 | return port; |
774 | found = 1; | 262 | return NULL; |
775 | break; | ||
776 | } | ||
777 | } | ||
778 | return found ? port : NULL; | ||
779 | } | 263 | } |
780 | 264 | ||
781 | /** | 265 | static void zfcp_sysfs_unit_release(struct device *dev) |
782 | * zfcp_get_adapter_by_busid - find adpater in adapter list by bus_id | ||
783 | * @bus_id: bus_id to search for | ||
784 | * Traverse list of all adapters and return pointer to an adapter | ||
785 | * with the given bus_id. | ||
786 | */ | ||
787 | struct zfcp_adapter * | ||
788 | zfcp_get_adapter_by_busid(char *bus_id) | ||
789 | { | 266 | { |
790 | struct zfcp_adapter *adapter; | 267 | kfree(container_of(dev, struct zfcp_unit, sysfs_device)); |
791 | int found = 0; | ||
792 | |||
793 | list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) { | ||
794 | if ((strncmp(bus_id, zfcp_get_busid_by_adapter(adapter), | ||
795 | BUS_ID_SIZE) == 0) && | ||
796 | !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, | ||
797 | &adapter->status)){ | ||
798 | found = 1; | ||
799 | break; | ||
800 | } | ||
801 | } | ||
802 | return found ? adapter : NULL; | ||
803 | } | 268 | } |
804 | 269 | ||
805 | /** | 270 | /** |
806 | * zfcp_unit_enqueue - enqueue unit to unit list of a port. | 271 | * zfcp_unit_enqueue - enqueue unit to unit list of a port. |
807 | * @port: pointer to port where unit is added | 272 | * @port: pointer to port where unit is added |
808 | * @fcp_lun: FCP LUN of unit to be enqueued | 273 | * @fcp_lun: FCP LUN of unit to be enqueued |
809 | * Return: pointer to enqueued unit on success, NULL on error | 274 | * Returns: pointer to enqueued unit on success, ERR_PTR on error |
810 | * Locks: config_sema must be held to serialize changes to the unit list | 275 | * Locks: config_sema must be held to serialize changes to the unit list |
811 | * | 276 | * |
812 | * Sets up some unit internal structures and creates sysfs entry. | 277 | * Sets up some unit internal structures and creates sysfs entry. |
813 | */ | 278 | */ |
814 | struct zfcp_unit * | 279 | struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) |
815 | zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) | ||
816 | { | 280 | { |
817 | struct zfcp_unit *unit; | 281 | struct zfcp_unit *unit; |
818 | 282 | ||
819 | /* | 283 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); |
820 | * check that there is no unit with this FCP_LUN already in list | ||
821 | * and enqueue it. | ||
822 | * Note: Unlike for the adapter and the port, this is an error | ||
823 | */ | ||
824 | read_lock_irq(&zfcp_data.config_lock); | ||
825 | unit = zfcp_get_unit_by_lun(port, fcp_lun); | ||
826 | read_unlock_irq(&zfcp_data.config_lock); | ||
827 | if (unit) | ||
828 | return NULL; | ||
829 | |||
830 | unit = kzalloc(sizeof (struct zfcp_unit), GFP_KERNEL); | ||
831 | if (!unit) | 284 | if (!unit) |
832 | return NULL; | 285 | return ERR_PTR(-ENOMEM); |
833 | 286 | ||
834 | /* initialise reference count stuff */ | ||
835 | atomic_set(&unit->refcount, 0); | 287 | atomic_set(&unit->refcount, 0); |
836 | init_waitqueue_head(&unit->remove_wq); | 288 | init_waitqueue_head(&unit->remove_wq); |
837 | 289 | ||
838 | unit->port = port; | 290 | unit->port = port; |
839 | unit->fcp_lun = fcp_lun; | 291 | unit->fcp_lun = fcp_lun; |
840 | 292 | ||
841 | /* setup for sysfs registration */ | ||
842 | snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", fcp_lun); | 293 | snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", fcp_lun); |
843 | unit->sysfs_device.parent = &port->sysfs_device; | 294 | unit->sysfs_device.parent = &port->sysfs_device; |
844 | unit->sysfs_device.release = zfcp_sysfs_unit_release; | 295 | unit->sysfs_device.release = zfcp_sysfs_unit_release; |
@@ -847,14 +298,28 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) | |||
847 | /* mark unit unusable as long as sysfs registration is not complete */ | 298 | /* mark unit unusable as long as sysfs registration is not complete */ |
848 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | 299 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); |
849 | 300 | ||
850 | if (device_register(&unit->sysfs_device)) { | 301 | spin_lock_init(&unit->latencies.lock); |
851 | kfree(unit); | 302 | unit->latencies.write.channel.min = 0xFFFFFFFF; |
852 | return NULL; | 303 | unit->latencies.write.fabric.min = 0xFFFFFFFF; |
304 | unit->latencies.read.channel.min = 0xFFFFFFFF; | ||
305 | unit->latencies.read.fabric.min = 0xFFFFFFFF; | ||
306 | unit->latencies.cmd.channel.min = 0xFFFFFFFF; | ||
307 | unit->latencies.cmd.fabric.min = 0xFFFFFFFF; | ||
308 | |||
309 | read_lock_irq(&zfcp_data.config_lock); | ||
310 | if (zfcp_get_unit_by_lun(port, fcp_lun)) { | ||
311 | read_unlock_irq(&zfcp_data.config_lock); | ||
312 | goto err_out_free; | ||
853 | } | 313 | } |
314 | read_unlock_irq(&zfcp_data.config_lock); | ||
854 | 315 | ||
855 | if (zfcp_sysfs_unit_create_files(&unit->sysfs_device)) { | 316 | if (device_register(&unit->sysfs_device)) |
317 | goto err_out_free; | ||
318 | |||
319 | if (sysfs_create_group(&unit->sysfs_device.kobj, | ||
320 | &zfcp_sysfs_unit_attrs)) { | ||
856 | device_unregister(&unit->sysfs_device); | 321 | device_unregister(&unit->sysfs_device); |
857 | return NULL; | 322 | return ERR_PTR(-EIO); |
858 | } | 323 | } |
859 | 324 | ||
860 | zfcp_unit_get(unit); | 325 | zfcp_unit_get(unit); |
@@ -864,16 +329,27 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) | |||
864 | list_add_tail(&unit->list, &port->unit_list_head); | 329 | list_add_tail(&unit->list, &port->unit_list_head); |
865 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | 330 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); |
866 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); | 331 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); |
332 | |||
867 | write_unlock_irq(&zfcp_data.config_lock); | 333 | write_unlock_irq(&zfcp_data.config_lock); |
868 | 334 | ||
869 | port->units++; | 335 | port->units++; |
870 | zfcp_port_get(port); | 336 | zfcp_port_get(port); |
871 | 337 | ||
872 | return unit; | 338 | return unit; |
339 | |||
340 | err_out_free: | ||
341 | kfree(unit); | ||
342 | return ERR_PTR(-EINVAL); | ||
873 | } | 343 | } |
874 | 344 | ||
875 | void | 345 | /** |
876 | zfcp_unit_dequeue(struct zfcp_unit *unit) | 346 | * zfcp_unit_dequeue - dequeue unit |
347 | * @unit: pointer to zfcp_unit | ||
348 | * | ||
349 | * waits until all work is done on unit and removes it then from the unit->list | ||
350 | * of the associated port. | ||
351 | */ | ||
352 | void zfcp_unit_dequeue(struct zfcp_unit *unit) | ||
877 | { | 353 | { |
878 | zfcp_unit_wait(unit); | 354 | zfcp_unit_wait(unit); |
879 | write_lock_irq(&zfcp_data.config_lock); | 355 | write_lock_irq(&zfcp_data.config_lock); |
@@ -881,68 +357,51 @@ zfcp_unit_dequeue(struct zfcp_unit *unit) | |||
881 | write_unlock_irq(&zfcp_data.config_lock); | 357 | write_unlock_irq(&zfcp_data.config_lock); |
882 | unit->port->units--; | 358 | unit->port->units--; |
883 | zfcp_port_put(unit->port); | 359 | zfcp_port_put(unit->port); |
884 | zfcp_sysfs_unit_remove_files(&unit->sysfs_device); | 360 | sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs); |
885 | device_unregister(&unit->sysfs_device); | 361 | device_unregister(&unit->sysfs_device); |
886 | } | 362 | } |
887 | 363 | ||
888 | /* | 364 | static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) |
889 | * Allocates a combined QTCB/fsf_req buffer for erp actions and fcp/SCSI | ||
890 | * commands. | ||
891 | * It also genrates fcp-nameserver request/response buffer and unsolicited | ||
892 | * status read fsf_req buffers. | ||
893 | * | ||
894 | * locks: must only be called with zfcp_data.config_sema taken | ||
895 | */ | ||
896 | static int | ||
897 | zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) | ||
898 | { | 365 | { |
366 | /* must only be called with zfcp_data.config_sema taken */ | ||
899 | adapter->pool.fsf_req_erp = | 367 | adapter->pool.fsf_req_erp = |
900 | mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_ERP_NR, | 368 | mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); |
901 | zfcp_data.fsf_req_qtcb_cache); | ||
902 | if (!adapter->pool.fsf_req_erp) | 369 | if (!adapter->pool.fsf_req_erp) |
903 | return -ENOMEM; | 370 | return -ENOMEM; |
904 | 371 | ||
905 | adapter->pool.fsf_req_scsi = | 372 | adapter->pool.fsf_req_scsi = |
906 | mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_SCSI_NR, | 373 | mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); |
907 | zfcp_data.fsf_req_qtcb_cache); | ||
908 | if (!adapter->pool.fsf_req_scsi) | 374 | if (!adapter->pool.fsf_req_scsi) |
909 | return -ENOMEM; | 375 | return -ENOMEM; |
910 | 376 | ||
911 | adapter->pool.fsf_req_abort = | 377 | adapter->pool.fsf_req_abort = |
912 | mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_ABORT_NR, | 378 | mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); |
913 | zfcp_data.fsf_req_qtcb_cache); | ||
914 | if (!adapter->pool.fsf_req_abort) | 379 | if (!adapter->pool.fsf_req_abort) |
915 | return -ENOMEM; | 380 | return -ENOMEM; |
916 | 381 | ||
917 | adapter->pool.fsf_req_status_read = | 382 | adapter->pool.fsf_req_status_read = |
918 | mempool_create_kmalloc_pool(ZFCP_POOL_STATUS_READ_NR, | 383 | mempool_create_kmalloc_pool(FSF_STATUS_READS_RECOM, |
919 | sizeof(struct zfcp_fsf_req)); | 384 | sizeof(struct zfcp_fsf_req)); |
920 | if (!adapter->pool.fsf_req_status_read) | 385 | if (!adapter->pool.fsf_req_status_read) |
921 | return -ENOMEM; | 386 | return -ENOMEM; |
922 | 387 | ||
923 | adapter->pool.data_status_read = | 388 | adapter->pool.data_status_read = |
924 | mempool_create_slab_pool(ZFCP_POOL_STATUS_READ_NR, | 389 | mempool_create_slab_pool(FSF_STATUS_READS_RECOM, |
925 | zfcp_data.sr_buffer_cache); | 390 | zfcp_data.sr_buffer_cache); |
926 | if (!adapter->pool.data_status_read) | 391 | if (!adapter->pool.data_status_read) |
927 | return -ENOMEM; | 392 | return -ENOMEM; |
928 | 393 | ||
929 | adapter->pool.data_gid_pn = | 394 | adapter->pool.data_gid_pn = |
930 | mempool_create_slab_pool(ZFCP_POOL_DATA_GID_PN_NR, | 395 | mempool_create_slab_pool(1, zfcp_data.gid_pn_cache); |
931 | zfcp_data.gid_pn_cache); | ||
932 | if (!adapter->pool.data_gid_pn) | 396 | if (!adapter->pool.data_gid_pn) |
933 | return -ENOMEM; | 397 | return -ENOMEM; |
934 | 398 | ||
935 | return 0; | 399 | return 0; |
936 | } | 400 | } |
937 | 401 | ||
938 | /** | 402 | static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) |
939 | * zfcp_free_low_mem_buffers - free memory pools of an adapter | ||
940 | * @adapter: pointer to zfcp_adapter for which memory pools should be freed | ||
941 | * locking: zfcp_data.config_sema must be held | ||
942 | */ | ||
943 | static void | ||
944 | zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) | ||
945 | { | 403 | { |
404 | /* zfcp_data.config_sema must be held */ | ||
946 | if (adapter->pool.fsf_req_erp) | 405 | if (adapter->pool.fsf_req_erp) |
947 | mempool_destroy(adapter->pool.fsf_req_erp); | 406 | mempool_destroy(adapter->pool.fsf_req_erp); |
948 | if (adapter->pool.fsf_req_scsi) | 407 | if (adapter->pool.fsf_req_scsi) |
@@ -962,20 +421,61 @@ static void zfcp_dummy_release(struct device *dev) | |||
962 | return; | 421 | return; |
963 | } | 422 | } |
964 | 423 | ||
965 | /* | 424 | /** |
425 | * zfcp_status_read_refill - refill the long running status_read_requests | ||
426 | * @adapter: ptr to struct zfcp_adapter for which the buffers should be refilled | ||
427 | * | ||
428 | * Returns: 0 on success, 1 otherwise | ||
429 | * | ||
430 | * if there are 16 or more status_read requests missing an adapter_reopen | ||
431 | * is triggered | ||
432 | */ | ||
433 | int zfcp_status_read_refill(struct zfcp_adapter *adapter) | ||
434 | { | ||
435 | while (atomic_read(&adapter->stat_miss) > 0) | ||
436 | if (zfcp_fsf_status_read(adapter)) { | ||
437 | if (atomic_read(&adapter->stat_miss) >= 16) { | ||
438 | zfcp_erp_adapter_reopen(adapter, 0, 103, NULL); | ||
439 | return 1; | ||
440 | } | ||
441 | break; | ||
442 | } else | ||
443 | atomic_dec(&adapter->stat_miss); | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static void _zfcp_status_read_scheduler(struct work_struct *work) | ||
448 | { | ||
449 | zfcp_status_read_refill(container_of(work, struct zfcp_adapter, | ||
450 | stat_work)); | ||
451 | } | ||
452 | |||
453 | static int zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) | ||
454 | { | ||
455 | struct zfcp_port *port; | ||
456 | |||
457 | port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, | ||
458 | ZFCP_DID_DIRECTORY_SERVICE); | ||
459 | if (IS_ERR(port)) | ||
460 | return PTR_ERR(port); | ||
461 | zfcp_port_put(port); | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | /** | ||
467 | * zfcp_adapter_enqueue - enqueue a new adapter to the list | ||
468 | * @ccw_device: pointer to the struct cc_device | ||
469 | * | ||
470 | * Returns: 0 if a new adapter was successfully enqueued | ||
471 | * -ENOMEM if alloc failed | ||
966 | * Enqueues an adapter at the end of the adapter list in the driver data. | 472 | * Enqueues an adapter at the end of the adapter list in the driver data. |
967 | * All adapter internal structures are set up. | 473 | * All adapter internal structures are set up. |
968 | * Proc-fs entries are also created. | 474 | * Proc-fs entries are also created. |
969 | * | ||
970 | * returns: 0 if a new adapter was successfully enqueued | ||
971 | * ZFCP_KNOWN if an adapter with this devno was already present | ||
972 | * -ENOMEM if alloc failed | ||
973 | * locks: config_sema must be held to serialise changes to the adapter list | 475 | * locks: config_sema must be held to serialise changes to the adapter list |
974 | */ | 476 | */ |
975 | struct zfcp_adapter * | 477 | int zfcp_adapter_enqueue(struct ccw_device *ccw_device) |
976 | zfcp_adapter_enqueue(struct ccw_device *ccw_device) | ||
977 | { | 478 | { |
978 | int retval = 0; | ||
979 | struct zfcp_adapter *adapter; | 479 | struct zfcp_adapter *adapter; |
980 | 480 | ||
981 | /* | 481 | /* |
@@ -983,85 +483,58 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
983 | * are protected by the config_sema, which must be held to get here | 483 | * are protected by the config_sema, which must be held to get here |
984 | */ | 484 | */ |
985 | 485 | ||
986 | /* try to allocate new adapter data structure (zeroed) */ | 486 | adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); |
987 | adapter = kzalloc(sizeof (struct zfcp_adapter), GFP_KERNEL); | 487 | if (!adapter) |
988 | if (!adapter) { | 488 | return -ENOMEM; |
989 | ZFCP_LOG_INFO("error: allocation of base adapter " | ||
990 | "structure failed\n"); | ||
991 | goto out; | ||
992 | } | ||
993 | 489 | ||
994 | ccw_device->handler = NULL; | 490 | ccw_device->handler = NULL; |
995 | |||
996 | /* save ccw_device pointer */ | ||
997 | adapter->ccw_device = ccw_device; | 491 | adapter->ccw_device = ccw_device; |
492 | atomic_set(&adapter->refcount, 0); | ||
998 | 493 | ||
999 | retval = zfcp_qdio_allocate_queues(adapter); | 494 | if (zfcp_qdio_allocate(adapter)) |
1000 | if (retval) | ||
1001 | goto queues_alloc_failed; | ||
1002 | |||
1003 | retval = zfcp_qdio_allocate(adapter); | ||
1004 | if (retval) | ||
1005 | goto qdio_allocate_failed; | 495 | goto qdio_allocate_failed; |
1006 | 496 | ||
1007 | retval = zfcp_allocate_low_mem_buffers(adapter); | 497 | if (zfcp_allocate_low_mem_buffers(adapter)) |
1008 | if (retval) { | ||
1009 | ZFCP_LOG_INFO("error: pool allocation failed\n"); | ||
1010 | goto failed_low_mem_buffers; | 498 | goto failed_low_mem_buffers; |
1011 | } | ||
1012 | 499 | ||
1013 | /* initialise reference count stuff */ | 500 | if (zfcp_reqlist_alloc(adapter)) |
1014 | atomic_set(&adapter->refcount, 0); | 501 | goto failed_low_mem_buffers; |
502 | |||
503 | if (zfcp_adapter_debug_register(adapter)) | ||
504 | goto debug_register_failed; | ||
505 | |||
1015 | init_waitqueue_head(&adapter->remove_wq); | 506 | init_waitqueue_head(&adapter->remove_wq); |
507 | init_waitqueue_head(&adapter->erp_thread_wqh); | ||
508 | init_waitqueue_head(&adapter->erp_done_wqh); | ||
1016 | 509 | ||
1017 | /* initialise list of ports */ | ||
1018 | INIT_LIST_HEAD(&adapter->port_list_head); | 510 | INIT_LIST_HEAD(&adapter->port_list_head); |
1019 | |||
1020 | /* initialise list of ports to be removed */ | ||
1021 | INIT_LIST_HEAD(&adapter->port_remove_lh); | 511 | INIT_LIST_HEAD(&adapter->port_remove_lh); |
512 | INIT_LIST_HEAD(&adapter->erp_ready_head); | ||
513 | INIT_LIST_HEAD(&adapter->erp_running_head); | ||
1022 | 514 | ||
1023 | /* initialize list of fsf requests */ | ||
1024 | spin_lock_init(&adapter->req_list_lock); | 515 | spin_lock_init(&adapter->req_list_lock); |
1025 | retval = zfcp_reqlist_alloc(adapter); | ||
1026 | if (retval) { | ||
1027 | ZFCP_LOG_INFO("request list initialization failed\n"); | ||
1028 | goto failed_low_mem_buffers; | ||
1029 | } | ||
1030 | |||
1031 | /* initialize debug locks */ | ||
1032 | 516 | ||
1033 | spin_lock_init(&adapter->hba_dbf_lock); | 517 | spin_lock_init(&adapter->hba_dbf_lock); |
1034 | spin_lock_init(&adapter->san_dbf_lock); | 518 | spin_lock_init(&adapter->san_dbf_lock); |
1035 | spin_lock_init(&adapter->scsi_dbf_lock); | 519 | spin_lock_init(&adapter->scsi_dbf_lock); |
1036 | spin_lock_init(&adapter->rec_dbf_lock); | 520 | spin_lock_init(&adapter->rec_dbf_lock); |
1037 | 521 | spin_lock_init(&adapter->req_q.lock); | |
1038 | retval = zfcp_adapter_debug_register(adapter); | ||
1039 | if (retval) | ||
1040 | goto debug_register_failed; | ||
1041 | |||
1042 | /* initialize error recovery stuff */ | ||
1043 | 522 | ||
1044 | rwlock_init(&adapter->erp_lock); | 523 | rwlock_init(&adapter->erp_lock); |
1045 | sema_init(&adapter->erp_ready_sem, 0); | ||
1046 | INIT_LIST_HEAD(&adapter->erp_ready_head); | ||
1047 | INIT_LIST_HEAD(&adapter->erp_running_head); | ||
1048 | |||
1049 | /* initialize abort lock */ | ||
1050 | rwlock_init(&adapter->abort_lock); | 524 | rwlock_init(&adapter->abort_lock); |
1051 | 525 | ||
1052 | /* initialise some erp stuff */ | 526 | sema_init(&adapter->erp_ready_sem, 0); |
1053 | init_waitqueue_head(&adapter->erp_thread_wqh); | ||
1054 | init_waitqueue_head(&adapter->erp_done_wqh); | ||
1055 | 527 | ||
1056 | /* initialize lock of associated request queue */ | 528 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); |
1057 | rwlock_init(&adapter->request_queue.queue_lock); | 529 | INIT_WORK(&adapter->scan_work, _zfcp_scan_ports_later); |
1058 | 530 | ||
1059 | /* mark adapter unusable as long as sysfs registration is not complete */ | 531 | /* mark adapter unusable as long as sysfs registration is not complete */ |
1060 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | 532 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); |
1061 | 533 | ||
1062 | dev_set_drvdata(&ccw_device->dev, adapter); | 534 | dev_set_drvdata(&ccw_device->dev, adapter); |
1063 | 535 | ||
1064 | if (zfcp_sysfs_adapter_create_files(&ccw_device->dev)) | 536 | if (sysfs_create_group(&ccw_device->dev.kobj, |
537 | &zfcp_sysfs_adapter_attrs)) | ||
1065 | goto sysfs_failed; | 538 | goto sysfs_failed; |
1066 | 539 | ||
1067 | adapter->generic_services.parent = &adapter->ccw_device->dev; | 540 | adapter->generic_services.parent = &adapter->ccw_device->dev; |
@@ -1072,7 +545,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
1072 | if (device_register(&adapter->generic_services)) | 545 | if (device_register(&adapter->generic_services)) |
1073 | goto generic_services_failed; | 546 | goto generic_services_failed; |
1074 | 547 | ||
1075 | /* put allocated adapter at list tail */ | ||
1076 | write_lock_irq(&zfcp_data.config_lock); | 548 | write_lock_irq(&zfcp_data.config_lock); |
1077 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | 549 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); |
1078 | list_add_tail(&adapter->list, &zfcp_data.adapter_list_head); | 550 | list_add_tail(&adapter->list, &zfcp_data.adapter_list_head); |
@@ -1080,57 +552,49 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
1080 | 552 | ||
1081 | zfcp_data.adapters++; | 553 | zfcp_data.adapters++; |
1082 | 554 | ||
1083 | goto out; | 555 | zfcp_nameserver_enqueue(adapter); |
556 | |||
557 | return 0; | ||
1084 | 558 | ||
1085 | generic_services_failed: | 559 | generic_services_failed: |
1086 | zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); | 560 | sysfs_remove_group(&ccw_device->dev.kobj, |
1087 | sysfs_failed: | 561 | &zfcp_sysfs_adapter_attrs); |
562 | sysfs_failed: | ||
1088 | zfcp_adapter_debug_unregister(adapter); | 563 | zfcp_adapter_debug_unregister(adapter); |
1089 | debug_register_failed: | 564 | debug_register_failed: |
1090 | dev_set_drvdata(&ccw_device->dev, NULL); | 565 | dev_set_drvdata(&ccw_device->dev, NULL); |
1091 | zfcp_reqlist_free(adapter); | 566 | kfree(adapter->req_list); |
1092 | failed_low_mem_buffers: | 567 | failed_low_mem_buffers: |
1093 | zfcp_free_low_mem_buffers(adapter); | 568 | zfcp_free_low_mem_buffers(adapter); |
1094 | if (qdio_free(ccw_device) != 0) | 569 | qdio_allocate_failed: |
1095 | ZFCP_LOG_NORMAL("bug: qdio_free for adapter %s failed\n", | 570 | zfcp_qdio_free(adapter); |
1096 | zfcp_get_busid_by_adapter(adapter)); | ||
1097 | qdio_allocate_failed: | ||
1098 | zfcp_qdio_free_queues(adapter); | ||
1099 | queues_alloc_failed: | ||
1100 | kfree(adapter); | 571 | kfree(adapter); |
1101 | adapter = NULL; | 572 | return -ENOMEM; |
1102 | out: | ||
1103 | return adapter; | ||
1104 | } | 573 | } |
1105 | 574 | ||
1106 | /* | 575 | /** |
1107 | * returns: 0 - struct zfcp_adapter data structure successfully removed | 576 | * zfcp_adapter_dequeue - remove the adapter from the resource list |
1108 | * !0 - struct zfcp_adapter data structure could not be removed | 577 | * @adapter: pointer to struct zfcp_adapter which should be removed |
1109 | * (e.g. still used) | ||
1110 | * locks: adapter list write lock is assumed to be held by caller | 578 | * locks: adapter list write lock is assumed to be held by caller |
1111 | */ | 579 | */ |
1112 | void | 580 | void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) |
1113 | zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | ||
1114 | { | 581 | { |
1115 | int retval = 0; | 582 | int retval = 0; |
1116 | unsigned long flags; | 583 | unsigned long flags; |
1117 | 584 | ||
585 | cancel_work_sync(&adapter->scan_work); | ||
586 | cancel_work_sync(&adapter->stat_work); | ||
1118 | zfcp_adapter_scsi_unregister(adapter); | 587 | zfcp_adapter_scsi_unregister(adapter); |
1119 | device_unregister(&adapter->generic_services); | 588 | device_unregister(&adapter->generic_services); |
1120 | zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); | 589 | sysfs_remove_group(&adapter->ccw_device->dev.kobj, |
590 | &zfcp_sysfs_adapter_attrs); | ||
1121 | dev_set_drvdata(&adapter->ccw_device->dev, NULL); | 591 | dev_set_drvdata(&adapter->ccw_device->dev, NULL); |
1122 | /* sanity check: no pending FSF requests */ | 592 | /* sanity check: no pending FSF requests */ |
1123 | spin_lock_irqsave(&adapter->req_list_lock, flags); | 593 | spin_lock_irqsave(&adapter->req_list_lock, flags); |
1124 | retval = zfcp_reqlist_isempty(adapter); | 594 | retval = zfcp_reqlist_isempty(adapter); |
1125 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); | 595 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); |
1126 | if (!retval) { | 596 | if (!retval) |
1127 | ZFCP_LOG_NORMAL("bug: adapter %s (%p) still in use, " | 597 | return; |
1128 | "%i requests outstanding\n", | ||
1129 | zfcp_get_busid_by_adapter(adapter), adapter, | ||
1130 | atomic_read(&adapter->reqs_active)); | ||
1131 | retval = -EBUSY; | ||
1132 | goto out; | ||
1133 | } | ||
1134 | 598 | ||
1135 | zfcp_adapter_debug_unregister(adapter); | 599 | zfcp_adapter_debug_unregister(adapter); |
1136 | 600 | ||
@@ -1142,26 +606,18 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | |||
1142 | /* decrease number of adapters in list */ | 606 | /* decrease number of adapters in list */ |
1143 | zfcp_data.adapters--; | 607 | zfcp_data.adapters--; |
1144 | 608 | ||
1145 | ZFCP_LOG_TRACE("adapter %s (%p) removed from list, " | 609 | zfcp_qdio_free(adapter); |
1146 | "%i adapters still in list\n", | ||
1147 | zfcp_get_busid_by_adapter(adapter), | ||
1148 | adapter, zfcp_data.adapters); | ||
1149 | |||
1150 | retval = qdio_free(adapter->ccw_device); | ||
1151 | if (retval) | ||
1152 | ZFCP_LOG_NORMAL("bug: qdio_free for adapter %s failed\n", | ||
1153 | zfcp_get_busid_by_adapter(adapter)); | ||
1154 | 610 | ||
1155 | zfcp_free_low_mem_buffers(adapter); | 611 | zfcp_free_low_mem_buffers(adapter); |
1156 | /* free memory of adapter data structure and queues */ | 612 | kfree(adapter->req_list); |
1157 | zfcp_qdio_free_queues(adapter); | ||
1158 | zfcp_reqlist_free(adapter); | ||
1159 | kfree(adapter->fc_stats); | 613 | kfree(adapter->fc_stats); |
1160 | kfree(adapter->stats_reset_data); | 614 | kfree(adapter->stats_reset_data); |
1161 | ZFCP_LOG_TRACE("freeing adapter structure\n"); | ||
1162 | kfree(adapter); | 615 | kfree(adapter); |
1163 | out: | 616 | } |
1164 | return; | 617 | |
618 | static void zfcp_sysfs_port_release(struct device *dev) | ||
619 | { | ||
620 | kfree(container_of(dev, struct zfcp_port, sysfs_device)); | ||
1165 | } | 621 | } |
1166 | 622 | ||
1167 | /** | 623 | /** |
@@ -1170,98 +626,90 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | |||
1170 | * @wwpn: WWPN of the remote port to be enqueued | 626 | * @wwpn: WWPN of the remote port to be enqueued |
1171 | * @status: initial status for the port | 627 | * @status: initial status for the port |
1172 | * @d_id: destination id of the remote port to be enqueued | 628 | * @d_id: destination id of the remote port to be enqueued |
1173 | * Return: pointer to enqueued port on success, NULL on error | 629 | * Returns: pointer to enqueued port on success, ERR_PTR on error |
1174 | * Locks: config_sema must be held to serialize changes to the port list | 630 | * Locks: config_sema must be held to serialize changes to the port list |
1175 | * | 631 | * |
1176 | * All port internal structures are set up and the sysfs entry is generated. | 632 | * All port internal structures are set up and the sysfs entry is generated. |
1177 | * d_id is used to enqueue ports with a well known address like the Directory | 633 | * d_id is used to enqueue ports with a well known address like the Directory |
1178 | * Service for nameserver lookup. | 634 | * Service for nameserver lookup. |
1179 | */ | 635 | */ |
1180 | struct zfcp_port * | 636 | struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, |
1181 | zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, | 637 | u32 status, u32 d_id) |
1182 | u32 d_id) | ||
1183 | { | 638 | { |
1184 | struct zfcp_port *port; | 639 | struct zfcp_port *port; |
1185 | int check_wwpn; | 640 | int retval; |
1186 | 641 | char *bus_id; | |
1187 | check_wwpn = !(status & ZFCP_STATUS_PORT_NO_WWPN); | ||
1188 | /* | ||
1189 | * check that there is no port with this WWPN already in list | ||
1190 | */ | ||
1191 | if (check_wwpn) { | ||
1192 | read_lock_irq(&zfcp_data.config_lock); | ||
1193 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | ||
1194 | read_unlock_irq(&zfcp_data.config_lock); | ||
1195 | if (port) | ||
1196 | return NULL; | ||
1197 | } | ||
1198 | 642 | ||
1199 | port = kzalloc(sizeof (struct zfcp_port), GFP_KERNEL); | 643 | port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); |
1200 | if (!port) | 644 | if (!port) |
1201 | return NULL; | 645 | return ERR_PTR(-ENOMEM); |
1202 | 646 | ||
1203 | /* initialise reference count stuff */ | ||
1204 | atomic_set(&port->refcount, 0); | ||
1205 | init_waitqueue_head(&port->remove_wq); | 647 | init_waitqueue_head(&port->remove_wq); |
1206 | 648 | ||
1207 | INIT_LIST_HEAD(&port->unit_list_head); | 649 | INIT_LIST_HEAD(&port->unit_list_head); |
1208 | INIT_LIST_HEAD(&port->unit_remove_lh); | 650 | INIT_LIST_HEAD(&port->unit_remove_lh); |
1209 | 651 | ||
1210 | port->adapter = adapter; | 652 | port->adapter = adapter; |
653 | port->d_id = d_id; | ||
654 | port->wwpn = wwpn; | ||
1211 | 655 | ||
1212 | if (check_wwpn) | 656 | /* mark port unusable as long as sysfs registration is not complete */ |
1213 | port->wwpn = wwpn; | 657 | atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); |
1214 | 658 | atomic_set(&port->refcount, 0); | |
1215 | atomic_set_mask(status, &port->status); | ||
1216 | 659 | ||
1217 | /* setup for sysfs registration */ | ||
1218 | if (status & ZFCP_STATUS_PORT_WKA) { | 660 | if (status & ZFCP_STATUS_PORT_WKA) { |
1219 | switch (d_id) { | 661 | switch (d_id) { |
1220 | case ZFCP_DID_DIRECTORY_SERVICE: | 662 | case ZFCP_DID_DIRECTORY_SERVICE: |
1221 | snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, | 663 | bus_id = "directory"; |
1222 | "directory"); | ||
1223 | break; | 664 | break; |
1224 | case ZFCP_DID_MANAGEMENT_SERVICE: | 665 | case ZFCP_DID_MANAGEMENT_SERVICE: |
1225 | snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, | 666 | bus_id = "management"; |
1226 | "management"); | ||
1227 | break; | 667 | break; |
1228 | case ZFCP_DID_KEY_DISTRIBUTION_SERVICE: | 668 | case ZFCP_DID_KEY_DISTRIBUTION_SERVICE: |
1229 | snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, | 669 | bus_id = "key_distribution"; |
1230 | "key_distribution"); | ||
1231 | break; | 670 | break; |
1232 | case ZFCP_DID_ALIAS_SERVICE: | 671 | case ZFCP_DID_ALIAS_SERVICE: |
1233 | snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, | 672 | bus_id = "alias"; |
1234 | "alias"); | ||
1235 | break; | 673 | break; |
1236 | case ZFCP_DID_TIME_SERVICE: | 674 | case ZFCP_DID_TIME_SERVICE: |
1237 | snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, | 675 | bus_id = "time"; |
1238 | "time"); | ||
1239 | break; | 676 | break; |
1240 | default: | 677 | default: |
1241 | kfree(port); | 678 | kfree(port); |
1242 | return NULL; | 679 | return ERR_PTR(-EINVAL); |
1243 | } | 680 | } |
1244 | port->d_id = d_id; | 681 | snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "%s", bus_id); |
1245 | port->sysfs_device.parent = &adapter->generic_services; | 682 | port->sysfs_device.parent = &adapter->generic_services; |
1246 | } else { | 683 | } else { |
1247 | snprintf(port->sysfs_device.bus_id, | 684 | snprintf(port->sysfs_device.bus_id, |
1248 | BUS_ID_SIZE, "0x%016llx", wwpn); | 685 | BUS_ID_SIZE, "0x%016llx", wwpn); |
1249 | port->sysfs_device.parent = &adapter->ccw_device->dev; | 686 | port->sysfs_device.parent = &adapter->ccw_device->dev; |
1250 | } | 687 | } |
688 | |||
1251 | port->sysfs_device.release = zfcp_sysfs_port_release; | 689 | port->sysfs_device.release = zfcp_sysfs_port_release; |
1252 | dev_set_drvdata(&port->sysfs_device, port); | 690 | dev_set_drvdata(&port->sysfs_device, port); |
1253 | 691 | ||
1254 | /* mark port unusable as long as sysfs registration is not complete */ | 692 | read_lock_irq(&zfcp_data.config_lock); |
1255 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | 693 | if (!(status & ZFCP_STATUS_PORT_NO_WWPN)) |
694 | if (zfcp_get_port_by_wwpn(adapter, wwpn)) { | ||
695 | read_unlock_irq(&zfcp_data.config_lock); | ||
696 | goto err_out_free; | ||
697 | } | ||
698 | read_unlock_irq(&zfcp_data.config_lock); | ||
1256 | 699 | ||
1257 | if (device_register(&port->sysfs_device)) { | 700 | if (device_register(&port->sysfs_device)) |
1258 | kfree(port); | 701 | goto err_out_free; |
1259 | return NULL; | 702 | |
1260 | } | 703 | if (status & ZFCP_STATUS_PORT_WKA) |
704 | retval = sysfs_create_group(&port->sysfs_device.kobj, | ||
705 | &zfcp_sysfs_ns_port_attrs); | ||
706 | else | ||
707 | retval = sysfs_create_group(&port->sysfs_device.kobj, | ||
708 | &zfcp_sysfs_port_attrs); | ||
1261 | 709 | ||
1262 | if (zfcp_sysfs_port_create_files(&port->sysfs_device, status)) { | 710 | if (retval) { |
1263 | device_unregister(&port->sysfs_device); | 711 | device_unregister(&port->sysfs_device); |
1264 | return NULL; | 712 | goto err_out; |
1265 | } | 713 | } |
1266 | 714 | ||
1267 | zfcp_port_get(port); | 715 | zfcp_port_get(port); |
@@ -1274,15 +722,23 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, | |||
1274 | if (!adapter->nameserver_port) | 722 | if (!adapter->nameserver_port) |
1275 | adapter->nameserver_port = port; | 723 | adapter->nameserver_port = port; |
1276 | adapter->ports++; | 724 | adapter->ports++; |
725 | |||
1277 | write_unlock_irq(&zfcp_data.config_lock); | 726 | write_unlock_irq(&zfcp_data.config_lock); |
1278 | 727 | ||
1279 | zfcp_adapter_get(adapter); | 728 | zfcp_adapter_get(adapter); |
1280 | |||
1281 | return port; | 729 | return port; |
730 | |||
731 | err_out_free: | ||
732 | kfree(port); | ||
733 | err_out: | ||
734 | return ERR_PTR(-EINVAL); | ||
1282 | } | 735 | } |
1283 | 736 | ||
1284 | void | 737 | /** |
1285 | zfcp_port_dequeue(struct zfcp_port *port) | 738 | * zfcp_port_dequeue - dequeues a port from the port list of the adapter |
739 | * @port: pointer to struct zfcp_port which should be removed | ||
740 | */ | ||
741 | void zfcp_port_dequeue(struct zfcp_port *port) | ||
1286 | { | 742 | { |
1287 | zfcp_port_wait(port); | 743 | zfcp_port_wait(port); |
1288 | write_lock_irq(&zfcp_data.config_lock); | 744 | write_lock_irq(&zfcp_data.config_lock); |
@@ -1293,546 +749,53 @@ zfcp_port_dequeue(struct zfcp_port *port) | |||
1293 | fc_remote_port_delete(port->rport); | 749 | fc_remote_port_delete(port->rport); |
1294 | port->rport = NULL; | 750 | port->rport = NULL; |
1295 | zfcp_adapter_put(port->adapter); | 751 | zfcp_adapter_put(port->adapter); |
1296 | zfcp_sysfs_port_remove_files(&port->sysfs_device, | 752 | if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA) |
1297 | atomic_read(&port->status)); | 753 | sysfs_remove_group(&port->sysfs_device.kobj, |
1298 | device_unregister(&port->sysfs_device); | 754 | &zfcp_sysfs_ns_port_attrs); |
1299 | } | ||
1300 | |||
1301 | /* Enqueues a nameserver port */ | ||
1302 | int | ||
1303 | zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) | ||
1304 | { | ||
1305 | struct zfcp_port *port; | ||
1306 | |||
1307 | port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, | ||
1308 | ZFCP_DID_DIRECTORY_SERVICE); | ||
1309 | if (!port) { | ||
1310 | ZFCP_LOG_INFO("error: enqueue of nameserver port for " | ||
1311 | "adapter %s failed\n", | ||
1312 | zfcp_get_busid_by_adapter(adapter)); | ||
1313 | return -ENXIO; | ||
1314 | } | ||
1315 | zfcp_port_put(port); | ||
1316 | |||
1317 | return 0; | ||
1318 | } | ||
1319 | |||
1320 | #undef ZFCP_LOG_AREA | ||
1321 | |||
1322 | /****************************************************************/ | ||
1323 | /******* Fibre Channel Standard related Functions **************/ | ||
1324 | /****************************************************************/ | ||
1325 | |||
1326 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_FC | ||
1327 | |||
1328 | static void zfcp_fsf_incoming_els_rscn(struct zfcp_fsf_req *fsf_req) | ||
1329 | { | ||
1330 | struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; | ||
1331 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
1332 | struct fcp_rscn_head *fcp_rscn_head; | ||
1333 | struct fcp_rscn_element *fcp_rscn_element; | ||
1334 | struct zfcp_port *port; | ||
1335 | u16 i; | ||
1336 | u16 no_entries; | ||
1337 | u32 range_mask; | ||
1338 | unsigned long flags; | ||
1339 | |||
1340 | fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload; | ||
1341 | fcp_rscn_element = (struct fcp_rscn_element *) status_buffer->payload; | ||
1342 | |||
1343 | /* see FC-FS */ | ||
1344 | no_entries = (fcp_rscn_head->payload_len / 4); | ||
1345 | |||
1346 | for (i = 1; i < no_entries; i++) { | ||
1347 | /* skip head and start with 1st element */ | ||
1348 | fcp_rscn_element++; | ||
1349 | switch (fcp_rscn_element->addr_format) { | ||
1350 | case ZFCP_PORT_ADDRESS: | ||
1351 | range_mask = ZFCP_PORTS_RANGE_PORT; | ||
1352 | break; | ||
1353 | case ZFCP_AREA_ADDRESS: | ||
1354 | range_mask = ZFCP_PORTS_RANGE_AREA; | ||
1355 | break; | ||
1356 | case ZFCP_DOMAIN_ADDRESS: | ||
1357 | range_mask = ZFCP_PORTS_RANGE_DOMAIN; | ||
1358 | break; | ||
1359 | case ZFCP_FABRIC_ADDRESS: | ||
1360 | range_mask = ZFCP_PORTS_RANGE_FABRIC; | ||
1361 | break; | ||
1362 | default: | ||
1363 | ZFCP_LOG_INFO("incoming RSCN with unknown " | ||
1364 | "address format\n"); | ||
1365 | continue; | ||
1366 | } | ||
1367 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1368 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
1369 | if (atomic_test_mask | ||
1370 | (ZFCP_STATUS_PORT_WKA, &port->status)) | ||
1371 | continue; | ||
1372 | /* Do we know this port? If not skip it. */ | ||
1373 | if (!atomic_test_mask | ||
1374 | (ZFCP_STATUS_PORT_DID_DID, &port->status)) { | ||
1375 | ZFCP_LOG_INFO("incoming RSCN, trying to open " | ||
1376 | "port 0x%016Lx\n", port->wwpn); | ||
1377 | zfcp_erp_port_reopen(port, | ||
1378 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
1379 | 82, fsf_req); | ||
1380 | continue; | ||
1381 | } | ||
1382 | |||
1383 | /* | ||
1384 | * FIXME: race: d_id might being invalidated | ||
1385 | * (...DID_DID reset) | ||
1386 | */ | ||
1387 | if ((port->d_id & range_mask) | ||
1388 | == (fcp_rscn_element->nport_did & range_mask)) { | ||
1389 | ZFCP_LOG_TRACE("reopen did 0x%08x\n", | ||
1390 | fcp_rscn_element->nport_did); | ||
1391 | /* | ||
1392 | * Unfortunately, an RSCN does not specify the | ||
1393 | * type of change a target underwent. We assume | ||
1394 | * that it makes sense to reopen the link. | ||
1395 | * FIXME: Shall we try to find out more about | ||
1396 | * the target and link state before closing it? | ||
1397 | * How to accomplish this? (nameserver?) | ||
1398 | * Where would such code be put in? | ||
1399 | * (inside or outside erp) | ||
1400 | */ | ||
1401 | ZFCP_LOG_INFO("incoming RSCN, trying to open " | ||
1402 | "port 0x%016Lx\n", port->wwpn); | ||
1403 | zfcp_test_link(port); | ||
1404 | } | ||
1405 | } | ||
1406 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1407 | } | ||
1408 | } | ||
1409 | |||
1410 | static void zfcp_fsf_incoming_els_plogi(struct zfcp_fsf_req *fsf_req) | ||
1411 | { | ||
1412 | struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; | ||
1413 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
1414 | struct fsf_plogi *els_plogi; | ||
1415 | struct zfcp_port *port; | ||
1416 | unsigned long flags; | ||
1417 | |||
1418 | els_plogi = (struct fsf_plogi *) status_buffer->payload; | ||
1419 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1420 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
1421 | if (port->wwpn == (*(wwn_t *) &els_plogi->serv_param.wwpn)) | ||
1422 | break; | ||
1423 | } | ||
1424 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1425 | |||
1426 | if (!port || (port->wwpn != (*(wwn_t *) &els_plogi->serv_param.wwpn))) { | ||
1427 | ZFCP_LOG_DEBUG("ignored incoming PLOGI for nonexisting port " | ||
1428 | "with d_id 0x%06x on adapter %s\n", | ||
1429 | status_buffer->d_id, | ||
1430 | zfcp_get_busid_by_adapter(adapter)); | ||
1431 | } else { | ||
1432 | zfcp_erp_port_forced_reopen(port, 0, 83, fsf_req); | ||
1433 | } | ||
1434 | } | ||
1435 | |||
1436 | static void zfcp_fsf_incoming_els_logo(struct zfcp_fsf_req *fsf_req) | ||
1437 | { | ||
1438 | struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; | ||
1439 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
1440 | struct fcp_logo *els_logo = (struct fcp_logo *) status_buffer->payload; | ||
1441 | struct zfcp_port *port; | ||
1442 | unsigned long flags; | ||
1443 | |||
1444 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1445 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
1446 | if (port->wwpn == els_logo->nport_wwpn) | ||
1447 | break; | ||
1448 | } | ||
1449 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1450 | |||
1451 | if (!port || (port->wwpn != els_logo->nport_wwpn)) { | ||
1452 | ZFCP_LOG_DEBUG("ignored incoming LOGO for nonexisting port " | ||
1453 | "with d_id 0x%06x on adapter %s\n", | ||
1454 | status_buffer->d_id, | ||
1455 | zfcp_get_busid_by_adapter(adapter)); | ||
1456 | } else { | ||
1457 | zfcp_erp_port_forced_reopen(port, 0, 84, fsf_req); | ||
1458 | } | ||
1459 | } | ||
1460 | |||
1461 | static void | ||
1462 | zfcp_fsf_incoming_els_unknown(struct zfcp_adapter *adapter, | ||
1463 | struct fsf_status_read_buffer *status_buffer) | ||
1464 | { | ||
1465 | ZFCP_LOG_NORMAL("warning: unknown incoming ELS 0x%08x " | ||
1466 | "for adapter %s\n", *(u32 *) (status_buffer->payload), | ||
1467 | zfcp_get_busid_by_adapter(adapter)); | ||
1468 | |||
1469 | } | ||
1470 | |||
1471 | void | ||
1472 | zfcp_fsf_incoming_els(struct zfcp_fsf_req *fsf_req) | ||
1473 | { | ||
1474 | struct fsf_status_read_buffer *status_buffer; | ||
1475 | u32 els_type; | ||
1476 | struct zfcp_adapter *adapter; | ||
1477 | |||
1478 | status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; | ||
1479 | els_type = *(u32 *) (status_buffer->payload); | ||
1480 | adapter = fsf_req->adapter; | ||
1481 | |||
1482 | zfcp_san_dbf_event_incoming_els(fsf_req); | ||
1483 | if (els_type == LS_PLOGI) | ||
1484 | zfcp_fsf_incoming_els_plogi(fsf_req); | ||
1485 | else if (els_type == LS_LOGO) | ||
1486 | zfcp_fsf_incoming_els_logo(fsf_req); | ||
1487 | else if ((els_type & 0xffff0000) == LS_RSCN) | ||
1488 | /* we are only concerned with the command, not the length */ | ||
1489 | zfcp_fsf_incoming_els_rscn(fsf_req); | ||
1490 | else | ||
1491 | zfcp_fsf_incoming_els_unknown(adapter, status_buffer); | ||
1492 | } | ||
1493 | |||
1494 | |||
1495 | /** | ||
1496 | * zfcp_gid_pn_buffers_alloc - allocate buffers for GID_PN nameserver request | ||
1497 | * @gid_pn: pointer to return pointer to struct zfcp_gid_pn_data | ||
1498 | * @pool: pointer to mempool_t if non-null memory pool is used for allocation | ||
1499 | */ | ||
1500 | static int | ||
1501 | zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool) | ||
1502 | { | ||
1503 | struct zfcp_gid_pn_data *data; | ||
1504 | |||
1505 | if (pool != NULL) { | ||
1506 | data = mempool_alloc(pool, GFP_ATOMIC); | ||
1507 | if (likely(data != NULL)) { | ||
1508 | data->ct.pool = pool; | ||
1509 | } | ||
1510 | } else { | ||
1511 | data = kmem_cache_alloc(zfcp_data.gid_pn_cache, GFP_ATOMIC); | ||
1512 | } | ||
1513 | |||
1514 | if (NULL == data) | ||
1515 | return -ENOMEM; | ||
1516 | |||
1517 | memset(data, 0, sizeof(*data)); | ||
1518 | sg_init_table(&data->req , 1); | ||
1519 | sg_init_table(&data->resp , 1); | ||
1520 | data->ct.req = &data->req; | ||
1521 | data->ct.resp = &data->resp; | ||
1522 | data->ct.req_count = data->ct.resp_count = 1; | ||
1523 | zfcp_address_to_sg(&data->ct_iu_req, &data->req, sizeof(struct ct_iu_gid_pn_req)); | ||
1524 | zfcp_address_to_sg(&data->ct_iu_resp, &data->resp, sizeof(struct ct_iu_gid_pn_resp)); | ||
1525 | |||
1526 | *gid_pn = data; | ||
1527 | return 0; | ||
1528 | } | ||
1529 | |||
1530 | /** | ||
1531 | * zfcp_gid_pn_buffers_free - free buffers for GID_PN nameserver request | ||
1532 | * @gid_pn: pointer to struct zfcp_gid_pn_data which has to be freed | ||
1533 | */ | ||
1534 | static void zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn) | ||
1535 | { | ||
1536 | if (gid_pn->ct.pool) | ||
1537 | mempool_free(gid_pn, gid_pn->ct.pool); | ||
1538 | else | 755 | else |
1539 | kmem_cache_free(zfcp_data.gid_pn_cache, gid_pn); | 756 | sysfs_remove_group(&port->sysfs_device.kobj, |
1540 | } | 757 | &zfcp_sysfs_port_attrs); |
1541 | 758 | device_unregister(&port->sysfs_device); | |
1542 | /** | ||
1543 | * zfcp_ns_gid_pn_request - initiate GID_PN nameserver request | ||
1544 | * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed | ||
1545 | */ | ||
1546 | int | ||
1547 | zfcp_ns_gid_pn_request(struct zfcp_erp_action *erp_action) | ||
1548 | { | ||
1549 | int ret; | ||
1550 | struct ct_iu_gid_pn_req *ct_iu_req; | ||
1551 | struct zfcp_gid_pn_data *gid_pn; | ||
1552 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1553 | |||
1554 | ret = zfcp_gid_pn_buffers_alloc(&gid_pn, adapter->pool.data_gid_pn); | ||
1555 | if (ret < 0) { | ||
1556 | ZFCP_LOG_INFO("error: buffer allocation for gid_pn nameserver " | ||
1557 | "request failed for adapter %s\n", | ||
1558 | zfcp_get_busid_by_adapter(adapter)); | ||
1559 | goto out; | ||
1560 | } | ||
1561 | |||
1562 | /* setup nameserver request */ | ||
1563 | ct_iu_req = zfcp_sg_to_address(gid_pn->ct.req); | ||
1564 | ct_iu_req->header.revision = ZFCP_CT_REVISION; | ||
1565 | ct_iu_req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; | ||
1566 | ct_iu_req->header.gs_subtype = ZFCP_CT_NAME_SERVER; | ||
1567 | ct_iu_req->header.options = ZFCP_CT_SYNCHRONOUS; | ||
1568 | ct_iu_req->header.cmd_rsp_code = ZFCP_CT_GID_PN; | ||
1569 | ct_iu_req->header.max_res_size = ZFCP_CT_MAX_SIZE; | ||
1570 | ct_iu_req->wwpn = erp_action->port->wwpn; | ||
1571 | |||
1572 | /* setup parameters for send generic command */ | ||
1573 | gid_pn->ct.port = adapter->nameserver_port; | ||
1574 | gid_pn->ct.handler = zfcp_ns_gid_pn_handler; | ||
1575 | gid_pn->ct.handler_data = (unsigned long) gid_pn; | ||
1576 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; | ||
1577 | gid_pn->port = erp_action->port; | ||
1578 | |||
1579 | ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp, | ||
1580 | erp_action); | ||
1581 | if (ret) { | ||
1582 | ZFCP_LOG_INFO("error: initiation of gid_pn nameserver request " | ||
1583 | "failed for adapter %s\n", | ||
1584 | zfcp_get_busid_by_adapter(adapter)); | ||
1585 | |||
1586 | zfcp_gid_pn_buffers_free(gid_pn); | ||
1587 | } | ||
1588 | |||
1589 | out: | ||
1590 | return ret; | ||
1591 | } | ||
1592 | |||
1593 | /** | ||
1594 | * zfcp_ns_gid_pn_handler - handler for GID_PN nameserver request | ||
1595 | * @data: unsigned long, contains pointer to struct zfcp_gid_pn_data | ||
1596 | */ | ||
1597 | static void zfcp_ns_gid_pn_handler(unsigned long data) | ||
1598 | { | ||
1599 | struct zfcp_port *port; | ||
1600 | struct zfcp_send_ct *ct; | ||
1601 | struct ct_iu_gid_pn_req *ct_iu_req; | ||
1602 | struct ct_iu_gid_pn_resp *ct_iu_resp; | ||
1603 | struct zfcp_gid_pn_data *gid_pn; | ||
1604 | |||
1605 | |||
1606 | gid_pn = (struct zfcp_gid_pn_data *) data; | ||
1607 | port = gid_pn->port; | ||
1608 | ct = &gid_pn->ct; | ||
1609 | ct_iu_req = zfcp_sg_to_address(ct->req); | ||
1610 | ct_iu_resp = zfcp_sg_to_address(ct->resp); | ||
1611 | |||
1612 | if (ct->status != 0) | ||
1613 | goto failed; | ||
1614 | |||
1615 | if (zfcp_check_ct_response(&ct_iu_resp->header)) { | ||
1616 | /* FIXME: do we need some specific erp entry points */ | ||
1617 | atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); | ||
1618 | goto failed; | ||
1619 | } | ||
1620 | /* paranoia */ | ||
1621 | if (ct_iu_req->wwpn != port->wwpn) { | ||
1622 | ZFCP_LOG_NORMAL("bug: wwpn 0x%016Lx returned by nameserver " | ||
1623 | "lookup does not match expected wwpn 0x%016Lx " | ||
1624 | "for adapter %s\n", ct_iu_req->wwpn, port->wwpn, | ||
1625 | zfcp_get_busid_by_port(port)); | ||
1626 | goto mismatch; | ||
1627 | } | ||
1628 | |||
1629 | /* looks like a valid d_id */ | ||
1630 | port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; | ||
1631 | atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); | ||
1632 | ZFCP_LOG_DEBUG("adapter %s: wwpn=0x%016Lx ---> d_id=0x%06x\n", | ||
1633 | zfcp_get_busid_by_port(port), port->wwpn, port->d_id); | ||
1634 | goto out; | ||
1635 | |||
1636 | mismatch: | ||
1637 | ZFCP_LOG_DEBUG("CT IUs do not match:\n"); | ||
1638 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_req, | ||
1639 | sizeof(struct ct_iu_gid_pn_req)); | ||
1640 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_resp, | ||
1641 | sizeof(struct ct_iu_gid_pn_resp)); | ||
1642 | |||
1643 | failed: | ||
1644 | ZFCP_LOG_NORMAL("warning: failed gid_pn nameserver request for wwpn " | ||
1645 | "0x%016Lx for adapter %s\n", | ||
1646 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
1647 | out: | ||
1648 | zfcp_gid_pn_buffers_free(gid_pn); | ||
1649 | return; | ||
1650 | } | 759 | } |
1651 | 760 | ||
1652 | /* reject CT_IU reason codes acc. to FC-GS-4 */ | ||
1653 | static const struct zfcp_rc_entry zfcp_ct_rc[] = { | ||
1654 | {0x01, "invalid command code"}, | ||
1655 | {0x02, "invalid version level"}, | ||
1656 | {0x03, "logical error"}, | ||
1657 | {0x04, "invalid CT_IU size"}, | ||
1658 | {0x05, "logical busy"}, | ||
1659 | {0x07, "protocol error"}, | ||
1660 | {0x09, "unable to perform command request"}, | ||
1661 | {0x0b, "command not supported"}, | ||
1662 | {0x0d, "server not available"}, | ||
1663 | {0x0e, "session could not be established"}, | ||
1664 | {0xff, "vendor specific error"}, | ||
1665 | {0, NULL}, | ||
1666 | }; | ||
1667 | |||
1668 | /* LS_RJT reason codes acc. to FC-FS */ | ||
1669 | static const struct zfcp_rc_entry zfcp_ls_rjt_rc[] = { | ||
1670 | {0x01, "invalid LS_Command code"}, | ||
1671 | {0x03, "logical error"}, | ||
1672 | {0x05, "logical busy"}, | ||
1673 | {0x07, "protocol error"}, | ||
1674 | {0x09, "unable to perform command request"}, | ||
1675 | {0x0b, "command not supported"}, | ||
1676 | {0x0e, "command already in progress"}, | ||
1677 | {0xff, "vendor specific error"}, | ||
1678 | {0, NULL}, | ||
1679 | }; | ||
1680 | |||
1681 | /* reject reason codes according to FC-PH/FC-FS */ | ||
1682 | static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = { | ||
1683 | {0x01, "invalid D_ID"}, | ||
1684 | {0x02, "invalid S_ID"}, | ||
1685 | {0x03, "Nx_Port not available, temporary"}, | ||
1686 | {0x04, "Nx_Port not available, permament"}, | ||
1687 | {0x05, "class not supported"}, | ||
1688 | {0x06, "delimiter usage error"}, | ||
1689 | {0x07, "TYPE not supported"}, | ||
1690 | {0x08, "invalid Link_Control"}, | ||
1691 | {0x09, "invalid R_CTL field"}, | ||
1692 | {0x0a, "invalid F_CTL field"}, | ||
1693 | {0x0b, "invalid OX_ID"}, | ||
1694 | {0x0c, "invalid RX_ID"}, | ||
1695 | {0x0d, "invalid SEQ_ID"}, | ||
1696 | {0x0e, "invalid DF_CTL"}, | ||
1697 | {0x0f, "invalid SEQ_CNT"}, | ||
1698 | {0x10, "invalid parameter field"}, | ||
1699 | {0x11, "exchange error"}, | ||
1700 | {0x12, "protocol error"}, | ||
1701 | {0x13, "incorrect length"}, | ||
1702 | {0x14, "unsupported ACK"}, | ||
1703 | {0x15, "class of service not supported by entity at FFFFFE"}, | ||
1704 | {0x16, "login required"}, | ||
1705 | {0x17, "excessive sequences attempted"}, | ||
1706 | {0x18, "unable to establish exchange"}, | ||
1707 | {0x1a, "fabric path not available"}, | ||
1708 | {0x1b, "invalid VC_ID (class 4)"}, | ||
1709 | {0x1c, "invalid CS_CTL field"}, | ||
1710 | {0x1d, "insufficient resources for VC (class 4)"}, | ||
1711 | {0x1f, "invalid class of service"}, | ||
1712 | {0x20, "preemption request rejected"}, | ||
1713 | {0x21, "preemption not enabled"}, | ||
1714 | {0x22, "multicast error"}, | ||
1715 | {0x23, "multicast error terminate"}, | ||
1716 | {0x24, "process login required"}, | ||
1717 | {0xff, "vendor specific reject"}, | ||
1718 | {0, NULL}, | ||
1719 | }; | ||
1720 | |||
1721 | /** | 761 | /** |
1722 | * zfcp_rc_description - return description for given reaon code | 762 | * zfcp_sg_free_table - free memory used by scatterlists |
1723 | * @code: reason code | 763 | * @sg: pointer to scatterlist |
1724 | * @rc_table: table of reason codes and descriptions | 764 | * @count: number of scatterlist which are to be free'ed |
765 | * the scatterlist are expected to reference pages always | ||
1725 | */ | 766 | */ |
1726 | static const char * | 767 | void zfcp_sg_free_table(struct scatterlist *sg, int count) |
1727 | zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table) | ||
1728 | { | 768 | { |
1729 | const char *descr = "unknown reason code"; | 769 | int i; |
1730 | 770 | ||
1731 | do { | 771 | for (i = 0; i < count; i++, sg++) |
1732 | if (code == rc_table->code) { | 772 | if (sg) |
1733 | descr = rc_table->description; | 773 | free_page((unsigned long) sg_virt(sg)); |
774 | else | ||
1734 | break; | 775 | break; |
1735 | } | ||
1736 | rc_table++; | ||
1737 | } while (rc_table->code && rc_table->description); | ||
1738 | |||
1739 | return descr; | ||
1740 | } | 776 | } |
1741 | 777 | ||
1742 | /** | 778 | /** |
1743 | * zfcp_check_ct_response - evaluate reason code for CT_IU | 779 | * zfcp_sg_setup_table - init scatterlist and allocate, assign buffers |
1744 | * @rjt: response payload to an CT_IU request | 780 | * @sg: pointer to struct scatterlist |
1745 | * Return: 0 for accept CT_IU, 1 for reject CT_IU or invlid response code | 781 | * @count: number of scatterlists which should be assigned with buffers |
782 | * of size page | ||
783 | * | ||
784 | * Returns: 0 on success, -ENOMEM otherwise | ||
1746 | */ | 785 | */ |
1747 | int | 786 | int zfcp_sg_setup_table(struct scatterlist *sg, int count) |
1748 | zfcp_check_ct_response(struct ct_hdr *rjt) | ||
1749 | { | 787 | { |
1750 | if (rjt->cmd_rsp_code == ZFCP_CT_ACCEPT) | 788 | void *addr; |
1751 | return 0; | 789 | int i; |
1752 | 790 | ||
1753 | if (rjt->cmd_rsp_code != ZFCP_CT_REJECT) { | 791 | sg_init_table(sg, count); |
1754 | ZFCP_LOG_NORMAL("error: invalid Generic Service command/" | 792 | for (i = 0; i < count; i++, sg++) { |
1755 | "response code (0x%04hx)\n", | 793 | addr = (void *) get_zeroed_page(GFP_KERNEL); |
1756 | rjt->cmd_rsp_code); | 794 | if (!addr) { |
1757 | return 1; | 795 | zfcp_sg_free_table(sg, i); |
796 | return -ENOMEM; | ||
797 | } | ||
798 | sg_set_buf(sg, addr, PAGE_SIZE); | ||
1758 | } | 799 | } |
1759 | 800 | return 0; | |
1760 | ZFCP_LOG_INFO("Generic Service command rejected\n"); | ||
1761 | ZFCP_LOG_INFO("%s (0x%02x, 0x%02x, 0x%02x)\n", | ||
1762 | zfcp_rc_description(rjt->reason_code, zfcp_ct_rc), | ||
1763 | (u32) rjt->reason_code, (u32) rjt->reason_code_expl, | ||
1764 | (u32) rjt->vendor_unique); | ||
1765 | |||
1766 | return 1; | ||
1767 | } | ||
1768 | |||
1769 | /** | ||
1770 | * zfcp_print_els_rjt - print reject parameter and description for ELS reject | ||
1771 | * @rjt_par: reject parameter acc. to FC-PH/FC-FS | ||
1772 | * @rc_table: table of reason codes and descriptions | ||
1773 | */ | ||
1774 | static void | ||
1775 | zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par, | ||
1776 | const struct zfcp_rc_entry *rc_table) | ||
1777 | { | ||
1778 | ZFCP_LOG_INFO("%s (%02x %02x %02x %02x)\n", | ||
1779 | zfcp_rc_description(rjt_par->reason_code, rc_table), | ||
1780 | (u32) rjt_par->action, (u32) rjt_par->reason_code, | ||
1781 | (u32) rjt_par->reason_expl, (u32) rjt_par->vendor_unique); | ||
1782 | } | ||
1783 | |||
1784 | /** | ||
1785 | * zfcp_fsf_handle_els_rjt - evaluate status qualifier/reason code on ELS reject | ||
1786 | * @sq: status qualifier word | ||
1787 | * @rjt_par: reject parameter as described in FC-PH and FC-FS | ||
1788 | * Return: -EROMTEIO for LS_RJT, -EREMCHG for invalid D_ID, -EIO else | ||
1789 | */ | ||
1790 | int | ||
1791 | zfcp_handle_els_rjt(u32 sq, struct zfcp_ls_rjt_par *rjt_par) | ||
1792 | { | ||
1793 | int ret = -EIO; | ||
1794 | |||
1795 | if (sq == FSF_IOSTAT_NPORT_RJT) { | ||
1796 | ZFCP_LOG_INFO("ELS rejected (P_RJT)\n"); | ||
1797 | zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); | ||
1798 | /* invalid d_id */ | ||
1799 | if (rjt_par->reason_code == 0x01) | ||
1800 | ret = -EREMCHG; | ||
1801 | } else if (sq == FSF_IOSTAT_FABRIC_RJT) { | ||
1802 | ZFCP_LOG_INFO("ELS rejected (F_RJT)\n"); | ||
1803 | zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); | ||
1804 | /* invalid d_id */ | ||
1805 | if (rjt_par->reason_code == 0x01) | ||
1806 | ret = -EREMCHG; | ||
1807 | } else if (sq == FSF_IOSTAT_LS_RJT) { | ||
1808 | ZFCP_LOG_INFO("ELS rejected (LS_RJT)\n"); | ||
1809 | zfcp_print_els_rjt(rjt_par, zfcp_ls_rjt_rc); | ||
1810 | ret = -EREMOTEIO; | ||
1811 | } else | ||
1812 | ZFCP_LOG_INFO("unexpected SQ: 0x%02x\n", sq); | ||
1813 | |||
1814 | return ret; | ||
1815 | } | ||
1816 | |||
1817 | /** | ||
1818 | * zfcp_plogi_evaluate - evaluate PLOGI playload and copy important fields | ||
1819 | * into zfcp_port structure | ||
1820 | * @port: zfcp_port structure | ||
1821 | * @plogi: plogi payload | ||
1822 | */ | ||
1823 | void | ||
1824 | zfcp_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi) | ||
1825 | { | ||
1826 | port->maxframe_size = plogi->serv_param.common_serv_param[7] | | ||
1827 | ((plogi->serv_param.common_serv_param[6] & 0x0F) << 8); | ||
1828 | if (plogi->serv_param.class1_serv_param[0] & 0x80) | ||
1829 | port->supported_classes |= FC_COS_CLASS1; | ||
1830 | if (plogi->serv_param.class2_serv_param[0] & 0x80) | ||
1831 | port->supported_classes |= FC_COS_CLASS2; | ||
1832 | if (plogi->serv_param.class3_serv_param[0] & 0x80) | ||
1833 | port->supported_classes |= FC_COS_CLASS3; | ||
1834 | if (plogi->serv_param.class4_serv_param[0] & 0x80) | ||
1835 | port->supported_classes |= FC_COS_CLASS4; | ||
1836 | } | 801 | } |
1837 | |||
1838 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 66d3b88844b0..391dd29749f8 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c | |||
@@ -1,64 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Registration and callback for the s390 common I/O layer. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #include "zfcp_ext.h" | 9 | #include "zfcp_ext.h" |
23 | 10 | ||
24 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG | ||
25 | |||
26 | static int zfcp_ccw_probe(struct ccw_device *); | ||
27 | static void zfcp_ccw_remove(struct ccw_device *); | ||
28 | static int zfcp_ccw_set_online(struct ccw_device *); | ||
29 | static int zfcp_ccw_set_offline(struct ccw_device *); | ||
30 | static int zfcp_ccw_notify(struct ccw_device *, int); | ||
31 | static void zfcp_ccw_shutdown(struct ccw_device *); | ||
32 | |||
33 | static struct ccw_device_id zfcp_ccw_device_id[] = { | ||
34 | {CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE, | ||
35 | ZFCP_CONTROL_UNIT_MODEL, | ||
36 | ZFCP_DEVICE_TYPE, | ||
37 | ZFCP_DEVICE_MODEL)}, | ||
38 | {CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE, | ||
39 | ZFCP_CONTROL_UNIT_MODEL, | ||
40 | ZFCP_DEVICE_TYPE, | ||
41 | ZFCP_DEVICE_MODEL_PRIV)}, | ||
42 | {}, | ||
43 | }; | ||
44 | |||
45 | static struct ccw_driver zfcp_ccw_driver = { | ||
46 | .owner = THIS_MODULE, | ||
47 | .name = ZFCP_NAME, | ||
48 | .ids = zfcp_ccw_device_id, | ||
49 | .probe = zfcp_ccw_probe, | ||
50 | .remove = zfcp_ccw_remove, | ||
51 | .set_online = zfcp_ccw_set_online, | ||
52 | .set_offline = zfcp_ccw_set_offline, | ||
53 | .notify = zfcp_ccw_notify, | ||
54 | .shutdown = zfcp_ccw_shutdown, | ||
55 | .driver = { | ||
56 | .groups = zfcp_driver_attr_groups, | ||
57 | }, | ||
58 | }; | ||
59 | |||
60 | MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); | ||
61 | |||
62 | /** | 11 | /** |
63 | * zfcp_ccw_probe - probe function of zfcp driver | 12 | * zfcp_ccw_probe - probe function of zfcp driver |
64 | * @ccw_device: pointer to belonging ccw device | 13 | * @ccw_device: pointer to belonging ccw device |
@@ -69,19 +18,16 @@ MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); | |||
69 | * In addition the nameserver port will be added to the ports of the adapter | 18 | * In addition the nameserver port will be added to the ports of the adapter |
70 | * and its sysfs representation will be created too. | 19 | * and its sysfs representation will be created too. |
71 | */ | 20 | */ |
72 | static int | 21 | static int zfcp_ccw_probe(struct ccw_device *ccw_device) |
73 | zfcp_ccw_probe(struct ccw_device *ccw_device) | ||
74 | { | 22 | { |
75 | struct zfcp_adapter *adapter; | ||
76 | int retval = 0; | 23 | int retval = 0; |
77 | 24 | ||
78 | down(&zfcp_data.config_sema); | 25 | down(&zfcp_data.config_sema); |
79 | adapter = zfcp_adapter_enqueue(ccw_device); | 26 | if (zfcp_adapter_enqueue(ccw_device)) { |
80 | if (!adapter) | 27 | dev_err(&ccw_device->dev, |
28 | "Setup of data structures failed.\n"); | ||
81 | retval = -EINVAL; | 29 | retval = -EINVAL; |
82 | else | 30 | } |
83 | ZFCP_LOG_DEBUG("Probed adapter %s\n", | ||
84 | zfcp_get_busid_by_adapter(adapter)); | ||
85 | up(&zfcp_data.config_sema); | 31 | up(&zfcp_data.config_sema); |
86 | return retval; | 32 | return retval; |
87 | } | 33 | } |
@@ -95,8 +41,7 @@ zfcp_ccw_probe(struct ccw_device *ccw_device) | |||
95 | * ports that belong to this adapter. And in addition all resources of this | 41 | * ports that belong to this adapter. And in addition all resources of this |
96 | * adapter will be freed too. | 42 | * adapter will be freed too. |
97 | */ | 43 | */ |
98 | static void | 44 | static void zfcp_ccw_remove(struct ccw_device *ccw_device) |
99 | zfcp_ccw_remove(struct ccw_device *ccw_device) | ||
100 | { | 45 | { |
101 | struct zfcp_adapter *adapter; | 46 | struct zfcp_adapter *adapter; |
102 | struct zfcp_port *port, *p; | 47 | struct zfcp_port *port, *p; |
@@ -106,8 +51,6 @@ zfcp_ccw_remove(struct ccw_device *ccw_device) | |||
106 | down(&zfcp_data.config_sema); | 51 | down(&zfcp_data.config_sema); |
107 | adapter = dev_get_drvdata(&ccw_device->dev); | 52 | adapter = dev_get_drvdata(&ccw_device->dev); |
108 | 53 | ||
109 | ZFCP_LOG_DEBUG("Removing adapter %s\n", | ||
110 | zfcp_get_busid_by_adapter(adapter)); | ||
111 | write_lock_irq(&zfcp_data.config_lock); | 54 | write_lock_irq(&zfcp_data.config_lock); |
112 | list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { | 55 | list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { |
113 | list_for_each_entry_safe(unit, u, &port->unit_list_head, list) { | 56 | list_for_each_entry_safe(unit, u, &port->unit_list_head, list) { |
@@ -145,8 +88,7 @@ zfcp_ccw_remove(struct ccw_device *ccw_device) | |||
145 | * registered with the SCSI stack, that the QDIO queues will be set up | 88 | * registered with the SCSI stack, that the QDIO queues will be set up |
146 | * and that the adapter will be opened (asynchronously). | 89 | * and that the adapter will be opened (asynchronously). |
147 | */ | 90 | */ |
148 | static int | 91 | static int zfcp_ccw_set_online(struct ccw_device *ccw_device) |
149 | zfcp_ccw_set_online(struct ccw_device *ccw_device) | ||
150 | { | 92 | { |
151 | struct zfcp_adapter *adapter; | 93 | struct zfcp_adapter *adapter; |
152 | int retval; | 94 | int retval; |
@@ -155,12 +97,8 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device) | |||
155 | adapter = dev_get_drvdata(&ccw_device->dev); | 97 | adapter = dev_get_drvdata(&ccw_device->dev); |
156 | 98 | ||
157 | retval = zfcp_erp_thread_setup(adapter); | 99 | retval = zfcp_erp_thread_setup(adapter); |
158 | if (retval) { | 100 | if (retval) |
159 | ZFCP_LOG_INFO("error: start of error recovery thread for " | ||
160 | "adapter %s failed\n", | ||
161 | zfcp_get_busid_by_adapter(adapter)); | ||
162 | goto out; | 101 | goto out; |
163 | } | ||
164 | 102 | ||
165 | retval = zfcp_adapter_scsi_register(adapter); | 103 | retval = zfcp_adapter_scsi_register(adapter); |
166 | if (retval) | 104 | if (retval) |
@@ -191,8 +129,7 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device) | |||
191 | * This function gets called by the common i/o layer and sets an adapter | 129 | * This function gets called by the common i/o layer and sets an adapter |
192 | * into state offline. | 130 | * into state offline. |
193 | */ | 131 | */ |
194 | static int | 132 | static int zfcp_ccw_set_offline(struct ccw_device *ccw_device) |
195 | zfcp_ccw_set_offline(struct ccw_device *ccw_device) | ||
196 | { | 133 | { |
197 | struct zfcp_adapter *adapter; | 134 | struct zfcp_adapter *adapter; |
198 | 135 | ||
@@ -206,15 +143,14 @@ zfcp_ccw_set_offline(struct ccw_device *ccw_device) | |||
206 | } | 143 | } |
207 | 144 | ||
208 | /** | 145 | /** |
209 | * zfcp_ccw_notify | 146 | * zfcp_ccw_notify - ccw notify function |
210 | * @ccw_device: pointer to belonging ccw device | 147 | * @ccw_device: pointer to belonging ccw device |
211 | * @event: indicates if adapter was detached or attached | 148 | * @event: indicates if adapter was detached or attached |
212 | * | 149 | * |
213 | * This function gets called by the common i/o layer if an adapter has gone | 150 | * This function gets called by the common i/o layer if an adapter has gone |
214 | * or reappeared. | 151 | * or reappeared. |
215 | */ | 152 | */ |
216 | static int | 153 | static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) |
217 | zfcp_ccw_notify(struct ccw_device *ccw_device, int event) | ||
218 | { | 154 | { |
219 | struct zfcp_adapter *adapter; | 155 | struct zfcp_adapter *adapter; |
220 | 156 | ||
@@ -222,18 +158,15 @@ zfcp_ccw_notify(struct ccw_device *ccw_device, int event) | |||
222 | adapter = dev_get_drvdata(&ccw_device->dev); | 158 | adapter = dev_get_drvdata(&ccw_device->dev); |
223 | switch (event) { | 159 | switch (event) { |
224 | case CIO_GONE: | 160 | case CIO_GONE: |
225 | ZFCP_LOG_NORMAL("adapter %s: device gone\n", | 161 | dev_warn(&adapter->ccw_device->dev, "device gone\n"); |
226 | zfcp_get_busid_by_adapter(adapter)); | ||
227 | zfcp_erp_adapter_shutdown(adapter, 0, 87, NULL); | 162 | zfcp_erp_adapter_shutdown(adapter, 0, 87, NULL); |
228 | break; | 163 | break; |
229 | case CIO_NO_PATH: | 164 | case CIO_NO_PATH: |
230 | ZFCP_LOG_NORMAL("adapter %s: no path\n", | 165 | dev_warn(&adapter->ccw_device->dev, "no path\n"); |
231 | zfcp_get_busid_by_adapter(adapter)); | ||
232 | zfcp_erp_adapter_shutdown(adapter, 0, 88, NULL); | 166 | zfcp_erp_adapter_shutdown(adapter, 0, 88, NULL); |
233 | break; | 167 | break; |
234 | case CIO_OPER: | 168 | case CIO_OPER: |
235 | ZFCP_LOG_NORMAL("adapter %s: operational again\n", | 169 | dev_info(&adapter->ccw_device->dev, "operational again\n"); |
236 | zfcp_get_busid_by_adapter(adapter)); | ||
237 | zfcp_erp_modify_adapter_status(adapter, 11, NULL, | 170 | zfcp_erp_modify_adapter_status(adapter, 11, NULL, |
238 | ZFCP_STATUS_COMMON_RUNNING, | 171 | ZFCP_STATUS_COMMON_RUNNING, |
239 | ZFCP_SET); | 172 | ZFCP_SET); |
@@ -247,24 +180,10 @@ zfcp_ccw_notify(struct ccw_device *ccw_device, int event) | |||
247 | } | 180 | } |
248 | 181 | ||
249 | /** | 182 | /** |
250 | * zfcp_ccw_register - ccw register function | 183 | * zfcp_ccw_shutdown - handle shutdown from cio |
251 | * | 184 | * @cdev: device for adapter to shutdown. |
252 | * Registers the driver at the common i/o layer. This function will be called | ||
253 | * at module load time/system start. | ||
254 | */ | ||
255 | int __init | ||
256 | zfcp_ccw_register(void) | ||
257 | { | ||
258 | return ccw_driver_register(&zfcp_ccw_driver); | ||
259 | } | ||
260 | |||
261 | /** | ||
262 | * zfcp_ccw_shutdown - gets called on reboot/shutdown | ||
263 | * | ||
264 | * Makes sure that QDIO queues are down when the system gets stopped. | ||
265 | */ | 185 | */ |
266 | static void | 186 | static void zfcp_ccw_shutdown(struct ccw_device *cdev) |
267 | zfcp_ccw_shutdown(struct ccw_device *cdev) | ||
268 | { | 187 | { |
269 | struct zfcp_adapter *adapter; | 188 | struct zfcp_adapter *adapter; |
270 | 189 | ||
@@ -275,4 +194,33 @@ zfcp_ccw_shutdown(struct ccw_device *cdev) | |||
275 | up(&zfcp_data.config_sema); | 194 | up(&zfcp_data.config_sema); |
276 | } | 195 | } |
277 | 196 | ||
278 | #undef ZFCP_LOG_AREA | 197 | static struct ccw_device_id zfcp_ccw_device_id[] = { |
198 | { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) }, | ||
199 | { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x4) }, /* priv. */ | ||
200 | {}, | ||
201 | }; | ||
202 | |||
203 | MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); | ||
204 | |||
205 | static struct ccw_driver zfcp_ccw_driver = { | ||
206 | .owner = THIS_MODULE, | ||
207 | .name = "zfcp", | ||
208 | .ids = zfcp_ccw_device_id, | ||
209 | .probe = zfcp_ccw_probe, | ||
210 | .remove = zfcp_ccw_remove, | ||
211 | .set_online = zfcp_ccw_set_online, | ||
212 | .set_offline = zfcp_ccw_set_offline, | ||
213 | .notify = zfcp_ccw_notify, | ||
214 | .shutdown = zfcp_ccw_shutdown, | ||
215 | }; | ||
216 | |||
217 | /** | ||
218 | * zfcp_ccw_register - ccw register function | ||
219 | * | ||
220 | * Registers the driver at the common i/o layer. This function will be called | ||
221 | * at module load time/system start. | ||
222 | */ | ||
223 | int __init zfcp_ccw_register(void) | ||
224 | { | ||
225 | return ccw_driver_register(&zfcp_ccw_driver); | ||
226 | } | ||
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c new file mode 100644 index 000000000000..ec2abceca6dc --- /dev/null +++ b/drivers/s390/scsi/zfcp_cfdc.c | |||
@@ -0,0 +1,259 @@ | |||
1 | /* | ||
2 | * zfcp device driver | ||
3 | * | ||
4 | * Userspace interface for accessing the | ||
5 | * Access Control Lists / Control File Data Channel | ||
6 | * | ||
7 | * Copyright IBM Corporation 2008 | ||
8 | */ | ||
9 | |||
10 | #include <linux/types.h> | ||
11 | #include <linux/miscdevice.h> | ||
12 | #include <asm/ccwdev.h> | ||
13 | #include "zfcp_def.h" | ||
14 | #include "zfcp_ext.h" | ||
15 | #include "zfcp_fsf.h" | ||
16 | |||
17 | #define ZFCP_CFDC_CMND_DOWNLOAD_NORMAL 0x00010001 | ||
18 | #define ZFCP_CFDC_CMND_DOWNLOAD_FORCE 0x00010101 | ||
19 | #define ZFCP_CFDC_CMND_FULL_ACCESS 0x00000201 | ||
20 | #define ZFCP_CFDC_CMND_RESTRICTED_ACCESS 0x00000401 | ||
21 | #define ZFCP_CFDC_CMND_UPLOAD 0x00010002 | ||
22 | |||
23 | #define ZFCP_CFDC_DOWNLOAD 0x00000001 | ||
24 | #define ZFCP_CFDC_UPLOAD 0x00000002 | ||
25 | #define ZFCP_CFDC_WITH_CONTROL_FILE 0x00010000 | ||
26 | |||
27 | #define ZFCP_CFDC_IOC_MAGIC 0xDD | ||
28 | #define ZFCP_CFDC_IOC \ | ||
29 | _IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_data) | ||
30 | |||
31 | /** | ||
32 | * struct zfcp_cfdc_data - data for ioctl cfdc interface | ||
33 | * @signature: request signature | ||
34 | * @devno: FCP adapter device number | ||
35 | * @command: command code | ||
36 | * @fsf_status: returns status of FSF command to userspace | ||
37 | * @fsf_status_qual: returned to userspace | ||
38 | * @payloads: access conflicts list | ||
39 | * @control_file: access control table | ||
40 | */ | ||
41 | struct zfcp_cfdc_data { | ||
42 | u32 signature; | ||
43 | u32 devno; | ||
44 | u32 command; | ||
45 | u32 fsf_status; | ||
46 | u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; | ||
47 | u8 payloads[256]; | ||
48 | u8 control_file[0]; | ||
49 | }; | ||
50 | |||
51 | static int zfcp_cfdc_copy_from_user(struct scatterlist *sg, | ||
52 | void __user *user_buffer) | ||
53 | { | ||
54 | unsigned int length; | ||
55 | unsigned int size = ZFCP_CFDC_MAX_SIZE; | ||
56 | |||
57 | while (size) { | ||
58 | length = min((unsigned int)size, sg->length); | ||
59 | if (copy_from_user(sg_virt(sg++), user_buffer, length)) | ||
60 | return -EFAULT; | ||
61 | user_buffer += length; | ||
62 | size -= length; | ||
63 | } | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int zfcp_cfdc_copy_to_user(void __user *user_buffer, | ||
68 | struct scatterlist *sg) | ||
69 | { | ||
70 | unsigned int length; | ||
71 | unsigned int size = ZFCP_CFDC_MAX_SIZE; | ||
72 | |||
73 | while (size) { | ||
74 | length = min((unsigned int) size, sg->length); | ||
75 | if (copy_to_user(user_buffer, sg_virt(sg++), length)) | ||
76 | return -EFAULT; | ||
77 | user_buffer += length; | ||
78 | size -= length; | ||
79 | } | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno) | ||
84 | { | ||
85 | struct zfcp_adapter *adapter = NULL, *cur_adapter; | ||
86 | struct ccw_dev_id dev_id; | ||
87 | |||
88 | read_lock_irq(&zfcp_data.config_lock); | ||
89 | list_for_each_entry(cur_adapter, &zfcp_data.adapter_list_head, list) { | ||
90 | ccw_device_get_id(cur_adapter->ccw_device, &dev_id); | ||
91 | if (dev_id.devno == devno) { | ||
92 | adapter = cur_adapter; | ||
93 | zfcp_adapter_get(adapter); | ||
94 | break; | ||
95 | } | ||
96 | } | ||
97 | read_unlock_irq(&zfcp_data.config_lock); | ||
98 | return adapter; | ||
99 | } | ||
100 | |||
101 | static int zfcp_cfdc_set_fsf(struct zfcp_fsf_cfdc *fsf_cfdc, int command) | ||
102 | { | ||
103 | switch (command) { | ||
104 | case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL: | ||
105 | fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
106 | fsf_cfdc->option = FSF_CFDC_OPTION_NORMAL_MODE; | ||
107 | break; | ||
108 | case ZFCP_CFDC_CMND_DOWNLOAD_FORCE: | ||
109 | fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
110 | fsf_cfdc->option = FSF_CFDC_OPTION_FORCE; | ||
111 | break; | ||
112 | case ZFCP_CFDC_CMND_FULL_ACCESS: | ||
113 | fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
114 | fsf_cfdc->option = FSF_CFDC_OPTION_FULL_ACCESS; | ||
115 | break; | ||
116 | case ZFCP_CFDC_CMND_RESTRICTED_ACCESS: | ||
117 | fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
118 | fsf_cfdc->option = FSF_CFDC_OPTION_RESTRICTED_ACCESS; | ||
119 | break; | ||
120 | case ZFCP_CFDC_CMND_UPLOAD: | ||
121 | fsf_cfdc->command = FSF_QTCB_UPLOAD_CONTROL_FILE; | ||
122 | fsf_cfdc->option = 0; | ||
123 | break; | ||
124 | default: | ||
125 | return -EINVAL; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int zfcp_cfdc_sg_setup(int command, struct scatterlist *sg, | ||
132 | u8 __user *control_file) | ||
133 | { | ||
134 | int retval; | ||
135 | retval = zfcp_sg_setup_table(sg, ZFCP_CFDC_PAGES); | ||
136 | if (retval) | ||
137 | return retval; | ||
138 | |||
139 | sg[ZFCP_CFDC_PAGES - 1].length = ZFCP_CFDC_MAX_SIZE % PAGE_SIZE; | ||
140 | |||
141 | if (command & ZFCP_CFDC_WITH_CONTROL_FILE && | ||
142 | command & ZFCP_CFDC_DOWNLOAD) { | ||
143 | retval = zfcp_cfdc_copy_from_user(sg, control_file); | ||
144 | if (retval) { | ||
145 | zfcp_sg_free_table(sg, ZFCP_CFDC_PAGES); | ||
146 | return -EFAULT; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static void zfcp_cfdc_req_to_sense(struct zfcp_cfdc_data *data, | ||
154 | struct zfcp_fsf_req *req) | ||
155 | { | ||
156 | data->fsf_status = req->qtcb->header.fsf_status; | ||
157 | memcpy(&data->fsf_status_qual, &req->qtcb->header.fsf_status_qual, | ||
158 | sizeof(union fsf_status_qual)); | ||
159 | memcpy(&data->payloads, &req->qtcb->bottom.support.els, | ||
160 | sizeof(req->qtcb->bottom.support.els)); | ||
161 | } | ||
162 | |||
163 | static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, | ||
164 | unsigned long buffer) | ||
165 | { | ||
166 | struct zfcp_cfdc_data *data; | ||
167 | struct zfcp_cfdc_data __user *data_user; | ||
168 | struct zfcp_adapter *adapter; | ||
169 | struct zfcp_fsf_req *req; | ||
170 | struct zfcp_fsf_cfdc *fsf_cfdc; | ||
171 | int retval; | ||
172 | |||
173 | if (command != ZFCP_CFDC_IOC) | ||
174 | return -ENOTTY; | ||
175 | |||
176 | data_user = (void __user *) buffer; | ||
177 | if (!data_user) | ||
178 | return -EINVAL; | ||
179 | |||
180 | fsf_cfdc = kmalloc(sizeof(struct zfcp_fsf_cfdc), GFP_KERNEL); | ||
181 | if (!fsf_cfdc) | ||
182 | return -ENOMEM; | ||
183 | |||
184 | data = kmalloc(sizeof(struct zfcp_cfdc_data), GFP_KERNEL); | ||
185 | if (!data) { | ||
186 | retval = -ENOMEM; | ||
187 | goto no_mem_sense; | ||
188 | } | ||
189 | |||
190 | retval = copy_from_user(data, data_user, sizeof(*data)); | ||
191 | if (retval) { | ||
192 | retval = -EFAULT; | ||
193 | goto free_buffer; | ||
194 | } | ||
195 | |||
196 | if (data->signature != 0xCFDCACDF) { | ||
197 | retval = -EINVAL; | ||
198 | goto free_buffer; | ||
199 | } | ||
200 | |||
201 | retval = zfcp_cfdc_set_fsf(fsf_cfdc, data->command); | ||
202 | |||
203 | adapter = zfcp_cfdc_get_adapter(data->devno); | ||
204 | if (!adapter) { | ||
205 | retval = -ENXIO; | ||
206 | goto free_buffer; | ||
207 | } | ||
208 | |||
209 | retval = zfcp_cfdc_sg_setup(data->command, fsf_cfdc->sg, | ||
210 | data_user->control_file); | ||
211 | if (retval) | ||
212 | goto adapter_put; | ||
213 | req = zfcp_fsf_control_file(adapter, fsf_cfdc); | ||
214 | if (IS_ERR(req)) { | ||
215 | retval = PTR_ERR(req); | ||
216 | goto free_sg; | ||
217 | } | ||
218 | |||
219 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
220 | retval = -ENXIO; | ||
221 | goto free_fsf; | ||
222 | } | ||
223 | |||
224 | zfcp_cfdc_req_to_sense(data, req); | ||
225 | retval = copy_to_user(data_user, data, sizeof(*data_user)); | ||
226 | if (retval) { | ||
227 | retval = -EFAULT; | ||
228 | goto free_fsf; | ||
229 | } | ||
230 | |||
231 | if (data->command & ZFCP_CFDC_UPLOAD) | ||
232 | retval = zfcp_cfdc_copy_to_user(&data_user->control_file, | ||
233 | fsf_cfdc->sg); | ||
234 | |||
235 | free_fsf: | ||
236 | zfcp_fsf_req_free(req); | ||
237 | free_sg: | ||
238 | zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES); | ||
239 | adapter_put: | ||
240 | zfcp_adapter_put(adapter); | ||
241 | free_buffer: | ||
242 | kfree(data); | ||
243 | no_mem_sense: | ||
244 | kfree(fsf_cfdc); | ||
245 | return retval; | ||
246 | } | ||
247 | |||
248 | static const struct file_operations zfcp_cfdc_fops = { | ||
249 | .unlocked_ioctl = zfcp_cfdc_dev_ioctl, | ||
250 | #ifdef CONFIG_COMPAT | ||
251 | .compat_ioctl = zfcp_cfdc_dev_ioctl | ||
252 | #endif | ||
253 | }; | ||
254 | |||
255 | struct miscdevice zfcp_cfdc_misc = { | ||
256 | .minor = MISC_DYNAMIC_MINOR, | ||
257 | .name = "zfcp_cfdc", | ||
258 | .fops = &zfcp_cfdc_fops, | ||
259 | }; | ||
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index c8bad675dbd1..36169c6944fd 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c | |||
@@ -1,22 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Debug traces for zfcp. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #include <linux/ctype.h> | 9 | #include <linux/ctype.h> |
@@ -29,8 +16,6 @@ module_param(dbfsize, uint, 0400); | |||
29 | MODULE_PARM_DESC(dbfsize, | 16 | MODULE_PARM_DESC(dbfsize, |
30 | "number of pages for each debug feature area (default 4)"); | 17 | "number of pages for each debug feature area (default 4)"); |
31 | 18 | ||
32 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER | ||
33 | |||
34 | static void zfcp_dbf_hexdump(debug_info_t *dbf, void *to, int to_len, | 19 | static void zfcp_dbf_hexdump(debug_info_t *dbf, void *to, int to_len, |
35 | int level, char *from, int from_len) | 20 | int level, char *from, int from_len) |
36 | { | 21 | { |
@@ -186,8 +171,8 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) | |||
186 | fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE); | 171 | fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE); |
187 | response->fsf_req_status = fsf_req->status; | 172 | response->fsf_req_status = fsf_req->status; |
188 | response->sbal_first = fsf_req->sbal_first; | 173 | response->sbal_first = fsf_req->sbal_first; |
189 | response->sbal_curr = fsf_req->sbal_curr; | ||
190 | response->sbal_last = fsf_req->sbal_last; | 174 | response->sbal_last = fsf_req->sbal_last; |
175 | response->sbal_response = fsf_req->sbal_response; | ||
191 | response->pool = fsf_req->pool != NULL; | 176 | response->pool = fsf_req->pool != NULL; |
192 | response->erp_action = (unsigned long)fsf_req->erp_action; | 177 | response->erp_action = (unsigned long)fsf_req->erp_action; |
193 | 178 | ||
@@ -268,7 +253,7 @@ void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, | |||
268 | strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE); | 253 | strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE); |
269 | strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE); | 254 | strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE); |
270 | 255 | ||
271 | rec->u.status.failed = adapter->status_read_failed; | 256 | rec->u.status.failed = atomic_read(&adapter->stat_miss); |
272 | if (status_buffer != NULL) { | 257 | if (status_buffer != NULL) { |
273 | rec->u.status.status_type = status_buffer->status_type; | 258 | rec->u.status.status_type = status_buffer->status_type; |
274 | rec->u.status.status_subtype = status_buffer->status_subtype; | 259 | rec->u.status.status_subtype = status_buffer->status_subtype; |
@@ -355,8 +340,8 @@ static void zfcp_hba_dbf_view_response(char **p, | |||
355 | FSF_STATUS_QUALIFIER_SIZE, 0, FSF_STATUS_QUALIFIER_SIZE); | 340 | FSF_STATUS_QUALIFIER_SIZE, 0, FSF_STATUS_QUALIFIER_SIZE); |
356 | zfcp_dbf_out(p, "fsf_req_status", "0x%08x", r->fsf_req_status); | 341 | zfcp_dbf_out(p, "fsf_req_status", "0x%08x", r->fsf_req_status); |
357 | zfcp_dbf_out(p, "sbal_first", "0x%02x", r->sbal_first); | 342 | zfcp_dbf_out(p, "sbal_first", "0x%02x", r->sbal_first); |
358 | zfcp_dbf_out(p, "sbal_curr", "0x%02x", r->sbal_curr); | ||
359 | zfcp_dbf_out(p, "sbal_last", "0x%02x", r->sbal_last); | 343 | zfcp_dbf_out(p, "sbal_last", "0x%02x", r->sbal_last); |
344 | zfcp_dbf_out(p, "sbal_response", "0x%02x", r->sbal_response); | ||
360 | zfcp_dbf_out(p, "pool", "0x%02x", r->pool); | 345 | zfcp_dbf_out(p, "pool", "0x%02x", r->pool); |
361 | 346 | ||
362 | switch (r->fsf_command) { | 347 | switch (r->fsf_command) { |
@@ -515,13 +500,13 @@ static const char *zfcp_rec_dbf_ids[] = { | |||
515 | [52] = "port boxed close unit", | 500 | [52] = "port boxed close unit", |
516 | [53] = "port boxed fcp", | 501 | [53] = "port boxed fcp", |
517 | [54] = "unit boxed fcp", | 502 | [54] = "unit boxed fcp", |
518 | [55] = "port access denied ct", | 503 | [55] = "port access denied", |
519 | [56] = "port access denied els", | 504 | [56] = "", |
520 | [57] = "port access denied open port", | 505 | [57] = "", |
521 | [58] = "port access denied close physical", | 506 | [58] = "", |
522 | [59] = "unit access denied open unit", | 507 | [59] = "unit access denied", |
523 | [60] = "shared unit access denied open unit", | 508 | [60] = "shared unit access denied open unit", |
524 | [61] = "unit access denied fcp", | 509 | [61] = "", |
525 | [62] = "request timeout", | 510 | [62] = "request timeout", |
526 | [63] = "adisc link test reject or timeout", | 511 | [63] = "adisc link test reject or timeout", |
527 | [64] = "adisc link test d_id changed", | 512 | [64] = "adisc link test d_id changed", |
@@ -546,8 +531,8 @@ static const char *zfcp_rec_dbf_ids[] = { | |||
546 | [80] = "exclusive read-only unit access unsupported", | 531 | [80] = "exclusive read-only unit access unsupported", |
547 | [81] = "shared read-write unit access unsupported", | 532 | [81] = "shared read-write unit access unsupported", |
548 | [82] = "incoming rscn", | 533 | [82] = "incoming rscn", |
549 | [83] = "incoming plogi", | 534 | [83] = "incoming wwpn", |
550 | [84] = "incoming logo", | 535 | [84] = "", |
551 | [85] = "online", | 536 | [85] = "online", |
552 | [86] = "offline", | 537 | [86] = "offline", |
553 | [87] = "ccw device gone", | 538 | [87] = "ccw device gone", |
@@ -586,8 +571,8 @@ static const char *zfcp_rec_dbf_ids[] = { | |||
586 | [120] = "unknown fsf command", | 571 | [120] = "unknown fsf command", |
587 | [121] = "no recommendation for status qualifier", | 572 | [121] = "no recommendation for status qualifier", |
588 | [122] = "status read physical port closed in error", | 573 | [122] = "status read physical port closed in error", |
589 | [123] = "fc service class not supported ct", | 574 | [123] = "fc service class not supported", |
590 | [124] = "fc service class not supported els", | 575 | [124] = "", |
591 | [125] = "need newer zfcp", | 576 | [125] = "need newer zfcp", |
592 | [126] = "need newer microcode", | 577 | [126] = "need newer microcode", |
593 | [127] = "arbitrated loop not supported", | 578 | [127] = "arbitrated loop not supported", |
@@ -595,7 +580,7 @@ static const char *zfcp_rec_dbf_ids[] = { | |||
595 | [129] = "qtcb size mismatch", | 580 | [129] = "qtcb size mismatch", |
596 | [130] = "unknown fsf status ecd", | 581 | [130] = "unknown fsf status ecd", |
597 | [131] = "fcp request too big", | 582 | [131] = "fcp request too big", |
598 | [132] = "fc service class not supported fcp", | 583 | [132] = "", |
599 | [133] = "data direction not valid fcp", | 584 | [133] = "data direction not valid fcp", |
600 | [134] = "command length not valid fcp", | 585 | [134] = "command length not valid fcp", |
601 | [135] = "status read act update", | 586 | [135] = "status read act update", |
@@ -603,13 +588,18 @@ static const char *zfcp_rec_dbf_ids[] = { | |||
603 | [137] = "hbaapi port open", | 588 | [137] = "hbaapi port open", |
604 | [138] = "hbaapi unit open", | 589 | [138] = "hbaapi unit open", |
605 | [139] = "hbaapi unit shutdown", | 590 | [139] = "hbaapi unit shutdown", |
606 | [140] = "qdio error", | 591 | [140] = "qdio error outbound", |
607 | [141] = "scsi host reset", | 592 | [141] = "scsi host reset", |
608 | [142] = "dismissing fsf request for recovery action", | 593 | [142] = "dismissing fsf request for recovery action", |
609 | [143] = "recovery action timed out", | 594 | [143] = "recovery action timed out", |
610 | [144] = "recovery action gone", | 595 | [144] = "recovery action gone", |
611 | [145] = "recovery action being processed", | 596 | [145] = "recovery action being processed", |
612 | [146] = "recovery action ready for next step", | 597 | [146] = "recovery action ready for next step", |
598 | [147] = "qdio error inbound", | ||
599 | [148] = "nameserver needed for port scan", | ||
600 | [149] = "port scan", | ||
601 | [150] = "ptp attach", | ||
602 | [151] = "port validation failed", | ||
613 | }; | 603 | }; |
614 | 604 | ||
615 | static int zfcp_rec_dbf_view_format(debug_info_t *id, struct debug_view *view, | 605 | static int zfcp_rec_dbf_view_format(debug_info_t *id, struct debug_view *view, |
@@ -670,24 +660,20 @@ static struct debug_view zfcp_rec_dbf_view = { | |||
670 | * zfcp_rec_dbf_event_thread - trace event related to recovery thread operation | 660 | * zfcp_rec_dbf_event_thread - trace event related to recovery thread operation |
671 | * @id2: identifier for event | 661 | * @id2: identifier for event |
672 | * @adapter: adapter | 662 | * @adapter: adapter |
673 | * @lock: non-zero value indicates that erp_lock has not yet been acquired | 663 | * This function assumes that the caller is holding erp_lock. |
674 | */ | 664 | */ |
675 | void zfcp_rec_dbf_event_thread(u8 id2, struct zfcp_adapter *adapter, int lock) | 665 | void zfcp_rec_dbf_event_thread(u8 id2, struct zfcp_adapter *adapter) |
676 | { | 666 | { |
677 | struct zfcp_rec_dbf_record *r = &adapter->rec_dbf_buf; | 667 | struct zfcp_rec_dbf_record *r = &adapter->rec_dbf_buf; |
678 | unsigned long flags = 0; | 668 | unsigned long flags = 0; |
679 | struct list_head *entry; | 669 | struct list_head *entry; |
680 | unsigned ready = 0, running = 0, total; | 670 | unsigned ready = 0, running = 0, total; |
681 | 671 | ||
682 | if (lock) | ||
683 | read_lock_irqsave(&adapter->erp_lock, flags); | ||
684 | list_for_each(entry, &adapter->erp_ready_head) | 672 | list_for_each(entry, &adapter->erp_ready_head) |
685 | ready++; | 673 | ready++; |
686 | list_for_each(entry, &adapter->erp_running_head) | 674 | list_for_each(entry, &adapter->erp_running_head) |
687 | running++; | 675 | running++; |
688 | total = adapter->erp_total_count; | 676 | total = adapter->erp_total_count; |
689 | if (lock) | ||
690 | read_unlock_irqrestore(&adapter->erp_lock, flags); | ||
691 | 677 | ||
692 | spin_lock_irqsave(&adapter->rec_dbf_lock, flags); | 678 | spin_lock_irqsave(&adapter->rec_dbf_lock, flags); |
693 | memset(r, 0, sizeof(*r)); | 679 | memset(r, 0, sizeof(*r)); |
@@ -696,10 +682,25 @@ void zfcp_rec_dbf_event_thread(u8 id2, struct zfcp_adapter *adapter, int lock) | |||
696 | r->u.thread.total = total; | 682 | r->u.thread.total = total; |
697 | r->u.thread.ready = ready; | 683 | r->u.thread.ready = ready; |
698 | r->u.thread.running = running; | 684 | r->u.thread.running = running; |
699 | debug_event(adapter->rec_dbf, 5, r, sizeof(*r)); | 685 | debug_event(adapter->rec_dbf, 6, r, sizeof(*r)); |
700 | spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); | 686 | spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); |
701 | } | 687 | } |
702 | 688 | ||
689 | /** | ||
690 | * zfcp_rec_dbf_event_thread - trace event related to recovery thread operation | ||
691 | * @id2: identifier for event | ||
692 | * @adapter: adapter | ||
693 | * This function assumes that the caller does not hold erp_lock. | ||
694 | */ | ||
695 | void zfcp_rec_dbf_event_thread_lock(u8 id2, struct zfcp_adapter *adapter) | ||
696 | { | ||
697 | unsigned long flags; | ||
698 | |||
699 | read_lock_irqsave(&adapter->erp_lock, flags); | ||
700 | zfcp_rec_dbf_event_thread(id2, adapter); | ||
701 | read_unlock_irqrestore(&adapter->erp_lock, flags); | ||
702 | } | ||
703 | |||
703 | static void zfcp_rec_dbf_event_target(u8 id2, void *ref, | 704 | static void zfcp_rec_dbf_event_target(u8 id2, void *ref, |
704 | struct zfcp_adapter *adapter, | 705 | struct zfcp_adapter *adapter, |
705 | atomic_t *status, atomic_t *erp_count, | 706 | atomic_t *status, atomic_t *erp_count, |
@@ -823,7 +824,7 @@ void zfcp_rec_dbf_event_action(u8 id2, struct zfcp_erp_action *erp_action) | |||
823 | r->u.action.status = erp_action->status; | 824 | r->u.action.status = erp_action->status; |
824 | r->u.action.step = erp_action->step; | 825 | r->u.action.step = erp_action->step; |
825 | r->u.action.fsf_req = (unsigned long)erp_action->fsf_req; | 826 | r->u.action.fsf_req = (unsigned long)erp_action->fsf_req; |
826 | debug_event(adapter->rec_dbf, 4, r, sizeof(*r)); | 827 | debug_event(adapter->rec_dbf, 5, r, sizeof(*r)); |
827 | spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); | 828 | spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); |
828 | } | 829 | } |
829 | 830 | ||
@@ -960,7 +961,7 @@ void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req) | |||
960 | 961 | ||
961 | zfcp_san_dbf_event_els("iels", 1, fsf_req, buf->d_id, | 962 | zfcp_san_dbf_event_els("iels", 1, fsf_req, buf->d_id, |
962 | fc_host_port_id(adapter->scsi_host), | 963 | fc_host_port_id(adapter->scsi_host), |
963 | *(u8 *)buf->payload, (void *)buf->payload, | 964 | buf->payload.data[0], (void *)buf->payload.data, |
964 | length); | 965 | length); |
965 | } | 966 | } |
966 | 967 | ||
@@ -1064,8 +1065,7 @@ static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, | |||
1064 | if (fsf_req != NULL) { | 1065 | if (fsf_req != NULL) { |
1065 | fcp_rsp = (struct fcp_rsp_iu *) | 1066 | fcp_rsp = (struct fcp_rsp_iu *) |
1066 | &(fsf_req->qtcb->bottom.io.fcp_rsp); | 1067 | &(fsf_req->qtcb->bottom.io.fcp_rsp); |
1067 | fcp_rsp_info = | 1068 | fcp_rsp_info = (unsigned char *) &fcp_rsp[1]; |
1068 | zfcp_get_fcp_rsp_info_ptr(fcp_rsp); | ||
1069 | fcp_sns_info = | 1069 | fcp_sns_info = |
1070 | zfcp_get_fcp_sns_info_ptr(fcp_rsp); | 1070 | zfcp_get_fcp_sns_info_ptr(fcp_rsp); |
1071 | 1071 | ||
@@ -1279,5 +1279,3 @@ void zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter) | |||
1279 | adapter->hba_dbf = NULL; | 1279 | adapter->hba_dbf = NULL; |
1280 | adapter->rec_dbf = NULL; | 1280 | adapter->rec_dbf = NULL; |
1281 | } | 1281 | } |
1282 | |||
1283 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 54c34e483457..d04aea604974 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h | |||
@@ -38,7 +38,7 @@ struct zfcp_rec_dbf_record_thread { | |||
38 | u32 total; | 38 | u32 total; |
39 | u32 ready; | 39 | u32 ready; |
40 | u32 running; | 40 | u32 running; |
41 | } __attribute__ ((packed)); | 41 | }; |
42 | 42 | ||
43 | struct zfcp_rec_dbf_record_target { | 43 | struct zfcp_rec_dbf_record_target { |
44 | u64 ref; | 44 | u64 ref; |
@@ -47,7 +47,7 @@ struct zfcp_rec_dbf_record_target { | |||
47 | u64 wwpn; | 47 | u64 wwpn; |
48 | u64 fcp_lun; | 48 | u64 fcp_lun; |
49 | u32 erp_count; | 49 | u32 erp_count; |
50 | } __attribute__ ((packed)); | 50 | }; |
51 | 51 | ||
52 | struct zfcp_rec_dbf_record_trigger { | 52 | struct zfcp_rec_dbf_record_trigger { |
53 | u8 want; | 53 | u8 want; |
@@ -59,14 +59,14 @@ struct zfcp_rec_dbf_record_trigger { | |||
59 | u64 action; | 59 | u64 action; |
60 | u64 wwpn; | 60 | u64 wwpn; |
61 | u64 fcp_lun; | 61 | u64 fcp_lun; |
62 | } __attribute__ ((packed)); | 62 | }; |
63 | 63 | ||
64 | struct zfcp_rec_dbf_record_action { | 64 | struct zfcp_rec_dbf_record_action { |
65 | u32 status; | 65 | u32 status; |
66 | u32 step; | 66 | u32 step; |
67 | u64 action; | 67 | u64 action; |
68 | u64 fsf_req; | 68 | u64 fsf_req; |
69 | } __attribute__ ((packed)); | 69 | }; |
70 | 70 | ||
71 | struct zfcp_rec_dbf_record { | 71 | struct zfcp_rec_dbf_record { |
72 | u8 id; | 72 | u8 id; |
@@ -77,7 +77,7 @@ struct zfcp_rec_dbf_record { | |||
77 | struct zfcp_rec_dbf_record_target target; | 77 | struct zfcp_rec_dbf_record_target target; |
78 | struct zfcp_rec_dbf_record_trigger trigger; | 78 | struct zfcp_rec_dbf_record_trigger trigger; |
79 | } u; | 79 | } u; |
80 | } __attribute__ ((packed)); | 80 | }; |
81 | 81 | ||
82 | enum { | 82 | enum { |
83 | ZFCP_REC_DBF_ID_ACTION, | 83 | ZFCP_REC_DBF_ID_ACTION, |
@@ -97,8 +97,8 @@ struct zfcp_hba_dbf_record_response { | |||
97 | u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; | 97 | u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; |
98 | u32 fsf_req_status; | 98 | u32 fsf_req_status; |
99 | u8 sbal_first; | 99 | u8 sbal_first; |
100 | u8 sbal_curr; | ||
101 | u8 sbal_last; | 100 | u8 sbal_last; |
101 | u8 sbal_response; | ||
102 | u8 pool; | 102 | u8 pool; |
103 | u64 erp_action; | 103 | u64 erp_action; |
104 | union { | 104 | union { |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index bda8c77b22da..67f45fc62f53 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -1,22 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Global definitions for the zfcp device driver. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #ifndef ZFCP_DEF_H | 9 | #ifndef ZFCP_DEF_H |
@@ -26,7 +13,6 @@ | |||
26 | 13 | ||
27 | #include <linux/init.h> | 14 | #include <linux/init.h> |
28 | #include <linux/moduleparam.h> | 15 | #include <linux/moduleparam.h> |
29 | #include <linux/miscdevice.h> | ||
30 | #include <linux/major.h> | 16 | #include <linux/major.h> |
31 | #include <linux/blkdev.h> | 17 | #include <linux/blkdev.h> |
32 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
@@ -53,9 +39,6 @@ | |||
53 | 39 | ||
54 | /********************* GENERAL DEFINES *********************************/ | 40 | /********************* GENERAL DEFINES *********************************/ |
55 | 41 | ||
56 | /* zfcp version number, it consists of major, minor, and patch-level number */ | ||
57 | #define ZFCP_VERSION "4.8.0" | ||
58 | |||
59 | /** | 42 | /** |
60 | * zfcp_sg_to_address - determine kernel address from struct scatterlist | 43 | * zfcp_sg_to_address - determine kernel address from struct scatterlist |
61 | * @list: struct scatterlist | 44 | * @list: struct scatterlist |
@@ -93,11 +76,6 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) | |||
93 | #define ZFCP_DEVICE_MODEL 0x03 | 76 | #define ZFCP_DEVICE_MODEL 0x03 |
94 | #define ZFCP_DEVICE_MODEL_PRIV 0x04 | 77 | #define ZFCP_DEVICE_MODEL_PRIV 0x04 |
95 | 78 | ||
96 | /* allow as many chained SBALs as are supported by hardware */ | ||
97 | #define ZFCP_MAX_SBALS_PER_REQ FSF_MAX_SBALS_PER_REQ | ||
98 | #define ZFCP_MAX_SBALS_PER_CT_REQ FSF_MAX_SBALS_PER_REQ | ||
99 | #define ZFCP_MAX_SBALS_PER_ELS_REQ FSF_MAX_SBALS_PER_ELS_REQ | ||
100 | |||
101 | /* DMQ bug workaround: don't use last SBALE */ | 79 | /* DMQ bug workaround: don't use last SBALE */ |
102 | #define ZFCP_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1) | 80 | #define ZFCP_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1) |
103 | 81 | ||
@@ -106,42 +84,17 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) | |||
106 | 84 | ||
107 | /* max. number of (data buffer) SBALEs in largest SBAL chain */ | 85 | /* max. number of (data buffer) SBALEs in largest SBAL chain */ |
108 | #define ZFCP_MAX_SBALES_PER_REQ \ | 86 | #define ZFCP_MAX_SBALES_PER_REQ \ |
109 | (ZFCP_MAX_SBALS_PER_REQ * ZFCP_MAX_SBALES_PER_SBAL - 2) | 87 | (FSF_MAX_SBALS_PER_REQ * ZFCP_MAX_SBALES_PER_SBAL - 2) |
110 | /* request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */ | 88 | /* request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */ |
111 | 89 | ||
112 | #define ZFCP_MAX_SECTORS (ZFCP_MAX_SBALES_PER_REQ * 8) | 90 | #define ZFCP_MAX_SECTORS (ZFCP_MAX_SBALES_PER_REQ * 8) |
113 | /* max. number of (data buffer) SBALEs in largest SBAL chain | 91 | /* max. number of (data buffer) SBALEs in largest SBAL chain |
114 | multiplied with number of sectors per 4k block */ | 92 | multiplied with number of sectors per 4k block */ |
115 | 93 | ||
116 | /* FIXME(tune): free space should be one max. SBAL chain plus what? */ | ||
117 | #define ZFCP_QDIO_PCI_INTERVAL (QDIO_MAX_BUFFERS_PER_Q \ | ||
118 | - (ZFCP_MAX_SBALS_PER_REQ + 4)) | ||
119 | |||
120 | #define ZFCP_SBAL_TIMEOUT (5*HZ) | ||
121 | |||
122 | #define ZFCP_TYPE2_RECOVERY_TIME 8 /* seconds */ | ||
123 | |||
124 | /* queue polling (values in microseconds) */ | ||
125 | #define ZFCP_MAX_INPUT_THRESHOLD 5000 /* FIXME: tune */ | ||
126 | #define ZFCP_MAX_OUTPUT_THRESHOLD 1000 /* FIXME: tune */ | ||
127 | #define ZFCP_MIN_INPUT_THRESHOLD 1 /* ignored by QDIO layer */ | ||
128 | #define ZFCP_MIN_OUTPUT_THRESHOLD 1 /* ignored by QDIO layer */ | ||
129 | |||
130 | #define QDIO_SCSI_QFMT 1 /* 1 for FSF */ | ||
131 | #define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer)) | ||
132 | |||
133 | /********************* FSF SPECIFIC DEFINES *********************************/ | 94 | /********************* FSF SPECIFIC DEFINES *********************************/ |
134 | 95 | ||
135 | #define ZFCP_ULP_INFO_VERSION 26 | ||
136 | #define ZFCP_QTCB_VERSION FSF_QTCB_CURRENT_VERSION | ||
137 | /* ATTENTION: value must not be used by hardware */ | 96 | /* ATTENTION: value must not be used by hardware */ |
138 | #define FSF_QTCB_UNSOLICITED_STATUS 0x6305 | 97 | #define FSF_QTCB_UNSOLICITED_STATUS 0x6305 |
139 | #define ZFCP_STATUS_READ_FAILED_THRESHOLD 3 | ||
140 | #define ZFCP_STATUS_READS_RECOM FSF_STATUS_READS_RECOM | ||
141 | |||
142 | /* Do 1st retry in 1 second, then double the timeout for each following retry */ | ||
143 | #define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP 1 | ||
144 | #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 7 | ||
145 | 98 | ||
146 | /* timeout value for "default timer" for fsf requests */ | 99 | /* timeout value for "default timer" for fsf requests */ |
147 | #define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ) | 100 | #define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ) |
@@ -153,17 +106,9 @@ typedef unsigned long long fcp_lun_t; | |||
153 | /* data length field may be at variable position in FCP-2 FCP_CMND IU */ | 106 | /* data length field may be at variable position in FCP-2 FCP_CMND IU */ |
154 | typedef unsigned int fcp_dl_t; | 107 | typedef unsigned int fcp_dl_t; |
155 | 108 | ||
156 | #define ZFCP_FC_SERVICE_CLASS_DEFAULT FSF_CLASS_3 | ||
157 | |||
158 | /* timeout for name-server lookup (in seconds) */ | 109 | /* timeout for name-server lookup (in seconds) */ |
159 | #define ZFCP_NS_GID_PN_TIMEOUT 10 | 110 | #define ZFCP_NS_GID_PN_TIMEOUT 10 |
160 | 111 | ||
161 | /* largest SCSI command we can process */ | ||
162 | /* FCP-2 (FCP_CMND IU) allows up to (255-3+16) */ | ||
163 | #define ZFCP_MAX_SCSI_CMND_LENGTH 255 | ||
164 | /* maximum number of commands in LUN queue (tagged queueing) */ | ||
165 | #define ZFCP_CMND_PER_LUN 32 | ||
166 | |||
167 | /* task attribute values in FCP-2 FCP_CMND IU */ | 112 | /* task attribute values in FCP-2 FCP_CMND IU */ |
168 | #define SIMPLE_Q 0 | 113 | #define SIMPLE_Q 0 |
169 | #define HEAD_OF_Q 1 | 114 | #define HEAD_OF_Q 1 |
@@ -224,9 +169,9 @@ struct fcp_rsp_iu { | |||
224 | #define RSP_CODE_TASKMAN_FAILED 5 | 169 | #define RSP_CODE_TASKMAN_FAILED 5 |
225 | 170 | ||
226 | /* see fc-fs */ | 171 | /* see fc-fs */ |
227 | #define LS_RSCN 0x61040000 | 172 | #define LS_RSCN 0x61 |
228 | #define LS_LOGO 0x05000000 | 173 | #define LS_LOGO 0x05 |
229 | #define LS_PLOGI 0x03000000 | 174 | #define LS_PLOGI 0x03 |
230 | 175 | ||
231 | struct fcp_rscn_head { | 176 | struct fcp_rscn_head { |
232 | u8 command; | 177 | u8 command; |
@@ -266,7 +211,6 @@ struct fcp_logo { | |||
266 | * FC-FS stuff | 211 | * FC-FS stuff |
267 | */ | 212 | */ |
268 | #define R_A_TOV 10 /* seconds */ | 213 | #define R_A_TOV 10 /* seconds */ |
269 | #define ZFCP_ELS_TIMEOUT (2 * R_A_TOV) | ||
270 | 214 | ||
271 | #define ZFCP_LS_RLS 0x0f | 215 | #define ZFCP_LS_RLS 0x0f |
272 | #define ZFCP_LS_ADISC 0x52 | 216 | #define ZFCP_LS_ADISC 0x52 |
@@ -311,7 +255,10 @@ struct zfcp_rc_entry { | |||
311 | #define ZFCP_CT_DIRECTORY_SERVICE 0xFC | 255 | #define ZFCP_CT_DIRECTORY_SERVICE 0xFC |
312 | #define ZFCP_CT_NAME_SERVER 0x02 | 256 | #define ZFCP_CT_NAME_SERVER 0x02 |
313 | #define ZFCP_CT_SYNCHRONOUS 0x00 | 257 | #define ZFCP_CT_SYNCHRONOUS 0x00 |
258 | #define ZFCP_CT_SCSI_FCP 0x08 | ||
259 | #define ZFCP_CT_UNABLE_TO_PERFORM_CMD 0x09 | ||
314 | #define ZFCP_CT_GID_PN 0x0121 | 260 | #define ZFCP_CT_GID_PN 0x0121 |
261 | #define ZFCP_CT_GPN_FT 0x0172 | ||
315 | #define ZFCP_CT_MAX_SIZE 0x1020 | 262 | #define ZFCP_CT_MAX_SIZE 0x1020 |
316 | #define ZFCP_CT_ACCEPT 0x8002 | 263 | #define ZFCP_CT_ACCEPT 0x8002 |
317 | #define ZFCP_CT_REJECT 0x8001 | 264 | #define ZFCP_CT_REJECT 0x8001 |
@@ -321,107 +268,6 @@ struct zfcp_rc_entry { | |||
321 | */ | 268 | */ |
322 | #define ZFCP_CT_TIMEOUT (3 * R_A_TOV) | 269 | #define ZFCP_CT_TIMEOUT (3 * R_A_TOV) |
323 | 270 | ||
324 | /******************** LOGGING MACROS AND DEFINES *****************************/ | ||
325 | |||
326 | /* | ||
327 | * Logging may be applied on certain kinds of driver operations | ||
328 | * independently. Additionally, different log-levels are supported for | ||
329 | * each of these areas. | ||
330 | */ | ||
331 | |||
332 | #define ZFCP_NAME "zfcp" | ||
333 | |||
334 | /* independent log areas */ | ||
335 | #define ZFCP_LOG_AREA_OTHER 0 | ||
336 | #define ZFCP_LOG_AREA_SCSI 1 | ||
337 | #define ZFCP_LOG_AREA_FSF 2 | ||
338 | #define ZFCP_LOG_AREA_CONFIG 3 | ||
339 | #define ZFCP_LOG_AREA_CIO 4 | ||
340 | #define ZFCP_LOG_AREA_QDIO 5 | ||
341 | #define ZFCP_LOG_AREA_ERP 6 | ||
342 | #define ZFCP_LOG_AREA_FC 7 | ||
343 | |||
344 | /* log level values*/ | ||
345 | #define ZFCP_LOG_LEVEL_NORMAL 0 | ||
346 | #define ZFCP_LOG_LEVEL_INFO 1 | ||
347 | #define ZFCP_LOG_LEVEL_DEBUG 2 | ||
348 | #define ZFCP_LOG_LEVEL_TRACE 3 | ||
349 | |||
350 | /* | ||
351 | * this allows removal of logging code by the preprocessor | ||
352 | * (the most detailed log level still to be compiled in is specified, | ||
353 | * higher log levels are removed) | ||
354 | */ | ||
355 | #define ZFCP_LOG_LEVEL_LIMIT ZFCP_LOG_LEVEL_TRACE | ||
356 | |||
357 | /* get "loglevel" nibble assignment */ | ||
358 | #define ZFCP_GET_LOG_VALUE(zfcp_lognibble) \ | ||
359 | ((atomic_read(&zfcp_data.loglevel) >> (zfcp_lognibble<<2)) & 0xF) | ||
360 | |||
361 | /* set "loglevel" nibble */ | ||
362 | #define ZFCP_SET_LOG_NIBBLE(value, zfcp_lognibble) \ | ||
363 | (value << (zfcp_lognibble << 2)) | ||
364 | |||
365 | /* all log-level defaults are combined to generate initial log-level */ | ||
366 | #define ZFCP_LOG_LEVEL_DEFAULTS \ | ||
367 | (ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_OTHER) | \ | ||
368 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_SCSI) | \ | ||
369 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_FSF) | \ | ||
370 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_CONFIG) | \ | ||
371 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_CIO) | \ | ||
372 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_QDIO) | \ | ||
373 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_ERP) | \ | ||
374 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_FC)) | ||
375 | |||
376 | /* check whether we have the right level for logging */ | ||
377 | #define ZFCP_LOG_CHECK(level) \ | ||
378 | ((ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA)) >= level) | ||
379 | |||
380 | /* logging routine for zfcp */ | ||
381 | #define _ZFCP_LOG(fmt, args...) \ | ||
382 | printk(KERN_ERR ZFCP_NAME": %s(%d): " fmt, __func__, \ | ||
383 | __LINE__ , ##args) | ||
384 | |||
385 | #define ZFCP_LOG(level, fmt, args...) \ | ||
386 | do { \ | ||
387 | if (ZFCP_LOG_CHECK(level)) \ | ||
388 | _ZFCP_LOG(fmt, ##args); \ | ||
389 | } while (0) | ||
390 | |||
391 | #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL | ||
392 | # define ZFCP_LOG_NORMAL(fmt, args...) do { } while (0) | ||
393 | #else | ||
394 | # define ZFCP_LOG_NORMAL(fmt, args...) \ | ||
395 | do { \ | ||
396 | if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_NORMAL)) \ | ||
397 | printk(KERN_ERR ZFCP_NAME": " fmt, ##args); \ | ||
398 | } while (0) | ||
399 | #endif | ||
400 | |||
401 | #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_INFO | ||
402 | # define ZFCP_LOG_INFO(fmt, args...) do { } while (0) | ||
403 | #else | ||
404 | # define ZFCP_LOG_INFO(fmt, args...) \ | ||
405 | do { \ | ||
406 | if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_INFO)) \ | ||
407 | printk(KERN_ERR ZFCP_NAME": " fmt, ##args); \ | ||
408 | } while (0) | ||
409 | #endif | ||
410 | |||
411 | #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_DEBUG | ||
412 | # define ZFCP_LOG_DEBUG(fmt, args...) do { } while (0) | ||
413 | #else | ||
414 | # define ZFCP_LOG_DEBUG(fmt, args...) \ | ||
415 | ZFCP_LOG(ZFCP_LOG_LEVEL_DEBUG, fmt , ##args) | ||
416 | #endif | ||
417 | |||
418 | #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_TRACE | ||
419 | # define ZFCP_LOG_TRACE(fmt, args...) do { } while (0) | ||
420 | #else | ||
421 | # define ZFCP_LOG_TRACE(fmt, args...) \ | ||
422 | ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, fmt , ##args) | ||
423 | #endif | ||
424 | |||
425 | /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/ | 271 | /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/ |
426 | 272 | ||
427 | /* | 273 | /* |
@@ -441,6 +287,7 @@ do { \ | |||
441 | #define ZFCP_STATUS_COMMON_ERP_INUSE 0x01000000 | 287 | #define ZFCP_STATUS_COMMON_ERP_INUSE 0x01000000 |
442 | #define ZFCP_STATUS_COMMON_ACCESS_DENIED 0x00800000 | 288 | #define ZFCP_STATUS_COMMON_ACCESS_DENIED 0x00800000 |
443 | #define ZFCP_STATUS_COMMON_ACCESS_BOXED 0x00400000 | 289 | #define ZFCP_STATUS_COMMON_ACCESS_BOXED 0x00400000 |
290 | #define ZFCP_STATUS_COMMON_NOESC 0x00200000 | ||
444 | 291 | ||
445 | /* adapter status */ | 292 | /* adapter status */ |
446 | #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 | 293 | #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 |
@@ -496,77 +343,6 @@ do { \ | |||
496 | #define ZFCP_STATUS_FSFREQ_RETRY 0x00000800 | 343 | #define ZFCP_STATUS_FSFREQ_RETRY 0x00000800 |
497 | #define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000 | 344 | #define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000 |
498 | 345 | ||
499 | /*********************** ERROR RECOVERY PROCEDURE DEFINES ********************/ | ||
500 | |||
501 | #define ZFCP_MAX_ERPS 3 | ||
502 | |||
503 | #define ZFCP_ERP_FSFREQ_TIMEOUT (30 * HZ) | ||
504 | #define ZFCP_ERP_MEMWAIT_TIMEOUT HZ | ||
505 | |||
506 | #define ZFCP_STATUS_ERP_TIMEDOUT 0x10000000 | ||
507 | #define ZFCP_STATUS_ERP_CLOSE_ONLY 0x01000000 | ||
508 | #define ZFCP_STATUS_ERP_DISMISSING 0x00100000 | ||
509 | #define ZFCP_STATUS_ERP_DISMISSED 0x00200000 | ||
510 | #define ZFCP_STATUS_ERP_LOWMEM 0x00400000 | ||
511 | |||
512 | #define ZFCP_ERP_STEP_UNINITIALIZED 0x00000000 | ||
513 | #define ZFCP_ERP_STEP_FSF_XCONFIG 0x00000001 | ||
514 | #define ZFCP_ERP_STEP_PHYS_PORT_CLOSING 0x00000010 | ||
515 | #define ZFCP_ERP_STEP_PORT_CLOSING 0x00000100 | ||
516 | #define ZFCP_ERP_STEP_NAMESERVER_OPEN 0x00000200 | ||
517 | #define ZFCP_ERP_STEP_NAMESERVER_LOOKUP 0x00000400 | ||
518 | #define ZFCP_ERP_STEP_PORT_OPENING 0x00000800 | ||
519 | #define ZFCP_ERP_STEP_UNIT_CLOSING 0x00001000 | ||
520 | #define ZFCP_ERP_STEP_UNIT_OPENING 0x00002000 | ||
521 | |||
522 | /* Ordered by escalation level (necessary for proper erp-code operation) */ | ||
523 | #define ZFCP_ERP_ACTION_REOPEN_ADAPTER 0x4 | ||
524 | #define ZFCP_ERP_ACTION_REOPEN_PORT_FORCED 0x3 | ||
525 | #define ZFCP_ERP_ACTION_REOPEN_PORT 0x2 | ||
526 | #define ZFCP_ERP_ACTION_REOPEN_UNIT 0x1 | ||
527 | |||
528 | #define ZFCP_ERP_ACTION_RUNNING 0x1 | ||
529 | #define ZFCP_ERP_ACTION_READY 0x2 | ||
530 | |||
531 | #define ZFCP_ERP_SUCCEEDED 0x0 | ||
532 | #define ZFCP_ERP_FAILED 0x1 | ||
533 | #define ZFCP_ERP_CONTINUES 0x2 | ||
534 | #define ZFCP_ERP_EXIT 0x3 | ||
535 | #define ZFCP_ERP_DISMISSED 0x4 | ||
536 | #define ZFCP_ERP_NOMEM 0x5 | ||
537 | |||
538 | |||
539 | /******************** CFDC SPECIFIC STUFF *****************************/ | ||
540 | |||
541 | /* Firewall data channel sense data record */ | ||
542 | struct zfcp_cfdc_sense_data { | ||
543 | u32 signature; /* Request signature */ | ||
544 | u32 devno; /* FCP adapter device number */ | ||
545 | u32 command; /* Command code */ | ||
546 | u32 fsf_status; /* FSF request status and status qualifier */ | ||
547 | u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; | ||
548 | u8 payloads[256]; /* Access conflicts list */ | ||
549 | u8 control_file[0]; /* Access control table */ | ||
550 | }; | ||
551 | |||
552 | #define ZFCP_CFDC_SIGNATURE 0xCFDCACDF | ||
553 | |||
554 | #define ZFCP_CFDC_CMND_DOWNLOAD_NORMAL 0x00010001 | ||
555 | #define ZFCP_CFDC_CMND_DOWNLOAD_FORCE 0x00010101 | ||
556 | #define ZFCP_CFDC_CMND_FULL_ACCESS 0x00000201 | ||
557 | #define ZFCP_CFDC_CMND_RESTRICTED_ACCESS 0x00000401 | ||
558 | #define ZFCP_CFDC_CMND_UPLOAD 0x00010002 | ||
559 | |||
560 | #define ZFCP_CFDC_DOWNLOAD 0x00000001 | ||
561 | #define ZFCP_CFDC_UPLOAD 0x00000002 | ||
562 | #define ZFCP_CFDC_WITH_CONTROL_FILE 0x00010000 | ||
563 | |||
564 | #define ZFCP_CFDC_DEV_NAME "zfcp_cfdc" | ||
565 | #define ZFCP_CFDC_DEV_MAJOR MISC_MAJOR | ||
566 | #define ZFCP_CFDC_DEV_MINOR MISC_DYNAMIC_MINOR | ||
567 | |||
568 | #define ZFCP_CFDC_MAX_CONTROL_FILE_SIZE 127 * 1024 | ||
569 | |||
570 | /************************* STRUCTURE DEFINITIONS *****************************/ | 346 | /************************* STRUCTURE DEFINITIONS *****************************/ |
571 | 347 | ||
572 | struct zfcp_fsf_req; | 348 | struct zfcp_fsf_req; |
@@ -623,7 +399,6 @@ typedef void (*zfcp_send_ct_handler_t)(unsigned long); | |||
623 | * @resp_count: number of elements in response scatter-gather list | 399 | * @resp_count: number of elements in response scatter-gather list |
624 | * @handler: handler function (called for response to the request) | 400 | * @handler: handler function (called for response to the request) |
625 | * @handler_data: data passed to handler function | 401 | * @handler_data: data passed to handler function |
626 | * @pool: pointer to memory pool for ct request structure | ||
627 | * @timeout: FSF timeout for this request | 402 | * @timeout: FSF timeout for this request |
628 | * @completion: completion for synchronization purposes | 403 | * @completion: completion for synchronization purposes |
629 | * @status: used to pass error status to calling function | 404 | * @status: used to pass error status to calling function |
@@ -636,7 +411,6 @@ struct zfcp_send_ct { | |||
636 | unsigned int resp_count; | 411 | unsigned int resp_count; |
637 | zfcp_send_ct_handler_t handler; | 412 | zfcp_send_ct_handler_t handler; |
638 | unsigned long handler_data; | 413 | unsigned long handler_data; |
639 | mempool_t *pool; | ||
640 | int timeout; | 414 | int timeout; |
641 | struct completion *completion; | 415 | struct completion *completion; |
642 | int status; | 416 | int status; |
@@ -685,13 +459,13 @@ struct zfcp_send_els { | |||
685 | }; | 459 | }; |
686 | 460 | ||
687 | struct zfcp_qdio_queue { | 461 | struct zfcp_qdio_queue { |
688 | struct qdio_buffer *buffer[QDIO_MAX_BUFFERS_PER_Q]; /* SBALs */ | 462 | struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; /* SBALs */ |
689 | u8 free_index; /* index of next free bfr | 463 | u8 first; /* index of next free bfr |
690 | in queue (free_count>0) */ | 464 | in queue (free_count>0) */ |
691 | atomic_t free_count; /* number of free buffers | 465 | atomic_t count; /* number of free buffers |
692 | in queue */ | 466 | in queue */ |
693 | rwlock_t queue_lock; /* lock for operations on queue */ | 467 | spinlock_t lock; /* lock for operations on queue */ |
694 | int distance_from_int; /* SBALs used since PCI indication | 468 | int pci_batch; /* SBALs since PCI indication |
695 | was last set */ | 469 | was last set */ |
696 | }; | 470 | }; |
697 | 471 | ||
@@ -708,6 +482,24 @@ struct zfcp_erp_action { | |||
708 | struct timer_list timer; | 482 | struct timer_list timer; |
709 | }; | 483 | }; |
710 | 484 | ||
485 | struct fsf_latency_record { | ||
486 | u32 min; | ||
487 | u32 max; | ||
488 | u64 sum; | ||
489 | }; | ||
490 | |||
491 | struct latency_cont { | ||
492 | struct fsf_latency_record channel; | ||
493 | struct fsf_latency_record fabric; | ||
494 | u64 counter; | ||
495 | }; | ||
496 | |||
497 | struct zfcp_latencies { | ||
498 | struct latency_cont read; | ||
499 | struct latency_cont write; | ||
500 | struct latency_cont cmd; | ||
501 | spinlock_t lock; | ||
502 | }; | ||
711 | 503 | ||
712 | struct zfcp_adapter { | 504 | struct zfcp_adapter { |
713 | struct list_head list; /* list of adapters */ | 505 | struct list_head list; /* list of adapters */ |
@@ -723,24 +515,25 @@ struct zfcp_adapter { | |||
723 | u32 adapter_features; /* FCP channel features */ | 515 | u32 adapter_features; /* FCP channel features */ |
724 | u32 connection_features; /* host connection features */ | 516 | u32 connection_features; /* host connection features */ |
725 | u32 hardware_version; /* of FCP channel */ | 517 | u32 hardware_version; /* of FCP channel */ |
518 | u16 timer_ticks; /* time int for a tick */ | ||
726 | struct Scsi_Host *scsi_host; /* Pointer to mid-layer */ | 519 | struct Scsi_Host *scsi_host; /* Pointer to mid-layer */ |
727 | struct list_head port_list_head; /* remote port list */ | 520 | struct list_head port_list_head; /* remote port list */ |
728 | struct list_head port_remove_lh; /* head of ports to be | 521 | struct list_head port_remove_lh; /* head of ports to be |
729 | removed */ | 522 | removed */ |
730 | u32 ports; /* number of remote ports */ | 523 | u32 ports; /* number of remote ports */ |
731 | atomic_t reqs_active; /* # active FSF reqs */ | ||
732 | unsigned long req_no; /* unique FSF req number */ | 524 | unsigned long req_no; /* unique FSF req number */ |
733 | struct list_head *req_list; /* list of pending reqs */ | 525 | struct list_head *req_list; /* list of pending reqs */ |
734 | spinlock_t req_list_lock; /* request list lock */ | 526 | spinlock_t req_list_lock; /* request list lock */ |
735 | struct zfcp_qdio_queue request_queue; /* request queue */ | 527 | struct zfcp_qdio_queue req_q; /* request queue */ |
736 | u32 fsf_req_seq_no; /* FSF cmnd seq number */ | 528 | u32 fsf_req_seq_no; /* FSF cmnd seq number */ |
737 | wait_queue_head_t request_wq; /* can be used to wait for | 529 | wait_queue_head_t request_wq; /* can be used to wait for |
738 | more avaliable SBALs */ | 530 | more avaliable SBALs */ |
739 | struct zfcp_qdio_queue response_queue; /* response queue */ | 531 | struct zfcp_qdio_queue resp_q; /* response queue */ |
740 | rwlock_t abort_lock; /* Protects against SCSI | 532 | rwlock_t abort_lock; /* Protects against SCSI |
741 | stack abort/command | 533 | stack abort/command |
742 | completion races */ | 534 | completion races */ |
743 | u16 status_read_failed; /* # failed status reads */ | 535 | atomic_t stat_miss; /* # missing status reads*/ |
536 | struct work_struct stat_work; | ||
744 | atomic_t status; /* status of this adapter */ | 537 | atomic_t status; /* status of this adapter */ |
745 | struct list_head erp_ready_head; /* error recovery for this | 538 | struct list_head erp_ready_head; /* error recovery for this |
746 | adapter/devices */ | 539 | adapter/devices */ |
@@ -774,13 +567,9 @@ struct zfcp_adapter { | |||
774 | struct fc_host_statistics *fc_stats; | 567 | struct fc_host_statistics *fc_stats; |
775 | struct fsf_qtcb_bottom_port *stats_reset_data; | 568 | struct fsf_qtcb_bottom_port *stats_reset_data; |
776 | unsigned long stats_reset; | 569 | unsigned long stats_reset; |
570 | struct work_struct scan_work; | ||
777 | }; | 571 | }; |
778 | 572 | ||
779 | /* | ||
780 | * the struct device sysfs_device must be at the beginning of this structure. | ||
781 | * pointer to struct device is used to free port structure in release function | ||
782 | * of the device. don't change! | ||
783 | */ | ||
784 | struct zfcp_port { | 573 | struct zfcp_port { |
785 | struct device sysfs_device; /* sysfs device */ | 574 | struct device sysfs_device; /* sysfs device */ |
786 | struct fc_rport *rport; /* rport of fc transport class */ | 575 | struct fc_rport *rport; /* rport of fc transport class */ |
@@ -804,10 +593,6 @@ struct zfcp_port { | |||
804 | u32 supported_classes; | 593 | u32 supported_classes; |
805 | }; | 594 | }; |
806 | 595 | ||
807 | /* the struct device sysfs_device must be at the beginning of this structure. | ||
808 | * pointer to struct device is used to free unit structure in release function | ||
809 | * of the device. don't change! | ||
810 | */ | ||
811 | struct zfcp_unit { | 596 | struct zfcp_unit { |
812 | struct device sysfs_device; /* sysfs device */ | 597 | struct device sysfs_device; /* sysfs device */ |
813 | struct list_head list; /* list of logical units */ | 598 | struct list_head list; /* list of logical units */ |
@@ -822,6 +607,7 @@ struct zfcp_unit { | |||
822 | struct scsi_device *device; /* scsi device struct pointer */ | 607 | struct scsi_device *device; /* scsi device struct pointer */ |
823 | struct zfcp_erp_action erp_action; /* pending error recovery */ | 608 | struct zfcp_erp_action erp_action; /* pending error recovery */ |
824 | atomic_t erp_counter; | 609 | atomic_t erp_counter; |
610 | struct zfcp_latencies latencies; | ||
825 | }; | 611 | }; |
826 | 612 | ||
827 | /* FSF request */ | 613 | /* FSF request */ |
@@ -831,19 +617,19 @@ struct zfcp_fsf_req { | |||
831 | struct zfcp_adapter *adapter; /* adapter request belongs to */ | 617 | struct zfcp_adapter *adapter; /* adapter request belongs to */ |
832 | u8 sbal_number; /* nr of SBALs free for use */ | 618 | u8 sbal_number; /* nr of SBALs free for use */ |
833 | u8 sbal_first; /* first SBAL for this request */ | 619 | u8 sbal_first; /* first SBAL for this request */ |
834 | u8 sbal_last; /* last possible SBAL for | 620 | u8 sbal_last; /* last SBAL for this request */ |
621 | u8 sbal_limit; /* last possible SBAL for | ||
835 | this reuest */ | 622 | this reuest */ |
836 | u8 sbal_curr; /* current SBAL during creation | ||
837 | of request */ | ||
838 | u8 sbale_curr; /* current SBALE during creation | 623 | u8 sbale_curr; /* current SBALE during creation |
839 | of request */ | 624 | of request */ |
625 | u8 sbal_response; /* SBAL used in interrupt */ | ||
840 | wait_queue_head_t completion_wq; /* can be used by a routine | 626 | wait_queue_head_t completion_wq; /* can be used by a routine |
841 | to wait for completion */ | 627 | to wait for completion */ |
842 | volatile u32 status; /* status of this request */ | 628 | volatile u32 status; /* status of this request */ |
843 | u32 fsf_command; /* FSF Command copy */ | 629 | u32 fsf_command; /* FSF Command copy */ |
844 | struct fsf_qtcb *qtcb; /* address of associated QTCB */ | 630 | struct fsf_qtcb *qtcb; /* address of associated QTCB */ |
845 | u32 seq_no; /* Sequence number of request */ | 631 | u32 seq_no; /* Sequence number of request */ |
846 | unsigned long data; /* private data of request */ | 632 | void *data; /* private data of request */ |
847 | struct timer_list timer; /* used for erp or scsi er */ | 633 | struct timer_list timer; /* used for erp or scsi er */ |
848 | struct zfcp_erp_action *erp_action; /* used if this request is | 634 | struct zfcp_erp_action *erp_action; /* used if this request is |
849 | issued on behalf of erp */ | 635 | issued on behalf of erp */ |
@@ -851,10 +637,9 @@ struct zfcp_fsf_req { | |||
851 | from emergency pool */ | 637 | from emergency pool */ |
852 | unsigned long long issued; /* request sent time (STCK) */ | 638 | unsigned long long issued; /* request sent time (STCK) */ |
853 | struct zfcp_unit *unit; | 639 | struct zfcp_unit *unit; |
640 | void (*handler)(struct zfcp_fsf_req *); | ||
854 | }; | 641 | }; |
855 | 642 | ||
856 | typedef void zfcp_fsf_req_handler_t(struct zfcp_fsf_req*); | ||
857 | |||
858 | /* driver data */ | 643 | /* driver data */ |
859 | struct zfcp_data { | 644 | struct zfcp_data { |
860 | struct scsi_host_template scsi_host_template; | 645 | struct scsi_host_template scsi_host_template; |
@@ -873,29 +658,11 @@ struct zfcp_data { | |||
873 | char init_busid[BUS_ID_SIZE]; | 658 | char init_busid[BUS_ID_SIZE]; |
874 | wwn_t init_wwpn; | 659 | wwn_t init_wwpn; |
875 | fcp_lun_t init_fcp_lun; | 660 | fcp_lun_t init_fcp_lun; |
876 | char *driver_version; | ||
877 | struct kmem_cache *fsf_req_qtcb_cache; | 661 | struct kmem_cache *fsf_req_qtcb_cache; |
878 | struct kmem_cache *sr_buffer_cache; | 662 | struct kmem_cache *sr_buffer_cache; |
879 | struct kmem_cache *gid_pn_cache; | 663 | struct kmem_cache *gid_pn_cache; |
880 | }; | 664 | }; |
881 | 665 | ||
882 | /** | ||
883 | * struct zfcp_sg_list - struct describing a scatter-gather list | ||
884 | * @sg: pointer to array of (struct scatterlist) | ||
885 | * @count: number of elements in scatter-gather list | ||
886 | */ | ||
887 | struct zfcp_sg_list { | ||
888 | struct scatterlist *sg; | ||
889 | unsigned int count; | ||
890 | }; | ||
891 | |||
892 | /* number of elements for various memory pools */ | ||
893 | #define ZFCP_POOL_FSF_REQ_ERP_NR 1 | ||
894 | #define ZFCP_POOL_FSF_REQ_SCSI_NR 1 | ||
895 | #define ZFCP_POOL_FSF_REQ_ABORT_NR 1 | ||
896 | #define ZFCP_POOL_STATUS_READ_NR ZFCP_STATUS_READS_RECOM | ||
897 | #define ZFCP_POOL_DATA_GID_PN_NR 1 | ||
898 | |||
899 | /* struct used by memory pools for fsf_requests */ | 666 | /* struct used by memory pools for fsf_requests */ |
900 | struct zfcp_fsf_req_qtcb { | 667 | struct zfcp_fsf_req_qtcb { |
901 | struct zfcp_fsf_req fsf_req; | 668 | struct zfcp_fsf_req fsf_req; |
@@ -905,7 +672,6 @@ struct zfcp_fsf_req_qtcb { | |||
905 | /********************** ZFCP SPECIFIC DEFINES ********************************/ | 672 | /********************** ZFCP SPECIFIC DEFINES ********************************/ |
906 | 673 | ||
907 | #define ZFCP_REQ_AUTO_CLEANUP 0x00000002 | 674 | #define ZFCP_REQ_AUTO_CLEANUP 0x00000002 |
908 | #define ZFCP_WAIT_FOR_SBAL 0x00000004 | ||
909 | #define ZFCP_REQ_NO_QTCB 0x00000008 | 675 | #define ZFCP_REQ_NO_QTCB 0x00000008 |
910 | 676 | ||
911 | #define ZFCP_SET 0x00000100 | 677 | #define ZFCP_SET 0x00000100 |
@@ -916,12 +682,6 @@ struct zfcp_fsf_req_qtcb { | |||
916 | ((atomic_read(target) & mask) == mask) | 682 | ((atomic_read(target) & mask) == mask) |
917 | #endif | 683 | #endif |
918 | 684 | ||
919 | extern void _zfcp_hex_dump(char *, int); | ||
920 | #define ZFCP_HEX_DUMP(level, addr, count) \ | ||
921 | if (ZFCP_LOG_CHECK(level)) { \ | ||
922 | _zfcp_hex_dump(addr, count); \ | ||
923 | } | ||
924 | |||
925 | #define zfcp_get_busid_by_adapter(adapter) (adapter->ccw_device->dev.bus_id) | 685 | #define zfcp_get_busid_by_adapter(adapter) (adapter->ccw_device->dev.bus_id) |
926 | #define zfcp_get_busid_by_port(port) (zfcp_get_busid_by_adapter(port->adapter)) | 686 | #define zfcp_get_busid_by_port(port) (zfcp_get_busid_by_adapter(port->adapter)) |
927 | #define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port)) | 687 | #define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port)) |
@@ -934,15 +694,6 @@ static inline int zfcp_reqlist_hash(unsigned long req_id) | |||
934 | return req_id % REQUEST_LIST_SIZE; | 694 | return req_id % REQUEST_LIST_SIZE; |
935 | } | 695 | } |
936 | 696 | ||
937 | static inline void zfcp_reqlist_add(struct zfcp_adapter *adapter, | ||
938 | struct zfcp_fsf_req *fsf_req) | ||
939 | { | ||
940 | unsigned int idx; | ||
941 | |||
942 | idx = zfcp_reqlist_hash(fsf_req->req_id); | ||
943 | list_add_tail(&fsf_req->list, &adapter->req_list[idx]); | ||
944 | } | ||
945 | |||
946 | static inline void zfcp_reqlist_remove(struct zfcp_adapter *adapter, | 697 | static inline void zfcp_reqlist_remove(struct zfcp_adapter *adapter, |
947 | struct zfcp_fsf_req *fsf_req) | 698 | struct zfcp_fsf_req *fsf_req) |
948 | { | 699 | { |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 805484658dd9..643ac4bba5b5 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -1,641 +1,406 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Error Recovery Procedures (ERP). |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP | ||
23 | |||
24 | #include "zfcp_ext.h" | 9 | #include "zfcp_ext.h" |
25 | 10 | ||
26 | static int zfcp_erp_adisc(struct zfcp_port *); | 11 | #define ZFCP_MAX_ERPS 3 |
27 | static void zfcp_erp_adisc_handler(unsigned long); | ||
28 | |||
29 | static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int, u8, | ||
30 | void *); | ||
31 | static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int, u8, | ||
32 | void *); | ||
33 | static int zfcp_erp_port_reopen_internal(struct zfcp_port *, int, u8, void *); | ||
34 | static int zfcp_erp_unit_reopen_internal(struct zfcp_unit *, int, u8, void *); | ||
35 | |||
36 | static int zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *, int, u8, | ||
37 | void *); | ||
38 | static int zfcp_erp_unit_reopen_all_internal(struct zfcp_port *, int, u8, | ||
39 | void *); | ||
40 | |||
41 | static void zfcp_erp_adapter_block(struct zfcp_adapter *, int); | ||
42 | static void zfcp_erp_adapter_unblock(struct zfcp_adapter *); | ||
43 | static void zfcp_erp_port_block(struct zfcp_port *, int); | ||
44 | static void zfcp_erp_port_unblock(struct zfcp_port *); | ||
45 | static void zfcp_erp_unit_block(struct zfcp_unit *, int); | ||
46 | static void zfcp_erp_unit_unblock(struct zfcp_unit *); | ||
47 | |||
48 | static int zfcp_erp_thread(void *); | ||
49 | |||
50 | static int zfcp_erp_strategy(struct zfcp_erp_action *); | ||
51 | |||
52 | static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *); | ||
53 | static int zfcp_erp_strategy_memwait(struct zfcp_erp_action *); | ||
54 | static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *, int); | ||
55 | static int zfcp_erp_strategy_check_unit(struct zfcp_unit *, int); | ||
56 | static int zfcp_erp_strategy_check_port(struct zfcp_port *, int); | ||
57 | static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int); | ||
58 | static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *, | ||
59 | struct zfcp_port *, | ||
60 | struct zfcp_unit *, int); | ||
61 | static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32); | ||
62 | static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *, | ||
63 | struct zfcp_port *, | ||
64 | struct zfcp_unit *, int); | ||
65 | static int zfcp_erp_strategy_check_queues(struct zfcp_adapter *); | ||
66 | static int zfcp_erp_strategy_check_action(struct zfcp_erp_action *, int); | ||
67 | |||
68 | static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *); | ||
69 | static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *, int); | ||
70 | static int zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *); | ||
71 | static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *); | ||
72 | static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *); | ||
73 | static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *); | ||
74 | static int zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *); | ||
75 | static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *); | ||
76 | static int zfcp_erp_adapter_strategy_open_fsf_statusread( | ||
77 | struct zfcp_erp_action *); | ||
78 | |||
79 | static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *); | ||
80 | static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *); | ||
81 | |||
82 | static int zfcp_erp_port_strategy(struct zfcp_erp_action *); | ||
83 | static int zfcp_erp_port_strategy_clearstati(struct zfcp_port *); | ||
84 | static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *); | ||
85 | static int zfcp_erp_port_strategy_open(struct zfcp_erp_action *); | ||
86 | static int zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *); | ||
87 | static int zfcp_erp_port_strategy_open_nameserver_wakeup( | ||
88 | struct zfcp_erp_action *); | ||
89 | static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *); | ||
90 | static int zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *); | ||
91 | static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *); | ||
92 | |||
93 | static int zfcp_erp_unit_strategy(struct zfcp_erp_action *); | ||
94 | static int zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *); | ||
95 | static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *); | ||
96 | static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *); | ||
97 | |||
98 | static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *); | ||
99 | static void zfcp_erp_action_dismiss_port(struct zfcp_port *); | ||
100 | static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *); | ||
101 | static void zfcp_erp_action_dismiss(struct zfcp_erp_action *); | ||
102 | |||
103 | static int zfcp_erp_action_enqueue(int, struct zfcp_adapter *, | ||
104 | struct zfcp_port *, struct zfcp_unit *, | ||
105 | u8 id, void *ref); | ||
106 | static int zfcp_erp_action_dequeue(struct zfcp_erp_action *); | ||
107 | static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *, | ||
108 | struct zfcp_port *, struct zfcp_unit *, | ||
109 | int); | ||
110 | |||
111 | static void zfcp_erp_action_ready(struct zfcp_erp_action *); | ||
112 | static int zfcp_erp_action_exists(struct zfcp_erp_action *); | ||
113 | |||
114 | static void zfcp_erp_action_to_ready(struct zfcp_erp_action *); | ||
115 | static void zfcp_erp_action_to_running(struct zfcp_erp_action *); | ||
116 | |||
117 | static void zfcp_erp_memwait_handler(unsigned long); | ||
118 | 12 | ||
119 | /** | 13 | enum zfcp_erp_act_flags { |
120 | * zfcp_close_qdio - close qdio queues for an adapter | 14 | ZFCP_STATUS_ERP_TIMEDOUT = 0x10000000, |
121 | */ | 15 | ZFCP_STATUS_ERP_CLOSE_ONLY = 0x01000000, |
122 | static void zfcp_close_qdio(struct zfcp_adapter *adapter) | 16 | ZFCP_STATUS_ERP_DISMISSING = 0x00100000, |
123 | { | 17 | ZFCP_STATUS_ERP_DISMISSED = 0x00200000, |
124 | struct zfcp_qdio_queue *req_queue; | 18 | ZFCP_STATUS_ERP_LOWMEM = 0x00400000, |
125 | int first, count; | 19 | }; |
126 | 20 | ||
127 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) | 21 | enum zfcp_erp_steps { |
128 | return; | 22 | ZFCP_ERP_STEP_UNINITIALIZED = 0x0000, |
23 | ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001, | ||
24 | ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010, | ||
25 | ZFCP_ERP_STEP_PORT_CLOSING = 0x0100, | ||
26 | ZFCP_ERP_STEP_NAMESERVER_OPEN = 0x0200, | ||
27 | ZFCP_ERP_STEP_NAMESERVER_LOOKUP = 0x0400, | ||
28 | ZFCP_ERP_STEP_PORT_OPENING = 0x0800, | ||
29 | ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000, | ||
30 | ZFCP_ERP_STEP_UNIT_OPENING = 0x2000, | ||
31 | }; | ||
129 | 32 | ||
130 | /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ | 33 | enum zfcp_erp_act_type { |
131 | req_queue = &adapter->request_queue; | 34 | ZFCP_ERP_ACTION_REOPEN_UNIT = 1, |
132 | write_lock_irq(&req_queue->queue_lock); | 35 | ZFCP_ERP_ACTION_REOPEN_PORT = 2, |
133 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); | 36 | ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3, |
134 | write_unlock_irq(&req_queue->queue_lock); | 37 | ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4, |
135 | 38 | }; | |
136 | while (qdio_shutdown(adapter->ccw_device, | 39 | |
137 | QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) | 40 | enum zfcp_erp_act_state { |
138 | ssleep(1); | 41 | ZFCP_ERP_ACTION_RUNNING = 1, |
139 | 42 | ZFCP_ERP_ACTION_READY = 2, | |
140 | /* cleanup used outbound sbals */ | 43 | }; |
141 | count = atomic_read(&req_queue->free_count); | 44 | |
142 | if (count < QDIO_MAX_BUFFERS_PER_Q) { | 45 | enum zfcp_erp_act_result { |
143 | first = (req_queue->free_index+count) % QDIO_MAX_BUFFERS_PER_Q; | 46 | ZFCP_ERP_SUCCEEDED = 0, |
144 | count = QDIO_MAX_BUFFERS_PER_Q - count; | 47 | ZFCP_ERP_FAILED = 1, |
145 | zfcp_qdio_zero_sbals(req_queue->buffer, first, count); | 48 | ZFCP_ERP_CONTINUES = 2, |
146 | } | 49 | ZFCP_ERP_EXIT = 3, |
147 | req_queue->free_index = 0; | 50 | ZFCP_ERP_DISMISSED = 4, |
148 | atomic_set(&req_queue->free_count, 0); | 51 | ZFCP_ERP_NOMEM = 5, |
149 | req_queue->distance_from_int = 0; | 52 | }; |
150 | adapter->response_queue.free_index = 0; | 53 | |
151 | atomic_set(&adapter->response_queue.free_count, 0); | 54 | static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask) |
55 | { | ||
56 | zfcp_erp_modify_adapter_status(adapter, 15, NULL, | ||
57 | ZFCP_STATUS_COMMON_UNBLOCKED | mask, | ||
58 | ZFCP_CLEAR); | ||
152 | } | 59 | } |
153 | 60 | ||
154 | /** | 61 | static int zfcp_erp_action_exists(struct zfcp_erp_action *act) |
155 | * zfcp_close_fsf - stop FSF operations for an adapter | ||
156 | * | ||
157 | * Dismiss and cleanup all pending fsf_reqs (this wakes up all initiators of | ||
158 | * requests waiting for completion; especially this returns SCSI commands | ||
159 | * with error state). | ||
160 | */ | ||
161 | static void zfcp_close_fsf(struct zfcp_adapter *adapter) | ||
162 | { | 62 | { |
163 | /* close queues to ensure that buffers are not accessed by adapter */ | 63 | struct zfcp_erp_action *curr_act; |
164 | zfcp_close_qdio(adapter); | 64 | |
165 | zfcp_fsf_req_dismiss_all(adapter); | 65 | list_for_each_entry(curr_act, &act->adapter->erp_running_head, list) |
166 | /* reset FSF request sequence number */ | 66 | if (act == curr_act) |
167 | adapter->fsf_req_seq_no = 0; | 67 | return ZFCP_ERP_ACTION_RUNNING; |
168 | /* all ports and units are closed */ | 68 | return 0; |
169 | zfcp_erp_modify_adapter_status(adapter, 24, NULL, | ||
170 | ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); | ||
171 | } | 69 | } |
172 | 70 | ||
173 | /** | 71 | static void zfcp_erp_action_ready(struct zfcp_erp_action *act) |
174 | * zfcp_fsf_request_timeout_handler - called if a request timed out | ||
175 | * @data: pointer to adapter for handler function | ||
176 | * | ||
177 | * This function needs to be called if requests (ELS, Generic Service, | ||
178 | * or SCSI commands) exceed a certain time limit. The assumption is | ||
179 | * that after the time limit the adapter get stuck. So we trigger a reopen of | ||
180 | * the adapter. | ||
181 | */ | ||
182 | static void zfcp_fsf_request_timeout_handler(unsigned long data) | ||
183 | { | 72 | { |
184 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; | 73 | struct zfcp_adapter *adapter = act->adapter; |
185 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 62, | 74 | |
186 | NULL); | 75 | list_move(&act->list, &act->adapter->erp_ready_head); |
76 | zfcp_rec_dbf_event_action(146, act); | ||
77 | up(&adapter->erp_ready_sem); | ||
78 | zfcp_rec_dbf_event_thread(2, adapter); | ||
187 | } | 79 | } |
188 | 80 | ||
189 | void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout) | 81 | static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) |
190 | { | 82 | { |
191 | fsf_req->timer.function = zfcp_fsf_request_timeout_handler; | 83 | act->status |= ZFCP_STATUS_ERP_DISMISSED; |
192 | fsf_req->timer.data = (unsigned long) fsf_req->adapter; | 84 | if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING) |
193 | fsf_req->timer.expires = jiffies + timeout; | 85 | zfcp_erp_action_ready(act); |
194 | add_timer(&fsf_req->timer); | ||
195 | } | 86 | } |
196 | 87 | ||
197 | /* | 88 | static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) |
198 | * function: | ||
199 | * | ||
200 | * purpose: called if an adapter failed, | ||
201 | * initiates adapter recovery which is done | ||
202 | * asynchronously | ||
203 | * | ||
204 | * returns: 0 - initiated action successfully | ||
205 | * <0 - failed to initiate action | ||
206 | */ | ||
207 | static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, | ||
208 | int clear_mask, u8 id, void *ref) | ||
209 | { | 89 | { |
210 | int retval; | 90 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE) |
91 | zfcp_erp_action_dismiss(&unit->erp_action); | ||
92 | } | ||
211 | 93 | ||
212 | ZFCP_LOG_DEBUG("reopen adapter %s\n", | 94 | static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) |
213 | zfcp_get_busid_by_adapter(adapter)); | 95 | { |
96 | struct zfcp_unit *unit; | ||
214 | 97 | ||
215 | zfcp_erp_adapter_block(adapter, clear_mask); | 98 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE) |
99 | zfcp_erp_action_dismiss(&port->erp_action); | ||
100 | else | ||
101 | list_for_each_entry(unit, &port->unit_list_head, list) | ||
102 | zfcp_erp_action_dismiss_unit(unit); | ||
103 | } | ||
216 | 104 | ||
217 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { | 105 | static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) |
218 | ZFCP_LOG_DEBUG("skipped reopen of failed adapter %s\n", | 106 | { |
219 | zfcp_get_busid_by_adapter(adapter)); | 107 | struct zfcp_port *port; |
220 | /* ensure propagation of failed status to new devices */ | ||
221 | zfcp_erp_adapter_failed(adapter, 13, NULL); | ||
222 | retval = -EIO; | ||
223 | goto out; | ||
224 | } | ||
225 | retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, | ||
226 | adapter, NULL, NULL, id, ref); | ||
227 | 108 | ||
228 | out: | 109 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE) |
229 | return retval; | 110 | zfcp_erp_action_dismiss(&adapter->erp_action); |
111 | else | ||
112 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
113 | zfcp_erp_action_dismiss_port(port); | ||
230 | } | 114 | } |
231 | 115 | ||
232 | /* | 116 | static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, |
233 | * function: | 117 | struct zfcp_port *port, |
234 | * | 118 | struct zfcp_unit *unit) |
235 | * purpose: Wrappper for zfcp_erp_adapter_reopen_internal | ||
236 | * used to ensure the correct locking | ||
237 | * | ||
238 | * returns: 0 - initiated action successfully | ||
239 | * <0 - failed to initiate action | ||
240 | */ | ||
241 | int zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear_mask, | ||
242 | u8 id, void *ref) | ||
243 | { | 119 | { |
244 | int retval; | 120 | int need = want; |
245 | unsigned long flags; | 121 | int u_status, p_status, a_status; |
246 | 122 | ||
247 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 123 | switch (want) { |
248 | write_lock(&adapter->erp_lock); | 124 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
249 | retval = zfcp_erp_adapter_reopen_internal(adapter, clear_mask, id, ref); | 125 | u_status = atomic_read(&unit->status); |
250 | write_unlock(&adapter->erp_lock); | 126 | if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE) |
251 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 127 | return 0; |
128 | p_status = atomic_read(&port->status); | ||
129 | if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) || | ||
130 | p_status & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
131 | return 0; | ||
132 | if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED)) | ||
133 | need = ZFCP_ERP_ACTION_REOPEN_PORT; | ||
134 | /* fall through */ | ||
135 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
136 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
137 | p_status = atomic_read(&port->status); | ||
138 | if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE) | ||
139 | return 0; | ||
140 | a_status = atomic_read(&adapter->status); | ||
141 | if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) || | ||
142 | a_status & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
143 | return 0; | ||
144 | if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED)) | ||
145 | need = ZFCP_ERP_ACTION_REOPEN_ADAPTER; | ||
146 | /* fall through */ | ||
147 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
148 | a_status = atomic_read(&adapter->status); | ||
149 | if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE) | ||
150 | return 0; | ||
151 | } | ||
252 | 152 | ||
253 | return retval; | 153 | return need; |
254 | } | 154 | } |
255 | 155 | ||
256 | int zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear_mask, | 156 | static struct zfcp_erp_action *zfcp_erp_setup_act(int need, |
257 | u8 id, void *ref) | 157 | struct zfcp_adapter *adapter, |
158 | struct zfcp_port *port, | ||
159 | struct zfcp_unit *unit) | ||
258 | { | 160 | { |
259 | int retval; | 161 | struct zfcp_erp_action *erp_action; |
162 | u32 status = 0; | ||
260 | 163 | ||
261 | retval = zfcp_erp_adapter_reopen(adapter, | 164 | switch (need) { |
262 | ZFCP_STATUS_COMMON_RUNNING | | 165 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
263 | ZFCP_STATUS_COMMON_ERP_FAILED | | 166 | zfcp_unit_get(unit); |
264 | clear_mask, id, ref); | 167 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); |
168 | erp_action = &unit->erp_action; | ||
169 | if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) | ||
170 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | ||
171 | break; | ||
265 | 172 | ||
266 | return retval; | 173 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
267 | } | 174 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
175 | zfcp_port_get(port); | ||
176 | zfcp_erp_action_dismiss_port(port); | ||
177 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); | ||
178 | erp_action = &port->erp_action; | ||
179 | if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) | ||
180 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | ||
181 | break; | ||
268 | 182 | ||
269 | int zfcp_erp_port_shutdown(struct zfcp_port *port, int clear_mask, u8 id, | 183 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
270 | void *ref) | 184 | zfcp_adapter_get(adapter); |
271 | { | 185 | zfcp_erp_action_dismiss_adapter(adapter); |
272 | int retval; | 186 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); |
187 | erp_action = &adapter->erp_action; | ||
188 | if (!(atomic_read(&adapter->status) & | ||
189 | ZFCP_STATUS_COMMON_RUNNING)) | ||
190 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | ||
191 | break; | ||
273 | 192 | ||
274 | retval = zfcp_erp_port_reopen(port, | 193 | default: |
275 | ZFCP_STATUS_COMMON_RUNNING | | 194 | return NULL; |
276 | ZFCP_STATUS_COMMON_ERP_FAILED | | 195 | } |
277 | clear_mask, id, ref); | ||
278 | 196 | ||
279 | return retval; | 197 | memset(erp_action, 0, sizeof(struct zfcp_erp_action)); |
198 | erp_action->adapter = adapter; | ||
199 | erp_action->port = port; | ||
200 | erp_action->unit = unit; | ||
201 | erp_action->action = need; | ||
202 | erp_action->status = status; | ||
203 | |||
204 | return erp_action; | ||
280 | } | 205 | } |
281 | 206 | ||
282 | int zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask, u8 id, | 207 | static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, |
283 | void *ref) | 208 | struct zfcp_port *port, |
209 | struct zfcp_unit *unit, u8 id, void *ref) | ||
284 | { | 210 | { |
285 | int retval; | 211 | int retval = 1, need; |
212 | struct zfcp_erp_action *act = NULL; | ||
213 | |||
214 | if (!(atomic_read(&adapter->status) & | ||
215 | ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)) | ||
216 | return -EIO; | ||
286 | 217 | ||
287 | retval = zfcp_erp_unit_reopen(unit, | 218 | need = zfcp_erp_required_act(want, adapter, port, unit); |
288 | ZFCP_STATUS_COMMON_RUNNING | | 219 | if (!need) |
289 | ZFCP_STATUS_COMMON_ERP_FAILED | | 220 | goto out; |
290 | clear_mask, id, ref); | ||
291 | 221 | ||
222 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); | ||
223 | act = zfcp_erp_setup_act(need, adapter, port, unit); | ||
224 | if (!act) | ||
225 | goto out; | ||
226 | ++adapter->erp_total_count; | ||
227 | list_add_tail(&act->list, &adapter->erp_ready_head); | ||
228 | up(&adapter->erp_ready_sem); | ||
229 | zfcp_rec_dbf_event_thread(1, adapter); | ||
230 | retval = 0; | ||
231 | out: | ||
232 | zfcp_rec_dbf_event_trigger(id, ref, want, need, act, | ||
233 | adapter, port, unit); | ||
292 | return retval; | 234 | return retval; |
293 | } | 235 | } |
294 | 236 | ||
295 | 237 | static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, | |
296 | /** | 238 | int clear_mask, u8 id, void *ref) |
297 | * zfcp_erp_adisc - send ADISC ELS command | ||
298 | * @port: port structure | ||
299 | */ | ||
300 | static int | ||
301 | zfcp_erp_adisc(struct zfcp_port *port) | ||
302 | { | 239 | { |
303 | struct zfcp_adapter *adapter = port->adapter; | 240 | zfcp_erp_adapter_block(adapter, clear_mask); |
304 | struct zfcp_send_els *send_els; | ||
305 | struct zfcp_ls_adisc *adisc; | ||
306 | void *address = NULL; | ||
307 | int retval = 0; | ||
308 | |||
309 | send_els = kzalloc(sizeof(struct zfcp_send_els), GFP_ATOMIC); | ||
310 | if (send_els == NULL) | ||
311 | goto nomem; | ||
312 | |||
313 | send_els->req = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC); | ||
314 | if (send_els->req == NULL) | ||
315 | goto nomem; | ||
316 | sg_init_table(send_els->req, 1); | ||
317 | |||
318 | send_els->resp = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC); | ||
319 | if (send_els->resp == NULL) | ||
320 | goto nomem; | ||
321 | sg_init_table(send_els->resp, 1); | ||
322 | |||
323 | address = (void *) get_zeroed_page(GFP_ATOMIC); | ||
324 | if (address == NULL) | ||
325 | goto nomem; | ||
326 | |||
327 | zfcp_address_to_sg(address, send_els->req, sizeof(struct zfcp_ls_adisc)); | ||
328 | address += PAGE_SIZE >> 1; | ||
329 | zfcp_address_to_sg(address, send_els->resp, sizeof(struct zfcp_ls_adisc_acc)); | ||
330 | send_els->req_count = send_els->resp_count = 1; | ||
331 | |||
332 | send_els->adapter = adapter; | ||
333 | send_els->port = port; | ||
334 | send_els->d_id = port->d_id; | ||
335 | send_els->handler = zfcp_erp_adisc_handler; | ||
336 | send_els->handler_data = (unsigned long) send_els; | ||
337 | |||
338 | adisc = zfcp_sg_to_address(send_els->req); | ||
339 | send_els->ls_code = adisc->code = ZFCP_LS_ADISC; | ||
340 | |||
341 | /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports | ||
342 | without FC-AL-2 capability, so we don't set it */ | ||
343 | adisc->wwpn = fc_host_port_name(adapter->scsi_host); | ||
344 | adisc->wwnn = fc_host_node_name(adapter->scsi_host); | ||
345 | adisc->nport_id = fc_host_port_id(adapter->scsi_host); | ||
346 | ZFCP_LOG_INFO("ADISC request from s_id 0x%06x to d_id 0x%06x " | ||
347 | "(wwpn=0x%016Lx, wwnn=0x%016Lx, " | ||
348 | "hard_nport_id=0x%06x, nport_id=0x%06x)\n", | ||
349 | adisc->nport_id, send_els->d_id, (wwn_t) adisc->wwpn, | ||
350 | (wwn_t) adisc->wwnn, adisc->hard_nport_id, | ||
351 | adisc->nport_id); | ||
352 | |||
353 | retval = zfcp_fsf_send_els(send_els); | ||
354 | if (retval != 0) { | ||
355 | ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port " | ||
356 | "0x%06x on adapter %s\n", send_els->d_id, | ||
357 | zfcp_get_busid_by_adapter(adapter)); | ||
358 | goto freemem; | ||
359 | } | ||
360 | 241 | ||
361 | goto out; | 242 | /* ensure propagation of failed status to new devices */ |
362 | 243 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { | |
363 | nomem: | 244 | zfcp_erp_adapter_failed(adapter, 13, NULL); |
364 | retval = -ENOMEM; | 245 | return -EIO; |
365 | freemem: | ||
366 | if (address != NULL) | ||
367 | __free_pages(sg_page(send_els->req), 0); | ||
368 | if (send_els != NULL) { | ||
369 | kfree(send_els->req); | ||
370 | kfree(send_els->resp); | ||
371 | kfree(send_els); | ||
372 | } | 246 | } |
373 | out: | 247 | return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, |
374 | return retval; | 248 | adapter, NULL, NULL, id, ref); |
375 | } | 249 | } |
376 | 250 | ||
377 | |||
378 | /** | 251 | /** |
379 | * zfcp_erp_adisc_handler - handler for ADISC ELS command | 252 | * zfcp_erp_adapter_reopen - Reopen adapter. |
380 | * @data: pointer to struct zfcp_send_els | 253 | * @adapter: Adapter to reopen. |
381 | * | 254 | * @clear: Status flags to clear. |
382 | * If ADISC failed (LS_RJT or timed out) forced reopen of the port is triggered. | 255 | * @id: Id for debug trace event. |
256 | * @ref: Reference for debug trace event. | ||
383 | */ | 257 | */ |
384 | static void | 258 | void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, |
385 | zfcp_erp_adisc_handler(unsigned long data) | 259 | u8 id, void *ref) |
386 | { | 260 | { |
387 | struct zfcp_send_els *send_els; | 261 | unsigned long flags; |
388 | struct zfcp_port *port; | ||
389 | struct zfcp_adapter *adapter; | ||
390 | u32 d_id; | ||
391 | struct zfcp_ls_adisc_acc *adisc; | ||
392 | |||
393 | send_els = (struct zfcp_send_els *) data; | ||
394 | adapter = send_els->adapter; | ||
395 | port = send_els->port; | ||
396 | d_id = send_els->d_id; | ||
397 | |||
398 | /* request rejected or timed out */ | ||
399 | if (send_els->status != 0) { | ||
400 | ZFCP_LOG_NORMAL("ELS request rejected/timed out, " | ||
401 | "force physical port reopen " | ||
402 | "(adapter %s, port d_id=0x%06x)\n", | ||
403 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
404 | if (zfcp_erp_port_forced_reopen(port, 0, 63, NULL)) | ||
405 | ZFCP_LOG_NORMAL("failed reopen of port " | ||
406 | "(adapter %s, wwpn=0x%016Lx)\n", | ||
407 | zfcp_get_busid_by_port(port), | ||
408 | port->wwpn); | ||
409 | goto out; | ||
410 | } | ||
411 | |||
412 | adisc = zfcp_sg_to_address(send_els->resp); | ||
413 | |||
414 | ZFCP_LOG_INFO("ADISC response from d_id 0x%06x to s_id " | ||
415 | "0x%06x (wwpn=0x%016Lx, wwnn=0x%016Lx, " | ||
416 | "hard_nport_id=0x%06x, nport_id=0x%06x)\n", | ||
417 | d_id, fc_host_port_id(adapter->scsi_host), | ||
418 | (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn, | ||
419 | adisc->hard_nport_id, adisc->nport_id); | ||
420 | |||
421 | /* set wwnn for port */ | ||
422 | if (port->wwnn == 0) | ||
423 | port->wwnn = adisc->wwnn; | ||
424 | |||
425 | if (port->wwpn != adisc->wwpn) { | ||
426 | ZFCP_LOG_NORMAL("d_id assignment changed, reopening " | ||
427 | "port (adapter %s, wwpn=0x%016Lx, " | ||
428 | "adisc_resp_wwpn=0x%016Lx)\n", | ||
429 | zfcp_get_busid_by_port(port), | ||
430 | port->wwpn, (wwn_t) adisc->wwpn); | ||
431 | if (zfcp_erp_port_reopen(port, 0, 64, NULL)) | ||
432 | ZFCP_LOG_NORMAL("failed reopen of port " | ||
433 | "(adapter %s, wwpn=0x%016Lx)\n", | ||
434 | zfcp_get_busid_by_port(port), | ||
435 | port->wwpn); | ||
436 | } | ||
437 | 262 | ||
438 | out: | 263 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
439 | zfcp_port_put(port); | 264 | write_lock(&adapter->erp_lock); |
440 | __free_pages(sg_page(send_els->req), 0); | 265 | _zfcp_erp_adapter_reopen(adapter, clear, id, ref); |
441 | kfree(send_els->req); | 266 | write_unlock(&adapter->erp_lock); |
442 | kfree(send_els->resp); | 267 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
443 | kfree(send_els); | ||
444 | } | 268 | } |
445 | 269 | ||
446 | |||
447 | /** | 270 | /** |
448 | * zfcp_test_link - lightweight link test procedure | 271 | * zfcp_erp_adapter_shutdown - Shutdown adapter. |
449 | * @port: port to be tested | 272 | * @adapter: Adapter to shut down. |
450 | * | 273 | * @clear: Status flags to clear. |
451 | * Test status of a link to a remote port using the ELS command ADISC. | 274 | * @id: Id for debug trace event. |
275 | * @ref: Reference for debug trace event. | ||
452 | */ | 276 | */ |
453 | int | 277 | void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, |
454 | zfcp_test_link(struct zfcp_port *port) | 278 | u8 id, void *ref) |
455 | { | 279 | { |
456 | int retval; | 280 | int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; |
457 | 281 | zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref); | |
458 | zfcp_port_get(port); | ||
459 | retval = zfcp_erp_adisc(port); | ||
460 | if (retval != 0 && retval != -EBUSY) { | ||
461 | zfcp_port_put(port); | ||
462 | ZFCP_LOG_NORMAL("reopen needed for port 0x%016Lx " | ||
463 | "on adapter %s\n ", port->wwpn, | ||
464 | zfcp_get_busid_by_port(port)); | ||
465 | retval = zfcp_erp_port_forced_reopen(port, 0, 65, NULL); | ||
466 | if (retval != 0) { | ||
467 | ZFCP_LOG_NORMAL("reopen of remote port 0x%016Lx " | ||
468 | "on adapter %s failed\n", port->wwpn, | ||
469 | zfcp_get_busid_by_port(port)); | ||
470 | retval = -EPERM; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | return retval; | ||
475 | } | 282 | } |
476 | 283 | ||
477 | 284 | /** | |
478 | /* | 285 | * zfcp_erp_port_shutdown - Shutdown port |
479 | * function: | 286 | * @port: Port to shut down. |
480 | * | 287 | * @clear: Status flags to clear. |
481 | * purpose: called if a port failed to be opened normally | 288 | * @id: Id for debug trace event. |
482 | * initiates Forced Reopen recovery which is done | 289 | * @ref: Reference for debug trace event. |
483 | * asynchronously | ||
484 | * | ||
485 | * returns: 0 - initiated action successfully | ||
486 | * <0 - failed to initiate action | ||
487 | */ | 290 | */ |
488 | static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port, | 291 | void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, u8 id, void *ref) |
489 | int clear_mask, u8 id, | ||
490 | void *ref) | ||
491 | { | 292 | { |
492 | int retval; | 293 | int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; |
294 | zfcp_erp_port_reopen(port, clear | flags, id, ref); | ||
295 | } | ||
493 | 296 | ||
494 | ZFCP_LOG_DEBUG("forced reopen of port 0x%016Lx on adapter %s\n", | 297 | /** |
495 | port->wwpn, zfcp_get_busid_by_port(port)); | 298 | * zfcp_erp_unit_shutdown - Shutdown unit |
299 | * @unit: Unit to shut down. | ||
300 | * @clear: Status flags to clear. | ||
301 | * @id: Id for debug trace event. | ||
302 | * @ref: Reference for debug trace event. | ||
303 | */ | ||
304 | void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, u8 id, void *ref) | ||
305 | { | ||
306 | int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; | ||
307 | zfcp_erp_unit_reopen(unit, clear | flags, id, ref); | ||
308 | } | ||
496 | 309 | ||
497 | zfcp_erp_port_block(port, clear_mask); | 310 | static void zfcp_erp_port_block(struct zfcp_port *port, int clear) |
311 | { | ||
312 | zfcp_erp_modify_port_status(port, 17, NULL, | ||
313 | ZFCP_STATUS_COMMON_UNBLOCKED | clear, | ||
314 | ZFCP_CLEAR); | ||
315 | } | ||
498 | 316 | ||
499 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { | 317 | static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, |
500 | ZFCP_LOG_DEBUG("skipped forced reopen of failed port 0x%016Lx " | 318 | int clear, u8 id, void *ref) |
501 | "on adapter %s\n", port->wwpn, | 319 | { |
502 | zfcp_get_busid_by_port(port)); | 320 | zfcp_erp_port_block(port, clear); |
503 | retval = -EIO; | ||
504 | goto out; | ||
505 | } | ||
506 | 321 | ||
507 | retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, | 322 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) |
508 | port->adapter, port, NULL, id, ref); | 323 | return; |
509 | 324 | ||
510 | out: | 325 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, |
511 | return retval; | 326 | port->adapter, port, NULL, id, ref); |
512 | } | 327 | } |
513 | 328 | ||
514 | /* | 329 | /** |
515 | * function: | 330 | * zfcp_erp_port_forced_reopen - Forced close of port and open again |
516 | * | 331 | * @port: Port to force close and to reopen. |
517 | * purpose: Wrappper for zfcp_erp_port_forced_reopen_internal | 332 | * @id: Id for debug trace event. |
518 | * used to ensure the correct locking | 333 | * @ref: Reference for debug trace event. |
519 | * | ||
520 | * returns: 0 - initiated action successfully | ||
521 | * <0 - failed to initiate action | ||
522 | */ | 334 | */ |
523 | int zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear_mask, u8 id, | 335 | void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, u8 id, |
524 | void *ref) | 336 | void *ref) |
525 | { | 337 | { |
526 | int retval; | ||
527 | unsigned long flags; | 338 | unsigned long flags; |
528 | struct zfcp_adapter *adapter; | 339 | struct zfcp_adapter *adapter = port->adapter; |
529 | 340 | ||
530 | adapter = port->adapter; | ||
531 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 341 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
532 | write_lock(&adapter->erp_lock); | 342 | write_lock(&adapter->erp_lock); |
533 | retval = zfcp_erp_port_forced_reopen_internal(port, clear_mask, id, | 343 | _zfcp_erp_port_forced_reopen(port, clear, id, ref); |
534 | ref); | ||
535 | write_unlock(&adapter->erp_lock); | 344 | write_unlock(&adapter->erp_lock); |
536 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 345 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
537 | |||
538 | return retval; | ||
539 | } | 346 | } |
540 | 347 | ||
541 | /* | 348 | static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id, |
542 | * function: | 349 | void *ref) |
543 | * | ||
544 | * purpose: called if a port is to be opened | ||
545 | * initiates Reopen recovery which is done | ||
546 | * asynchronously | ||
547 | * | ||
548 | * returns: 0 - initiated action successfully | ||
549 | * <0 - failed to initiate action | ||
550 | */ | ||
551 | static int zfcp_erp_port_reopen_internal(struct zfcp_port *port, int clear_mask, | ||
552 | u8 id, void *ref) | ||
553 | { | 350 | { |
554 | int retval; | 351 | zfcp_erp_port_block(port, clear); |
555 | |||
556 | ZFCP_LOG_DEBUG("reopen of port 0x%016Lx on adapter %s\n", | ||
557 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
558 | 352 | ||
559 | zfcp_erp_port_block(port, clear_mask); | 353 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
560 | |||
561 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { | ||
562 | ZFCP_LOG_DEBUG("skipped reopen of failed port 0x%016Lx " | ||
563 | "on adapter %s\n", port->wwpn, | ||
564 | zfcp_get_busid_by_port(port)); | ||
565 | /* ensure propagation of failed status to new devices */ | 354 | /* ensure propagation of failed status to new devices */ |
566 | zfcp_erp_port_failed(port, 14, NULL); | 355 | zfcp_erp_port_failed(port, 14, NULL); |
567 | retval = -EIO; | 356 | return -EIO; |
568 | goto out; | ||
569 | } | 357 | } |
570 | 358 | ||
571 | retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, | 359 | return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, |
572 | port->adapter, port, NULL, id, ref); | 360 | port->adapter, port, NULL, id, ref); |
573 | |||
574 | out: | ||
575 | return retval; | ||
576 | } | 361 | } |
577 | 362 | ||
578 | /** | 363 | /** |
579 | * zfcp_erp_port_reopen - initiate reopen of a remote port | 364 | * zfcp_erp_port_reopen - trigger remote port recovery |
580 | * @port: port to be reopened | 365 | * @port: port to recover |
581 | * @clear_mask: specifies flags in port status to be cleared | 366 | * @clear_mask: flags in port status to be cleared |
582 | * Return: 0 on success, < 0 on error | ||
583 | * | 367 | * |
584 | * This is a wrappper function for zfcp_erp_port_reopen_internal. It ensures | 368 | * Returns 0 if recovery has been triggered, < 0 if not. |
585 | * correct locking. An error recovery task is initiated to do the reopen. | ||
586 | * To wait for the completion of the reopen zfcp_erp_wait should be used. | ||
587 | */ | 369 | */ |
588 | int zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask, u8 id, | 370 | int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id, void *ref) |
589 | void *ref) | ||
590 | { | 371 | { |
591 | int retval; | ||
592 | unsigned long flags; | 372 | unsigned long flags; |
373 | int retval; | ||
593 | struct zfcp_adapter *adapter = port->adapter; | 374 | struct zfcp_adapter *adapter = port->adapter; |
594 | 375 | ||
595 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 376 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
596 | write_lock(&adapter->erp_lock); | 377 | write_lock(&adapter->erp_lock); |
597 | retval = zfcp_erp_port_reopen_internal(port, clear_mask, id, ref); | 378 | retval = _zfcp_erp_port_reopen(port, clear, id, ref); |
598 | write_unlock(&adapter->erp_lock); | 379 | write_unlock(&adapter->erp_lock); |
599 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 380 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
600 | 381 | ||
601 | return retval; | 382 | return retval; |
602 | } | 383 | } |
603 | 384 | ||
604 | /* | 385 | static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) |
605 | * function: | ||
606 | * | ||
607 | * purpose: called if a unit is to be opened | ||
608 | * initiates Reopen recovery which is done | ||
609 | * asynchronously | ||
610 | * | ||
611 | * returns: 0 - initiated action successfully | ||
612 | * <0 - failed to initiate action | ||
613 | */ | ||
614 | static int zfcp_erp_unit_reopen_internal(struct zfcp_unit *unit, int clear_mask, | ||
615 | u8 id, void *ref) | ||
616 | { | 386 | { |
617 | int retval; | 387 | zfcp_erp_modify_unit_status(unit, 19, NULL, |
618 | struct zfcp_adapter *adapter = unit->port->adapter; | 388 | ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, |
389 | ZFCP_CLEAR); | ||
390 | } | ||
619 | 391 | ||
620 | ZFCP_LOG_DEBUG("reopen of unit 0x%016Lx on port 0x%016Lx " | 392 | static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, u8 id, |
621 | "on adapter %s\n", unit->fcp_lun, | 393 | void *ref) |
622 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | 394 | { |
395 | struct zfcp_adapter *adapter = unit->port->adapter; | ||
623 | 396 | ||
624 | zfcp_erp_unit_block(unit, clear_mask); | 397 | zfcp_erp_unit_block(unit, clear); |
625 | 398 | ||
626 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) { | 399 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) |
627 | ZFCP_LOG_DEBUG("skipped reopen of failed unit 0x%016Lx " | 400 | return; |
628 | "on port 0x%016Lx on adapter %s\n", | ||
629 | unit->fcp_lun, unit->port->wwpn, | ||
630 | zfcp_get_busid_by_unit(unit)); | ||
631 | retval = -EIO; | ||
632 | goto out; | ||
633 | } | ||
634 | 401 | ||
635 | retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, | 402 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, |
636 | adapter, unit->port, unit, id, ref); | 403 | adapter, unit->port, unit, id, ref); |
637 | out: | ||
638 | return retval; | ||
639 | } | 404 | } |
640 | 405 | ||
641 | /** | 406 | /** |
@@ -643,987 +408,182 @@ static int zfcp_erp_unit_reopen_internal(struct zfcp_unit *unit, int clear_mask, | |||
643 | * @unit: unit to be reopened | 408 | * @unit: unit to be reopened |
644 | * @clear_mask: specifies flags in unit status to be cleared | 409 | * @clear_mask: specifies flags in unit status to be cleared |
645 | * Return: 0 on success, < 0 on error | 410 | * Return: 0 on success, < 0 on error |
646 | * | ||
647 | * This is a wrappper for zfcp_erp_unit_reopen_internal. It ensures correct | ||
648 | * locking. An error recovery task is initiated to do the reopen. | ||
649 | * To wait for the completion of the reopen zfcp_erp_wait should be used. | ||
650 | */ | 411 | */ |
651 | int zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear_mask, u8 id, | 412 | void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, u8 id, void *ref) |
652 | void *ref) | ||
653 | { | 413 | { |
654 | int retval; | ||
655 | unsigned long flags; | 414 | unsigned long flags; |
656 | struct zfcp_adapter *adapter; | 415 | struct zfcp_port *port = unit->port; |
657 | struct zfcp_port *port; | 416 | struct zfcp_adapter *adapter = port->adapter; |
658 | |||
659 | port = unit->port; | ||
660 | adapter = port->adapter; | ||
661 | 417 | ||
662 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 418 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
663 | write_lock(&adapter->erp_lock); | 419 | write_lock(&adapter->erp_lock); |
664 | retval = zfcp_erp_unit_reopen_internal(unit, clear_mask, id, ref); | 420 | _zfcp_erp_unit_reopen(unit, clear, id, ref); |
665 | write_unlock(&adapter->erp_lock); | 421 | write_unlock(&adapter->erp_lock); |
666 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 422 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
667 | |||
668 | return retval; | ||
669 | } | 423 | } |
670 | 424 | ||
671 | /** | 425 | static int status_change_set(unsigned long mask, atomic_t *status) |
672 | * zfcp_erp_adapter_block - mark adapter as blocked, block scsi requests | ||
673 | */ | ||
674 | static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask) | ||
675 | { | ||
676 | zfcp_erp_modify_adapter_status(adapter, 15, NULL, | ||
677 | ZFCP_STATUS_COMMON_UNBLOCKED | | ||
678 | clear_mask, ZFCP_CLEAR); | ||
679 | } | ||
680 | |||
681 | /* FIXME: isn't really atomic */ | ||
682 | /* | ||
683 | * returns the mask which has not been set so far, i.e. | ||
684 | * 0 if no bit has been changed, !0 if some bit has been changed | ||
685 | */ | ||
686 | static int atomic_test_and_set_mask(unsigned long mask, atomic_t *v) | ||
687 | { | 426 | { |
688 | int changed_bits = (atomic_read(v) /*XOR*/^ mask) & mask; | 427 | return (atomic_read(status) ^ mask) & mask; |
689 | atomic_set_mask(mask, v); | ||
690 | return changed_bits; | ||
691 | } | 428 | } |
692 | 429 | ||
693 | /* FIXME: isn't really atomic */ | 430 | static int status_change_clear(unsigned long mask, atomic_t *status) |
694 | /* | ||
695 | * returns the mask which has not been cleared so far, i.e. | ||
696 | * 0 if no bit has been changed, !0 if some bit has been changed | ||
697 | */ | ||
698 | static int atomic_test_and_clear_mask(unsigned long mask, atomic_t *v) | ||
699 | { | 431 | { |
700 | int changed_bits = atomic_read(v) & mask; | 432 | return atomic_read(status) & mask; |
701 | atomic_clear_mask(mask, v); | ||
702 | return changed_bits; | ||
703 | } | 433 | } |
704 | 434 | ||
705 | /** | ||
706 | * zfcp_erp_adapter_unblock - mark adapter as unblocked, allow scsi requests | ||
707 | */ | ||
708 | static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) | 435 | static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) |
709 | { | 436 | { |
710 | if (atomic_test_and_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | 437 | if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) |
711 | &adapter->status)) | ||
712 | zfcp_rec_dbf_event_adapter(16, NULL, adapter); | 438 | zfcp_rec_dbf_event_adapter(16, NULL, adapter); |
439 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); | ||
713 | } | 440 | } |
714 | 441 | ||
715 | /* | 442 | static void zfcp_erp_port_unblock(struct zfcp_port *port) |
716 | * function: | ||
717 | * | ||
718 | * purpose: disable I/O, | ||
719 | * return any open requests and clean them up, | ||
720 | * aim: no pending and incoming I/O | ||
721 | * | ||
722 | * returns: | ||
723 | */ | ||
724 | static void | ||
725 | zfcp_erp_port_block(struct zfcp_port *port, int clear_mask) | ||
726 | { | ||
727 | zfcp_erp_modify_port_status(port, 17, NULL, | ||
728 | ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, | ||
729 | ZFCP_CLEAR); | ||
730 | } | ||
731 | |||
732 | /* | ||
733 | * function: | ||
734 | * | ||
735 | * purpose: enable I/O | ||
736 | * | ||
737 | * returns: | ||
738 | */ | ||
739 | static void | ||
740 | zfcp_erp_port_unblock(struct zfcp_port *port) | ||
741 | { | 443 | { |
742 | if (atomic_test_and_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | 444 | if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) |
743 | &port->status)) | ||
744 | zfcp_rec_dbf_event_port(18, NULL, port); | 445 | zfcp_rec_dbf_event_port(18, NULL, port); |
446 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); | ||
745 | } | 447 | } |
746 | 448 | ||
747 | /* | 449 | static void zfcp_erp_unit_unblock(struct zfcp_unit *unit) |
748 | * function: | ||
749 | * | ||
750 | * purpose: disable I/O, | ||
751 | * return any open requests and clean them up, | ||
752 | * aim: no pending and incoming I/O | ||
753 | * | ||
754 | * returns: | ||
755 | */ | ||
756 | static void | ||
757 | zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) | ||
758 | { | ||
759 | zfcp_erp_modify_unit_status(unit, 19, NULL, | ||
760 | ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, | ||
761 | ZFCP_CLEAR); | ||
762 | } | ||
763 | |||
764 | /* | ||
765 | * function: | ||
766 | * | ||
767 | * purpose: enable I/O | ||
768 | * | ||
769 | * returns: | ||
770 | */ | ||
771 | static void | ||
772 | zfcp_erp_unit_unblock(struct zfcp_unit *unit) | ||
773 | { | 450 | { |
774 | if (atomic_test_and_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | 451 | if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) |
775 | &unit->status)) | ||
776 | zfcp_rec_dbf_event_unit(20, NULL, unit); | 452 | zfcp_rec_dbf_event_unit(20, NULL, unit); |
453 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status); | ||
777 | } | 454 | } |
778 | 455 | ||
779 | static void | 456 | static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) |
780 | zfcp_erp_action_ready(struct zfcp_erp_action *erp_action) | ||
781 | { | 457 | { |
782 | struct zfcp_adapter *adapter = erp_action->adapter; | 458 | list_move(&erp_action->list, &erp_action->adapter->erp_running_head); |
783 | 459 | zfcp_rec_dbf_event_action(145, erp_action); | |
784 | zfcp_erp_action_to_ready(erp_action); | ||
785 | up(&adapter->erp_ready_sem); | ||
786 | zfcp_rec_dbf_event_thread(2, adapter, 0); | ||
787 | } | 460 | } |
788 | 461 | ||
789 | /* | 462 | static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) |
790 | * function: | ||
791 | * | ||
792 | * purpose: | ||
793 | * | ||
794 | * returns: <0 erp_action not found in any list | ||
795 | * ZFCP_ERP_ACTION_READY erp_action is in ready list | ||
796 | * ZFCP_ERP_ACTION_RUNNING erp_action is in running list | ||
797 | * | ||
798 | * locks: erp_lock must be held | ||
799 | */ | ||
800 | static int | ||
801 | zfcp_erp_action_exists(struct zfcp_erp_action *erp_action) | ||
802 | { | 463 | { |
803 | int retval = -EINVAL; | 464 | struct zfcp_adapter *adapter = act->adapter; |
804 | struct list_head *entry; | ||
805 | struct zfcp_erp_action *entry_erp_action; | ||
806 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
807 | |||
808 | /* search in running list */ | ||
809 | list_for_each(entry, &adapter->erp_running_head) { | ||
810 | entry_erp_action = | ||
811 | list_entry(entry, struct zfcp_erp_action, list); | ||
812 | if (entry_erp_action == erp_action) { | ||
813 | retval = ZFCP_ERP_ACTION_RUNNING; | ||
814 | goto out; | ||
815 | } | ||
816 | } | ||
817 | /* search in ready list */ | ||
818 | list_for_each(entry, &adapter->erp_ready_head) { | ||
819 | entry_erp_action = | ||
820 | list_entry(entry, struct zfcp_erp_action, list); | ||
821 | if (entry_erp_action == erp_action) { | ||
822 | retval = ZFCP_ERP_ACTION_READY; | ||
823 | goto out; | ||
824 | } | ||
825 | } | ||
826 | 465 | ||
827 | out: | 466 | if (!act->fsf_req) |
828 | return retval; | 467 | return; |
829 | } | ||
830 | |||
831 | /* | ||
832 | * purpose: checks current status of action (timed out, dismissed, ...) | ||
833 | * and does appropriate preparations (dismiss fsf request, ...) | ||
834 | * | ||
835 | * locks: called under erp_lock (disabled interrupts) | ||
836 | */ | ||
837 | static void | ||
838 | zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) | ||
839 | { | ||
840 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
841 | 468 | ||
842 | if (erp_action->fsf_req) { | 469 | spin_lock(&adapter->req_list_lock); |
843 | /* take lock to ensure that request is not deleted meanwhile */ | 470 | if (zfcp_reqlist_find_safe(adapter, act->fsf_req) && |
844 | spin_lock(&adapter->req_list_lock); | 471 | act->fsf_req->erp_action == act) { |
845 | if (zfcp_reqlist_find_safe(adapter, erp_action->fsf_req) && | 472 | if (act->status & (ZFCP_STATUS_ERP_DISMISSED | |
846 | erp_action->fsf_req->erp_action == erp_action) { | 473 | ZFCP_STATUS_ERP_TIMEDOUT)) { |
847 | /* fsf_req still exists */ | 474 | act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; |
848 | /* dismiss fsf_req of timed out/dismissed erp_action */ | 475 | zfcp_rec_dbf_event_action(142, act); |
849 | if (erp_action->status & (ZFCP_STATUS_ERP_DISMISSED | | ||
850 | ZFCP_STATUS_ERP_TIMEDOUT)) { | ||
851 | erp_action->fsf_req->status |= | ||
852 | ZFCP_STATUS_FSFREQ_DISMISSED; | ||
853 | zfcp_rec_dbf_event_action(142, erp_action); | ||
854 | } | ||
855 | if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { | ||
856 | zfcp_rec_dbf_event_action(143, erp_action); | ||
857 | ZFCP_LOG_NORMAL("error: erp step timed out " | ||
858 | "(action=%d, fsf_req=%p)\n ", | ||
859 | erp_action->action, | ||
860 | erp_action->fsf_req); | ||
861 | } | ||
862 | /* | ||
863 | * If fsf_req is neither dismissed nor completed | ||
864 | * then keep it running asynchronously and don't mess | ||
865 | * with the association of erp_action and fsf_req. | ||
866 | */ | ||
867 | if (erp_action->fsf_req->status & | ||
868 | (ZFCP_STATUS_FSFREQ_COMPLETED | | ||
869 | ZFCP_STATUS_FSFREQ_DISMISSED)) { | ||
870 | /* forget about association between fsf_req | ||
871 | and erp_action */ | ||
872 | erp_action->fsf_req = NULL; | ||
873 | } | ||
874 | } else { | ||
875 | /* | ||
876 | * even if this fsf_req has gone, forget about | ||
877 | * association between erp_action and fsf_req | ||
878 | */ | ||
879 | erp_action->fsf_req = NULL; | ||
880 | } | 476 | } |
881 | spin_unlock(&adapter->req_list_lock); | 477 | if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) |
882 | } | 478 | zfcp_rec_dbf_event_action(143, act); |
479 | if (act->fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED | | ||
480 | ZFCP_STATUS_FSFREQ_DISMISSED)) | ||
481 | act->fsf_req = NULL; | ||
482 | } else | ||
483 | act->fsf_req = NULL; | ||
484 | spin_unlock(&adapter->req_list_lock); | ||
883 | } | 485 | } |
884 | 486 | ||
885 | /** | 487 | /** |
886 | * zfcp_erp_async_handler_nolock - complete erp_action | 488 | * zfcp_erp_notify - Trigger ERP action. |
887 | * | 489 | * @erp_action: ERP action to continue. |
888 | * Used for normal completion, time-out, dismissal and failure after | 490 | * @set_mask: ERP action status flags to set. |
889 | * low memory condition. | ||
890 | */ | 491 | */ |
891 | static void zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action, | 492 | void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask) |
892 | unsigned long set_mask) | ||
893 | { | ||
894 | if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) { | ||
895 | erp_action->status |= set_mask; | ||
896 | zfcp_erp_action_ready(erp_action); | ||
897 | } else { | ||
898 | /* action is ready or gone - nothing to do */ | ||
899 | } | ||
900 | } | ||
901 | |||
902 | /** | ||
903 | * zfcp_erp_async_handler - wrapper for erp_async_handler_nolock w/ locking | ||
904 | */ | ||
905 | void zfcp_erp_async_handler(struct zfcp_erp_action *erp_action, | ||
906 | unsigned long set_mask) | ||
907 | { | 493 | { |
908 | struct zfcp_adapter *adapter = erp_action->adapter; | 494 | struct zfcp_adapter *adapter = erp_action->adapter; |
909 | unsigned long flags; | 495 | unsigned long flags; |
910 | 496 | ||
911 | write_lock_irqsave(&adapter->erp_lock, flags); | 497 | write_lock_irqsave(&adapter->erp_lock, flags); |
912 | zfcp_erp_async_handler_nolock(erp_action, set_mask); | 498 | if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) { |
913 | write_unlock_irqrestore(&adapter->erp_lock, flags); | 499 | erp_action->status |= set_mask; |
914 | } | ||
915 | |||
916 | /* | ||
917 | * purpose: is called for erp_action which was slept waiting for | ||
918 | * memory becoming avaliable, | ||
919 | * will trigger that this action will be continued | ||
920 | */ | ||
921 | static void | ||
922 | zfcp_erp_memwait_handler(unsigned long data) | ||
923 | { | ||
924 | struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; | ||
925 | |||
926 | zfcp_erp_async_handler(erp_action, 0); | ||
927 | } | ||
928 | |||
929 | /* | ||
930 | * purpose: is called if an asynchronous erp step timed out, | ||
931 | * action gets an appropriate flag and will be processed | ||
932 | * accordingly | ||
933 | */ | ||
934 | static void zfcp_erp_timeout_handler(unsigned long data) | ||
935 | { | ||
936 | struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; | ||
937 | |||
938 | zfcp_erp_async_handler(erp_action, ZFCP_STATUS_ERP_TIMEDOUT); | ||
939 | } | ||
940 | |||
941 | /** | ||
942 | * zfcp_erp_action_dismiss - dismiss an erp_action | ||
943 | * | ||
944 | * adapter->erp_lock must be held | ||
945 | * | ||
946 | * Dismissal of an erp_action is usually required if an erp_action of | ||
947 | * higher priority is generated. | ||
948 | */ | ||
949 | static void zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action) | ||
950 | { | ||
951 | erp_action->status |= ZFCP_STATUS_ERP_DISMISSED; | ||
952 | if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) | ||
953 | zfcp_erp_action_ready(erp_action); | 500 | zfcp_erp_action_ready(erp_action); |
954 | } | ||
955 | |||
956 | int | ||
957 | zfcp_erp_thread_setup(struct zfcp_adapter *adapter) | ||
958 | { | ||
959 | int retval = 0; | ||
960 | |||
961 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
962 | |||
963 | retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); | ||
964 | if (retval < 0) { | ||
965 | ZFCP_LOG_NORMAL("error: creation of erp thread failed for " | ||
966 | "adapter %s\n", | ||
967 | zfcp_get_busid_by_adapter(adapter)); | ||
968 | } else { | ||
969 | wait_event(adapter->erp_thread_wqh, | ||
970 | atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, | ||
971 | &adapter->status)); | ||
972 | } | 501 | } |
973 | 502 | write_unlock_irqrestore(&adapter->erp_lock, flags); | |
974 | return (retval < 0); | ||
975 | } | ||
976 | |||
977 | /* | ||
978 | * function: | ||
979 | * | ||
980 | * purpose: | ||
981 | * | ||
982 | * returns: | ||
983 | * | ||
984 | * context: process (i.e. proc-fs or rmmod/insmod) | ||
985 | * | ||
986 | * note: The caller of this routine ensures that the specified | ||
987 | * adapter has been shut down and that this operation | ||
988 | * has been completed. Thus, there are no pending erp_actions | ||
989 | * which would need to be handled here. | ||
990 | */ | ||
991 | int | ||
992 | zfcp_erp_thread_kill(struct zfcp_adapter *adapter) | ||
993 | { | ||
994 | int retval = 0; | ||
995 | |||
996 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); | ||
997 | up(&adapter->erp_ready_sem); | ||
998 | zfcp_rec_dbf_event_thread(2, adapter, 1); | ||
999 | |||
1000 | wait_event(adapter->erp_thread_wqh, | ||
1001 | !atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, | ||
1002 | &adapter->status)); | ||
1003 | |||
1004 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, | ||
1005 | &adapter->status); | ||
1006 | |||
1007 | return retval; | ||
1008 | } | ||
1009 | |||
1010 | /* | ||
1011 | * purpose: is run as a kernel thread, | ||
1012 | * goes through list of error recovery actions of associated adapter | ||
1013 | * and delegates single action to execution | ||
1014 | * | ||
1015 | * returns: 0 | ||
1016 | */ | ||
1017 | static int | ||
1018 | zfcp_erp_thread(void *data) | ||
1019 | { | ||
1020 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; | ||
1021 | struct list_head *next; | ||
1022 | struct zfcp_erp_action *erp_action; | ||
1023 | unsigned long flags; | ||
1024 | |||
1025 | daemonize("zfcperp%s", zfcp_get_busid_by_adapter(adapter)); | ||
1026 | /* Block all signals */ | ||
1027 | siginitsetinv(¤t->blocked, 0); | ||
1028 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
1029 | wake_up(&adapter->erp_thread_wqh); | ||
1030 | |||
1031 | while (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, | ||
1032 | &adapter->status)) { | ||
1033 | |||
1034 | write_lock_irqsave(&adapter->erp_lock, flags); | ||
1035 | next = adapter->erp_ready_head.next; | ||
1036 | write_unlock_irqrestore(&adapter->erp_lock, flags); | ||
1037 | |||
1038 | if (next != &adapter->erp_ready_head) { | ||
1039 | erp_action = | ||
1040 | list_entry(next, struct zfcp_erp_action, list); | ||
1041 | /* | ||
1042 | * process action (incl. [re]moving it | ||
1043 | * from 'ready' queue) | ||
1044 | */ | ||
1045 | zfcp_erp_strategy(erp_action); | ||
1046 | } | ||
1047 | |||
1048 | /* | ||
1049 | * sleep as long as there is nothing to do, i.e. | ||
1050 | * no action in 'ready' queue to be processed and | ||
1051 | * thread is not to be killed | ||
1052 | */ | ||
1053 | zfcp_rec_dbf_event_thread(4, adapter, 1); | ||
1054 | down_interruptible(&adapter->erp_ready_sem); | ||
1055 | zfcp_rec_dbf_event_thread(5, adapter, 1); | ||
1056 | } | ||
1057 | |||
1058 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
1059 | wake_up(&adapter->erp_thread_wqh); | ||
1060 | |||
1061 | return 0; | ||
1062 | } | ||
1063 | |||
1064 | /* | ||
1065 | * function: | ||
1066 | * | ||
1067 | * purpose: drives single error recovery action and schedules higher and | ||
1068 | * subordinate actions, if necessary | ||
1069 | * | ||
1070 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
1071 | * ZFCP_ERP_SUCCEEDED - action finished successfully (deqd) | ||
1072 | * ZFCP_ERP_FAILED - action finished unsuccessfully (deqd) | ||
1073 | * ZFCP_ERP_EXIT - action finished (dequeued), offline | ||
1074 | * ZFCP_ERP_DISMISSED - action canceled (dequeued) | ||
1075 | */ | ||
1076 | static int | ||
1077 | zfcp_erp_strategy(struct zfcp_erp_action *erp_action) | ||
1078 | { | ||
1079 | int retval = 0; | ||
1080 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1081 | struct zfcp_port *port = erp_action->port; | ||
1082 | struct zfcp_unit *unit = erp_action->unit; | ||
1083 | int action = erp_action->action; | ||
1084 | u32 status = erp_action->status; | ||
1085 | unsigned long flags; | ||
1086 | |||
1087 | /* serialise dismissing, timing out, moving, enqueueing */ | ||
1088 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1089 | write_lock(&adapter->erp_lock); | ||
1090 | |||
1091 | /* dequeue dismissed action and leave, if required */ | ||
1092 | retval = zfcp_erp_strategy_check_action(erp_action, retval); | ||
1093 | if (retval == ZFCP_ERP_DISMISSED) { | ||
1094 | goto unlock; | ||
1095 | } | ||
1096 | |||
1097 | /* | ||
1098 | * move action to 'running' queue before processing it | ||
1099 | * (to avoid a race condition regarding moving the | ||
1100 | * action to the 'running' queue and back) | ||
1101 | */ | ||
1102 | zfcp_erp_action_to_running(erp_action); | ||
1103 | |||
1104 | /* | ||
1105 | * try to process action as far as possible, | ||
1106 | * no lock to allow for blocking operations (kmalloc, qdio, ...), | ||
1107 | * afterwards the lock is required again for the following reasons: | ||
1108 | * - dequeueing of finished action and enqueueing of | ||
1109 | * follow-up actions must be atomic so that any other | ||
1110 | * reopen-routine does not believe there is nothing to do | ||
1111 | * and that it is safe to enqueue something else, | ||
1112 | * - we want to force any control thread which is dismissing | ||
1113 | * actions to finish this before we decide about | ||
1114 | * necessary steps to be taken here further | ||
1115 | */ | ||
1116 | write_unlock(&adapter->erp_lock); | ||
1117 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1118 | retval = zfcp_erp_strategy_do_action(erp_action); | ||
1119 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1120 | write_lock(&adapter->erp_lock); | ||
1121 | |||
1122 | /* | ||
1123 | * check for dismissed status again to avoid follow-up actions, | ||
1124 | * failing of targets and so on for dismissed actions, | ||
1125 | * we go through down() here because there has been an up() | ||
1126 | */ | ||
1127 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) | ||
1128 | retval = ZFCP_ERP_CONTINUES; | ||
1129 | |||
1130 | switch (retval) { | ||
1131 | case ZFCP_ERP_NOMEM: | ||
1132 | /* no memory to continue immediately, let it sleep */ | ||
1133 | if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { | ||
1134 | ++adapter->erp_low_mem_count; | ||
1135 | erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; | ||
1136 | } | ||
1137 | /* This condition is true if there is no memory available | ||
1138 | for any erp_action on this adapter. This implies that there | ||
1139 | are no elements in the memory pool(s) left for erp_actions. | ||
1140 | This might happen if an erp_action that used a memory pool | ||
1141 | element was timed out. | ||
1142 | */ | ||
1143 | if (adapter->erp_total_count == adapter->erp_low_mem_count) { | ||
1144 | ZFCP_LOG_NORMAL("error: no mempool elements available, " | ||
1145 | "restarting I/O on adapter %s " | ||
1146 | "to free mempool\n", | ||
1147 | zfcp_get_busid_by_adapter(adapter)); | ||
1148 | zfcp_erp_adapter_reopen_internal(adapter, 0, 66, NULL); | ||
1149 | } else { | ||
1150 | retval = zfcp_erp_strategy_memwait(erp_action); | ||
1151 | } | ||
1152 | goto unlock; | ||
1153 | case ZFCP_ERP_CONTINUES: | ||
1154 | /* leave since this action runs asynchronously */ | ||
1155 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { | ||
1156 | --adapter->erp_low_mem_count; | ||
1157 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; | ||
1158 | } | ||
1159 | goto unlock; | ||
1160 | } | ||
1161 | /* ok, finished action (whatever its result is) */ | ||
1162 | |||
1163 | /* check for unrecoverable targets */ | ||
1164 | retval = zfcp_erp_strategy_check_target(erp_action, retval); | ||
1165 | |||
1166 | /* action must be dequeued (here to allow for further ones) */ | ||
1167 | zfcp_erp_action_dequeue(erp_action); | ||
1168 | |||
1169 | /* | ||
1170 | * put this target through the erp mill again if someone has | ||
1171 | * requested to change the status of a target being online | ||
1172 | * to offline or the other way around | ||
1173 | * (old retval is preserved if nothing has to be done here) | ||
1174 | */ | ||
1175 | retval = zfcp_erp_strategy_statechange(action, status, adapter, | ||
1176 | port, unit, retval); | ||
1177 | |||
1178 | /* | ||
1179 | * leave if target is in permanent error state or if | ||
1180 | * action is repeated in order to process state change | ||
1181 | */ | ||
1182 | if (retval == ZFCP_ERP_EXIT) { | ||
1183 | goto unlock; | ||
1184 | } | ||
1185 | |||
1186 | /* trigger follow up actions */ | ||
1187 | zfcp_erp_strategy_followup_actions(action, adapter, port, unit, retval); | ||
1188 | |||
1189 | unlock: | ||
1190 | write_unlock(&adapter->erp_lock); | ||
1191 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1192 | |||
1193 | if (retval != ZFCP_ERP_CONTINUES) | ||
1194 | zfcp_erp_action_cleanup(action, adapter, port, unit, retval); | ||
1195 | |||
1196 | /* | ||
1197 | * a few tasks remain when the erp queues are empty | ||
1198 | * (don't do that if the last action evaluated was dismissed | ||
1199 | * since this clearly indicates that there is more to come) : | ||
1200 | * - close the name server port if it is open yet | ||
1201 | * (enqueues another [probably] final action) | ||
1202 | * - otherwise, wake up whoever wants to be woken when we are | ||
1203 | * done with erp | ||
1204 | */ | ||
1205 | if (retval != ZFCP_ERP_DISMISSED) | ||
1206 | zfcp_erp_strategy_check_queues(adapter); | ||
1207 | |||
1208 | return retval; | ||
1209 | } | 503 | } |
1210 | 504 | ||
1211 | /* | 505 | /** |
1212 | * function: | 506 | * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request |
1213 | * | 507 | * @data: ERP action (from timer data) |
1214 | * purpose: | ||
1215 | * | ||
1216 | * returns: ZFCP_ERP_DISMISSED - if action has been dismissed | ||
1217 | * retval - otherwise | ||
1218 | */ | 508 | */ |
1219 | static int | 509 | void zfcp_erp_timeout_handler(unsigned long data) |
1220 | zfcp_erp_strategy_check_action(struct zfcp_erp_action *erp_action, int retval) | ||
1221 | { | 510 | { |
1222 | zfcp_erp_strategy_check_fsfreq(erp_action); | 511 | struct zfcp_erp_action *act = (struct zfcp_erp_action *) data; |
1223 | 512 | zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT); | |
1224 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { | ||
1225 | zfcp_erp_action_dequeue(erp_action); | ||
1226 | retval = ZFCP_ERP_DISMISSED; | ||
1227 | } | ||
1228 | |||
1229 | return retval; | ||
1230 | } | 513 | } |
1231 | 514 | ||
1232 | static int | 515 | static void zfcp_erp_memwait_handler(unsigned long data) |
1233 | zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) | ||
1234 | { | 516 | { |
1235 | int retval = ZFCP_ERP_FAILED; | 517 | zfcp_erp_notify((struct zfcp_erp_action *)data, 0); |
1236 | |||
1237 | /* | ||
1238 | * try to execute/continue action as far as possible, | ||
1239 | * note: no lock in subsequent strategy routines | ||
1240 | * (this allows these routine to call schedule, e.g. | ||
1241 | * kmalloc with such flags or qdio_initialize & friends) | ||
1242 | * Note: in case of timeout, the separate strategies will fail | ||
1243 | * anyhow. No need for a special action. Even worse, a nameserver | ||
1244 | * failure would not wake up waiting ports without the call. | ||
1245 | */ | ||
1246 | switch (erp_action->action) { | ||
1247 | |||
1248 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1249 | retval = zfcp_erp_adapter_strategy(erp_action); | ||
1250 | break; | ||
1251 | |||
1252 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
1253 | retval = zfcp_erp_port_forced_strategy(erp_action); | ||
1254 | break; | ||
1255 | |||
1256 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
1257 | retval = zfcp_erp_port_strategy(erp_action); | ||
1258 | break; | ||
1259 | |||
1260 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
1261 | retval = zfcp_erp_unit_strategy(erp_action); | ||
1262 | break; | ||
1263 | |||
1264 | default: | ||
1265 | ZFCP_LOG_NORMAL("bug: unknown erp action requested on " | ||
1266 | "adapter %s (action=%d)\n", | ||
1267 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
1268 | erp_action->action); | ||
1269 | } | ||
1270 | |||
1271 | return retval; | ||
1272 | } | 518 | } |
1273 | 519 | ||
1274 | /* | 520 | static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) |
1275 | * function: | ||
1276 | * | ||
1277 | * purpose: triggers retry of this action after a certain amount of time | ||
1278 | * by means of timer provided by erp_action | ||
1279 | * | ||
1280 | * returns: ZFCP_ERP_CONTINUES - erp_action sleeps in erp running queue | ||
1281 | */ | ||
1282 | static int | ||
1283 | zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) | ||
1284 | { | 521 | { |
1285 | int retval = ZFCP_ERP_CONTINUES; | ||
1286 | |||
1287 | init_timer(&erp_action->timer); | 522 | init_timer(&erp_action->timer); |
1288 | erp_action->timer.function = zfcp_erp_memwait_handler; | 523 | erp_action->timer.function = zfcp_erp_memwait_handler; |
1289 | erp_action->timer.data = (unsigned long) erp_action; | 524 | erp_action->timer.data = (unsigned long) erp_action; |
1290 | erp_action->timer.expires = jiffies + ZFCP_ERP_MEMWAIT_TIMEOUT; | 525 | erp_action->timer.expires = jiffies + HZ; |
1291 | add_timer(&erp_action->timer); | 526 | add_timer(&erp_action->timer); |
1292 | |||
1293 | return retval; | ||
1294 | } | 527 | } |
1295 | 528 | ||
1296 | /* | 529 | static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, |
1297 | * function: zfcp_erp_adapter_failed | 530 | int clear, u8 id, void *ref) |
1298 | * | ||
1299 | * purpose: sets the adapter and all underlying devices to ERP_FAILED | ||
1300 | * | ||
1301 | */ | ||
1302 | void | ||
1303 | zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, u8 id, void *ref) | ||
1304 | { | ||
1305 | zfcp_erp_modify_adapter_status(adapter, id, ref, | ||
1306 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | ||
1307 | ZFCP_LOG_NORMAL("adapter erp failed on adapter %s\n", | ||
1308 | zfcp_get_busid_by_adapter(adapter)); | ||
1309 | } | ||
1310 | |||
1311 | /* | ||
1312 | * function: zfcp_erp_port_failed | ||
1313 | * | ||
1314 | * purpose: sets the port and all underlying devices to ERP_FAILED | ||
1315 | * | ||
1316 | */ | ||
1317 | void | ||
1318 | zfcp_erp_port_failed(struct zfcp_port *port, u8 id, void *ref) | ||
1319 | { | ||
1320 | zfcp_erp_modify_port_status(port, id, ref, | ||
1321 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | ||
1322 | |||
1323 | if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) | ||
1324 | ZFCP_LOG_NORMAL("port erp failed (adapter %s, " | ||
1325 | "port d_id=0x%06x)\n", | ||
1326 | zfcp_get_busid_by_port(port), port->d_id); | ||
1327 | else | ||
1328 | ZFCP_LOG_NORMAL("port erp failed (adapter %s, wwpn=0x%016Lx)\n", | ||
1329 | zfcp_get_busid_by_port(port), port->wwpn); | ||
1330 | } | ||
1331 | |||
1332 | /* | ||
1333 | * function: zfcp_erp_unit_failed | ||
1334 | * | ||
1335 | * purpose: sets the unit to ERP_FAILED | ||
1336 | * | ||
1337 | */ | ||
1338 | void | ||
1339 | zfcp_erp_unit_failed(struct zfcp_unit *unit, u8 id, void *ref) | ||
1340 | { | ||
1341 | zfcp_erp_modify_unit_status(unit, id, ref, | ||
1342 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | ||
1343 | |||
1344 | ZFCP_LOG_NORMAL("unit erp failed on unit 0x%016Lx on port 0x%016Lx " | ||
1345 | " on adapter %s\n", unit->fcp_lun, | ||
1346 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | ||
1347 | } | ||
1348 | |||
1349 | /* | ||
1350 | * function: zfcp_erp_strategy_check_target | ||
1351 | * | ||
1352 | * purpose: increments the erp action count on the device currently in | ||
1353 | * recovery if the action failed or resets the count in case of | ||
1354 | * success. If a maximum count is exceeded the device is marked | ||
1355 | * as ERP_FAILED. | ||
1356 | * The 'blocked' state of a target which has been recovered | ||
1357 | * successfully is reset. | ||
1358 | * | ||
1359 | * returns: ZFCP_ERP_CONTINUES - action continues (not considered) | ||
1360 | * ZFCP_ERP_SUCCEEDED - action finished successfully | ||
1361 | * ZFCP_ERP_EXIT - action failed and will not continue | ||
1362 | */ | ||
1363 | static int | ||
1364 | zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, int result) | ||
1365 | { | ||
1366 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1367 | struct zfcp_port *port = erp_action->port; | ||
1368 | struct zfcp_unit *unit = erp_action->unit; | ||
1369 | |||
1370 | switch (erp_action->action) { | ||
1371 | |||
1372 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
1373 | result = zfcp_erp_strategy_check_unit(unit, result); | ||
1374 | break; | ||
1375 | |||
1376 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
1377 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
1378 | result = zfcp_erp_strategy_check_port(port, result); | ||
1379 | break; | ||
1380 | |||
1381 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1382 | result = zfcp_erp_strategy_check_adapter(adapter, result); | ||
1383 | break; | ||
1384 | } | ||
1385 | |||
1386 | return result; | ||
1387 | } | ||
1388 | |||
1389 | static int | ||
1390 | zfcp_erp_strategy_statechange(int action, | ||
1391 | u32 status, | ||
1392 | struct zfcp_adapter *adapter, | ||
1393 | struct zfcp_port *port, | ||
1394 | struct zfcp_unit *unit, int retval) | ||
1395 | { | ||
1396 | switch (action) { | ||
1397 | |||
1398 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1399 | if (zfcp_erp_strategy_statechange_detected(&adapter->status, | ||
1400 | status)) { | ||
1401 | zfcp_erp_adapter_reopen_internal(adapter, | ||
1402 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
1403 | 67, NULL); | ||
1404 | retval = ZFCP_ERP_EXIT; | ||
1405 | } | ||
1406 | break; | ||
1407 | |||
1408 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
1409 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
1410 | if (zfcp_erp_strategy_statechange_detected(&port->status, | ||
1411 | status)) { | ||
1412 | zfcp_erp_port_reopen_internal(port, | ||
1413 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
1414 | 68, NULL); | ||
1415 | retval = ZFCP_ERP_EXIT; | ||
1416 | } | ||
1417 | break; | ||
1418 | |||
1419 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
1420 | if (zfcp_erp_strategy_statechange_detected(&unit->status, | ||
1421 | status)) { | ||
1422 | zfcp_erp_unit_reopen_internal(unit, | ||
1423 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
1424 | 69, NULL); | ||
1425 | retval = ZFCP_ERP_EXIT; | ||
1426 | } | ||
1427 | break; | ||
1428 | } | ||
1429 | |||
1430 | return retval; | ||
1431 | } | ||
1432 | |||
1433 | static int | ||
1434 | zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status) | ||
1435 | { | 531 | { |
1436 | return | 532 | struct zfcp_port *port; |
1437 | /* take it online */ | ||
1438 | (atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, target_status) && | ||
1439 | (ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status)) || | ||
1440 | /* take it offline */ | ||
1441 | (!atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, target_status) && | ||
1442 | !(ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status)); | ||
1443 | } | ||
1444 | |||
1445 | static int | ||
1446 | zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) | ||
1447 | { | ||
1448 | switch (result) { | ||
1449 | case ZFCP_ERP_SUCCEEDED : | ||
1450 | atomic_set(&unit->erp_counter, 0); | ||
1451 | zfcp_erp_unit_unblock(unit); | ||
1452 | break; | ||
1453 | case ZFCP_ERP_FAILED : | ||
1454 | atomic_inc(&unit->erp_counter); | ||
1455 | if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) | ||
1456 | zfcp_erp_unit_failed(unit, 21, NULL); | ||
1457 | break; | ||
1458 | case ZFCP_ERP_EXIT : | ||
1459 | /* nothing */ | ||
1460 | break; | ||
1461 | } | ||
1462 | |||
1463 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) { | ||
1464 | zfcp_erp_unit_block(unit, 0); /* for ZFCP_ERP_SUCCEEDED */ | ||
1465 | result = ZFCP_ERP_EXIT; | ||
1466 | } | ||
1467 | |||
1468 | return result; | ||
1469 | } | ||
1470 | |||
1471 | static int | ||
1472 | zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) | ||
1473 | { | ||
1474 | switch (result) { | ||
1475 | case ZFCP_ERP_SUCCEEDED : | ||
1476 | atomic_set(&port->erp_counter, 0); | ||
1477 | zfcp_erp_port_unblock(port); | ||
1478 | break; | ||
1479 | case ZFCP_ERP_FAILED : | ||
1480 | atomic_inc(&port->erp_counter); | ||
1481 | if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) | ||
1482 | zfcp_erp_port_failed(port, 22, NULL); | ||
1483 | break; | ||
1484 | case ZFCP_ERP_EXIT : | ||
1485 | /* nothing */ | ||
1486 | break; | ||
1487 | } | ||
1488 | |||
1489 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { | ||
1490 | zfcp_erp_port_block(port, 0); /* for ZFCP_ERP_SUCCEEDED */ | ||
1491 | result = ZFCP_ERP_EXIT; | ||
1492 | } | ||
1493 | 533 | ||
1494 | return result; | 534 | list_for_each_entry(port, &adapter->port_list_head, list) |
535 | if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA)) | ||
536 | _zfcp_erp_port_reopen(port, clear, id, ref); | ||
1495 | } | 537 | } |
1496 | 538 | ||
1497 | static int | 539 | static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, u8 id, |
1498 | zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result) | 540 | void *ref) |
1499 | { | 541 | { |
1500 | switch (result) { | 542 | struct zfcp_unit *unit; |
1501 | case ZFCP_ERP_SUCCEEDED : | ||
1502 | atomic_set(&adapter->erp_counter, 0); | ||
1503 | zfcp_erp_adapter_unblock(adapter); | ||
1504 | break; | ||
1505 | case ZFCP_ERP_FAILED : | ||
1506 | atomic_inc(&adapter->erp_counter); | ||
1507 | if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) | ||
1508 | zfcp_erp_adapter_failed(adapter, 23, NULL); | ||
1509 | break; | ||
1510 | case ZFCP_ERP_EXIT : | ||
1511 | /* nothing */ | ||
1512 | break; | ||
1513 | } | ||
1514 | |||
1515 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { | ||
1516 | zfcp_erp_adapter_block(adapter, 0); /* for ZFCP_ERP_SUCCEEDED */ | ||
1517 | result = ZFCP_ERP_EXIT; | ||
1518 | } | ||
1519 | |||
1520 | return result; | ||
1521 | } | ||
1522 | |||
1523 | struct zfcp_erp_add_work { | ||
1524 | struct zfcp_unit *unit; | ||
1525 | struct work_struct work; | ||
1526 | }; | ||
1527 | 543 | ||
1528 | /** | 544 | list_for_each_entry(unit, &port->unit_list_head, list) |
1529 | * zfcp_erp_scsi_scan | 545 | _zfcp_erp_unit_reopen(unit, clear, id, ref); |
1530 | * @data: pointer to a struct zfcp_erp_add_work | ||
1531 | * | ||
1532 | * Registers a logical unit with the SCSI stack. | ||
1533 | */ | ||
1534 | static void zfcp_erp_scsi_scan(struct work_struct *work) | ||
1535 | { | ||
1536 | struct zfcp_erp_add_work *p = | ||
1537 | container_of(work, struct zfcp_erp_add_work, work); | ||
1538 | struct zfcp_unit *unit = p->unit; | ||
1539 | struct fc_rport *rport = unit->port->rport; | ||
1540 | scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, | ||
1541 | unit->scsi_lun, 0); | ||
1542 | atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); | ||
1543 | zfcp_unit_put(unit); | ||
1544 | kfree(p); | ||
1545 | } | 546 | } |
1546 | 547 | ||
1547 | /** | 548 | static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act) |
1548 | * zfcp_erp_schedule_work | ||
1549 | * @unit: pointer to unit which should be registered with SCSI stack | ||
1550 | * | ||
1551 | * Schedules work which registers a unit with the SCSI stack | ||
1552 | */ | ||
1553 | static void | ||
1554 | zfcp_erp_schedule_work(struct zfcp_unit *unit) | ||
1555 | { | 549 | { |
1556 | struct zfcp_erp_add_work *p; | 550 | struct zfcp_adapter *adapter = act->adapter; |
551 | struct zfcp_port *port = act->port; | ||
552 | struct zfcp_unit *unit = act->unit; | ||
553 | u32 status = act->status; | ||
1557 | 554 | ||
1558 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
1559 | if (!p) { | ||
1560 | ZFCP_LOG_NORMAL("error: Out of resources. Could not register " | ||
1561 | "the FCP-LUN 0x%Lx connected to " | ||
1562 | "the port with WWPN 0x%Lx connected to " | ||
1563 | "the adapter %s with the SCSI stack.\n", | ||
1564 | unit->fcp_lun, | ||
1565 | unit->port->wwpn, | ||
1566 | zfcp_get_busid_by_unit(unit)); | ||
1567 | return; | ||
1568 | } | ||
1569 | |||
1570 | zfcp_unit_get(unit); | ||
1571 | atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); | ||
1572 | INIT_WORK(&p->work, zfcp_erp_scsi_scan); | ||
1573 | p->unit = unit; | ||
1574 | schedule_work(&p->work); | ||
1575 | } | ||
1576 | |||
1577 | /* | ||
1578 | * function: | ||
1579 | * | ||
1580 | * purpose: remaining things in good cases, | ||
1581 | * escalation in bad cases | ||
1582 | * | ||
1583 | * returns: | ||
1584 | */ | ||
1585 | static int | ||
1586 | zfcp_erp_strategy_followup_actions(int action, | ||
1587 | struct zfcp_adapter *adapter, | ||
1588 | struct zfcp_port *port, | ||
1589 | struct zfcp_unit *unit, int status) | ||
1590 | { | ||
1591 | /* initiate follow-up actions depending on success of finished action */ | 555 | /* initiate follow-up actions depending on success of finished action */ |
1592 | switch (action) { | 556 | switch (act->action) { |
1593 | 557 | ||
1594 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 558 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
1595 | if (status == ZFCP_ERP_SUCCEEDED) | 559 | if (status == ZFCP_ERP_SUCCEEDED) |
1596 | zfcp_erp_port_reopen_all_internal(adapter, 0, 70, NULL); | 560 | _zfcp_erp_port_reopen_all(adapter, 0, 70, NULL); |
1597 | else | 561 | else |
1598 | zfcp_erp_adapter_reopen_internal(adapter, 0, 71, NULL); | 562 | _zfcp_erp_adapter_reopen(adapter, 0, 71, NULL); |
1599 | break; | 563 | break; |
1600 | 564 | ||
1601 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | 565 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
1602 | if (status == ZFCP_ERP_SUCCEEDED) | 566 | if (status == ZFCP_ERP_SUCCEEDED) |
1603 | zfcp_erp_port_reopen_internal(port, 0, 72, NULL); | 567 | _zfcp_erp_port_reopen(port, 0, 72, NULL); |
1604 | else | 568 | else |
1605 | zfcp_erp_adapter_reopen_internal(adapter, 0, 73, NULL); | 569 | _zfcp_erp_adapter_reopen(adapter, 0, 73, NULL); |
1606 | break; | 570 | break; |
1607 | 571 | ||
1608 | case ZFCP_ERP_ACTION_REOPEN_PORT: | 572 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
1609 | if (status == ZFCP_ERP_SUCCEEDED) | 573 | if (status == ZFCP_ERP_SUCCEEDED) |
1610 | zfcp_erp_unit_reopen_all_internal(port, 0, 74, NULL); | 574 | _zfcp_erp_unit_reopen_all(port, 0, 74, NULL); |
1611 | else | 575 | else |
1612 | zfcp_erp_port_forced_reopen_internal(port, 0, 75, NULL); | 576 | _zfcp_erp_port_forced_reopen(port, 0, 75, NULL); |
1613 | break; | 577 | break; |
1614 | 578 | ||
1615 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 579 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
1616 | /* Nothing to do if status == ZFCP_ERP_SUCCEEDED */ | ||
1617 | if (status != ZFCP_ERP_SUCCEEDED) | 580 | if (status != ZFCP_ERP_SUCCEEDED) |
1618 | zfcp_erp_port_reopen_internal(unit->port, 0, 76, NULL); | 581 | _zfcp_erp_port_reopen(unit->port, 0, 76, NULL); |
1619 | break; | 582 | break; |
1620 | } | 583 | } |
1621 | |||
1622 | return 0; | ||
1623 | } | 584 | } |
1624 | 585 | ||
1625 | static int | 586 | static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) |
1626 | zfcp_erp_strategy_check_queues(struct zfcp_adapter *adapter) | ||
1627 | { | 587 | { |
1628 | unsigned long flags; | 588 | unsigned long flags; |
1629 | 589 | ||
@@ -1637,1277 +597,622 @@ zfcp_erp_strategy_check_queues(struct zfcp_adapter *adapter) | |||
1637 | } | 597 | } |
1638 | read_unlock(&adapter->erp_lock); | 598 | read_unlock(&adapter->erp_lock); |
1639 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 599 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
1640 | |||
1641 | return 0; | ||
1642 | } | 600 | } |
1643 | 601 | ||
1644 | /** | 602 | static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act) |
1645 | * zfcp_erp_wait - wait for completion of error recovery on an adapter | ||
1646 | * @adapter: adapter for which to wait for completion of its error recovery | ||
1647 | * Return: 0 | ||
1648 | */ | ||
1649 | int | ||
1650 | zfcp_erp_wait(struct zfcp_adapter *adapter) | ||
1651 | { | 603 | { |
1652 | int retval = 0; | 604 | if (zfcp_qdio_open(act->adapter)) |
1653 | 605 | return ZFCP_ERP_FAILED; | |
1654 | wait_event(adapter->erp_done_wqh, | 606 | init_waitqueue_head(&act->adapter->request_wq); |
1655 | !atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, | 607 | atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status); |
1656 | &adapter->status)); | 608 | return ZFCP_ERP_SUCCEEDED; |
1657 | |||
1658 | return retval; | ||
1659 | } | 609 | } |
1660 | 610 | ||
1661 | void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, u8 id, | 611 | static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter) |
1662 | void *ref, u32 mask, int set_or_clear) | ||
1663 | { | 612 | { |
1664 | struct zfcp_port *port; | 613 | struct zfcp_port *port; |
1665 | u32 changed, common_mask = mask & ZFCP_COMMON_FLAGS; | 614 | port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0, |
1666 | 615 | adapter->peer_d_id); | |
1667 | if (set_or_clear == ZFCP_SET) { | 616 | if (IS_ERR(port)) /* error or port already attached */ |
1668 | changed = atomic_test_and_set_mask(mask, &adapter->status); | 617 | return; |
1669 | } else { | 618 | _zfcp_erp_port_reopen(port, 0, 150, NULL); |
1670 | changed = atomic_test_and_clear_mask(mask, &adapter->status); | ||
1671 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
1672 | atomic_set(&adapter->erp_counter, 0); | ||
1673 | } | ||
1674 | if (changed) | ||
1675 | zfcp_rec_dbf_event_adapter(id, ref, adapter); | ||
1676 | |||
1677 | /* Deal with all underlying devices, only pass common_mask */ | ||
1678 | if (common_mask) | ||
1679 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
1680 | zfcp_erp_modify_port_status(port, id, ref, common_mask, | ||
1681 | set_or_clear); | ||
1682 | } | 619 | } |
1683 | 620 | ||
1684 | /* | 621 | static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) |
1685 | * function: zfcp_erp_modify_port_status | ||
1686 | * | ||
1687 | * purpose: sets the port and all underlying devices to ERP_FAILED | ||
1688 | * | ||
1689 | */ | ||
1690 | void zfcp_erp_modify_port_status(struct zfcp_port *port, u8 id, void *ref, | ||
1691 | u32 mask, int set_or_clear) | ||
1692 | { | 622 | { |
1693 | struct zfcp_unit *unit; | 623 | int retries; |
1694 | u32 changed, common_mask = mask & ZFCP_COMMON_FLAGS; | 624 | int sleep = 1; |
1695 | 625 | struct zfcp_adapter *adapter = erp_action->adapter; | |
1696 | if (set_or_clear == ZFCP_SET) { | ||
1697 | changed = atomic_test_and_set_mask(mask, &port->status); | ||
1698 | } else { | ||
1699 | changed = atomic_test_and_clear_mask(mask, &port->status); | ||
1700 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
1701 | atomic_set(&port->erp_counter, 0); | ||
1702 | } | ||
1703 | if (changed) | ||
1704 | zfcp_rec_dbf_event_port(id, ref, port); | ||
1705 | |||
1706 | /* Modify status of all underlying devices, only pass common mask */ | ||
1707 | if (common_mask) | ||
1708 | list_for_each_entry(unit, &port->unit_list_head, list) | ||
1709 | zfcp_erp_modify_unit_status(unit, id, ref, common_mask, | ||
1710 | set_or_clear); | ||
1711 | } | ||
1712 | 626 | ||
1713 | /* | 627 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); |
1714 | * function: zfcp_erp_modify_unit_status | ||
1715 | * | ||
1716 | * purpose: sets the unit to ERP_FAILED | ||
1717 | * | ||
1718 | */ | ||
1719 | void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u8 id, void *ref, | ||
1720 | u32 mask, int set_or_clear) | ||
1721 | { | ||
1722 | u32 changed; | ||
1723 | 628 | ||
1724 | if (set_or_clear == ZFCP_SET) { | 629 | for (retries = 7; retries; retries--) { |
1725 | changed = atomic_test_and_set_mask(mask, &unit->status); | 630 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, |
1726 | } else { | 631 | &adapter->status); |
1727 | changed = atomic_test_and_clear_mask(mask, &unit->status); | 632 | write_lock_irq(&adapter->erp_lock); |
1728 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { | 633 | zfcp_erp_action_to_running(erp_action); |
1729 | atomic_set(&unit->erp_counter, 0); | 634 | write_unlock_irq(&adapter->erp_lock); |
635 | if (zfcp_fsf_exchange_config_data(erp_action)) { | ||
636 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | ||
637 | &adapter->status); | ||
638 | return ZFCP_ERP_FAILED; | ||
1730 | } | 639 | } |
1731 | } | ||
1732 | if (changed) | ||
1733 | zfcp_rec_dbf_event_unit(id, ref, unit); | ||
1734 | } | ||
1735 | 640 | ||
1736 | /* | 641 | zfcp_rec_dbf_event_thread_lock(6, adapter); |
1737 | * function: | 642 | down(&adapter->erp_ready_sem); |
1738 | * | 643 | zfcp_rec_dbf_event_thread_lock(7, adapter); |
1739 | * purpose: Wrappper for zfcp_erp_port_reopen_all_internal | 644 | if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) |
1740 | * used to ensure the correct locking | 645 | break; |
1741 | * | ||
1742 | * returns: 0 - initiated action successfully | ||
1743 | * <0 - failed to initiate action | ||
1744 | */ | ||
1745 | int zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, int clear_mask, | ||
1746 | u8 id, void *ref) | ||
1747 | { | ||
1748 | int retval; | ||
1749 | unsigned long flags; | ||
1750 | |||
1751 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1752 | write_lock(&adapter->erp_lock); | ||
1753 | retval = zfcp_erp_port_reopen_all_internal(adapter, clear_mask, id, | ||
1754 | ref); | ||
1755 | write_unlock(&adapter->erp_lock); | ||
1756 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1757 | |||
1758 | return retval; | ||
1759 | } | ||
1760 | 646 | ||
1761 | static int zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, | 647 | if (!(atomic_read(&adapter->status) & |
1762 | int clear_mask, u8 id, void *ref) | 648 | ZFCP_STATUS_ADAPTER_HOST_CON_INIT)) |
1763 | { | 649 | break; |
1764 | int retval = 0; | ||
1765 | struct zfcp_port *port; | ||
1766 | 650 | ||
1767 | list_for_each_entry(port, &adapter->port_list_head, list) | 651 | ssleep(sleep); |
1768 | if (!atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) | 652 | sleep *= 2; |
1769 | zfcp_erp_port_reopen_internal(port, clear_mask, id, | 653 | } |
1770 | ref); | ||
1771 | 654 | ||
1772 | return retval; | 655 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, |
1773 | } | 656 | &adapter->status); |
1774 | 657 | ||
1775 | /* | 658 | if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK)) |
1776 | * function: | 659 | return ZFCP_ERP_FAILED; |
1777 | * | ||
1778 | * purpose: | ||
1779 | * | ||
1780 | * returns: FIXME | ||
1781 | */ | ||
1782 | static int zfcp_erp_unit_reopen_all_internal(struct zfcp_port *port, | ||
1783 | int clear_mask, u8 id, void *ref) | ||
1784 | { | ||
1785 | int retval = 0; | ||
1786 | struct zfcp_unit *unit; | ||
1787 | 660 | ||
1788 | list_for_each_entry(unit, &port->unit_list_head, list) | 661 | if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) |
1789 | zfcp_erp_unit_reopen_internal(unit, clear_mask, id, ref); | 662 | zfcp_erp_enqueue_ptp_port(adapter); |
1790 | 663 | ||
1791 | return retval; | 664 | return ZFCP_ERP_SUCCEEDED; |
1792 | } | 665 | } |
1793 | 666 | ||
1794 | /* | 667 | static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act) |
1795 | * function: | ||
1796 | * | ||
1797 | * purpose: this routine executes the 'Reopen Adapter' action | ||
1798 | * (the entire action is processed synchronously, since | ||
1799 | * there are no actions which might be run concurrently | ||
1800 | * per definition) | ||
1801 | * | ||
1802 | * returns: ZFCP_ERP_SUCCEEDED - action finished successfully | ||
1803 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
1804 | */ | ||
1805 | static int | ||
1806 | zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action) | ||
1807 | { | 668 | { |
1808 | int retval; | 669 | int ret; |
1809 | struct zfcp_adapter *adapter = erp_action->adapter; | 670 | struct zfcp_adapter *adapter = act->adapter; |
1810 | |||
1811 | retval = zfcp_erp_adapter_strategy_close(erp_action); | ||
1812 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) | ||
1813 | retval = ZFCP_ERP_EXIT; | ||
1814 | else | ||
1815 | retval = zfcp_erp_adapter_strategy_open(erp_action); | ||
1816 | 671 | ||
1817 | if (retval == ZFCP_ERP_FAILED) { | 672 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); |
1818 | ZFCP_LOG_INFO("Waiting to allow the adapter %s " | ||
1819 | "to recover itself\n", | ||
1820 | zfcp_get_busid_by_adapter(adapter)); | ||
1821 | ssleep(ZFCP_TYPE2_RECOVERY_TIME); | ||
1822 | } | ||
1823 | 673 | ||
1824 | return retval; | 674 | write_lock_irq(&adapter->erp_lock); |
1825 | } | 675 | zfcp_erp_action_to_running(act); |
676 | write_unlock_irq(&adapter->erp_lock); | ||
1826 | 677 | ||
1827 | /* | 678 | ret = zfcp_fsf_exchange_port_data(act); |
1828 | * function: | 679 | if (ret == -EOPNOTSUPP) |
1829 | * | 680 | return ZFCP_ERP_SUCCEEDED; |
1830 | * purpose: | 681 | if (ret) |
1831 | * | 682 | return ZFCP_ERP_FAILED; |
1832 | * returns: ZFCP_ERP_SUCCEEDED - action finished successfully | ||
1833 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
1834 | */ | ||
1835 | static int | ||
1836 | zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *erp_action) | ||
1837 | { | ||
1838 | int retval; | ||
1839 | 683 | ||
1840 | atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, | 684 | zfcp_rec_dbf_event_thread_lock(8, adapter); |
1841 | &erp_action->adapter->status); | 685 | down(&adapter->erp_ready_sem); |
1842 | retval = zfcp_erp_adapter_strategy_generic(erp_action, 1); | 686 | zfcp_rec_dbf_event_thread_lock(9, adapter); |
1843 | atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, | 687 | if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) |
1844 | &erp_action->adapter->status); | 688 | return ZFCP_ERP_FAILED; |
1845 | 689 | ||
1846 | return retval; | 690 | return ZFCP_ERP_SUCCEEDED; |
1847 | } | 691 | } |
1848 | 692 | ||
1849 | /* | 693 | static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act) |
1850 | * function: | ||
1851 | * | ||
1852 | * purpose: | ||
1853 | * | ||
1854 | * returns: ZFCP_ERP_SUCCEEDED - action finished successfully | ||
1855 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
1856 | */ | ||
1857 | static int | ||
1858 | zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *erp_action) | ||
1859 | { | 694 | { |
1860 | int retval; | 695 | if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED) |
696 | return ZFCP_ERP_FAILED; | ||
1861 | 697 | ||
1862 | atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, | 698 | if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED) |
1863 | &erp_action->adapter->status); | 699 | return ZFCP_ERP_FAILED; |
1864 | retval = zfcp_erp_adapter_strategy_generic(erp_action, 0); | ||
1865 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, | ||
1866 | &erp_action->adapter->status); | ||
1867 | 700 | ||
1868 | return retval; | 701 | atomic_set(&act->adapter->stat_miss, 16); |
702 | if (zfcp_status_read_refill(act->adapter)) | ||
703 | return ZFCP_ERP_FAILED; | ||
704 | |||
705 | return ZFCP_ERP_SUCCEEDED; | ||
1869 | } | 706 | } |
1870 | 707 | ||
1871 | /* | 708 | static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *act, |
1872 | * function: zfcp_register_adapter | 709 | int close) |
1873 | * | ||
1874 | * purpose: allocate the irq associated with this devno and register | ||
1875 | * the FSF adapter with the SCSI stack | ||
1876 | * | ||
1877 | * returns: | ||
1878 | */ | ||
1879 | static int | ||
1880 | zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close) | ||
1881 | { | 710 | { |
1882 | int retval = ZFCP_ERP_SUCCEEDED; | 711 | int retval = ZFCP_ERP_SUCCEEDED; |
712 | struct zfcp_adapter *adapter = act->adapter; | ||
1883 | 713 | ||
1884 | if (close) | 714 | if (close) |
1885 | goto close_only; | 715 | goto close_only; |
1886 | 716 | ||
1887 | retval = zfcp_erp_adapter_strategy_open_qdio(erp_action); | 717 | retval = zfcp_erp_adapter_strategy_open_qdio(act); |
1888 | if (retval != ZFCP_ERP_SUCCEEDED) | 718 | if (retval != ZFCP_ERP_SUCCEEDED) |
1889 | goto failed_qdio; | 719 | goto failed_qdio; |
1890 | 720 | ||
1891 | retval = zfcp_erp_adapter_strategy_open_fsf(erp_action); | 721 | retval = zfcp_erp_adapter_strategy_open_fsf(act); |
1892 | if (retval != ZFCP_ERP_SUCCEEDED) | 722 | if (retval != ZFCP_ERP_SUCCEEDED) |
1893 | goto failed_openfcp; | 723 | goto failed_openfcp; |
1894 | 724 | ||
1895 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &erp_action->adapter->status); | 725 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &act->adapter->status); |
1896 | goto out; | 726 | schedule_work(&act->adapter->scan_work); |
727 | |||
728 | return ZFCP_ERP_SUCCEEDED; | ||
1897 | 729 | ||
1898 | close_only: | 730 | close_only: |
1899 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, | 731 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, |
1900 | &erp_action->adapter->status); | 732 | &act->adapter->status); |
1901 | 733 | ||
1902 | failed_openfcp: | 734 | failed_openfcp: |
1903 | zfcp_close_fsf(erp_action->adapter); | 735 | /* close queues to ensure that buffers are not accessed by adapter */ |
736 | zfcp_qdio_close(adapter); | ||
737 | zfcp_fsf_req_dismiss_all(adapter); | ||
738 | adapter->fsf_req_seq_no = 0; | ||
739 | /* all ports and units are closed */ | ||
740 | zfcp_erp_modify_adapter_status(adapter, 24, NULL, | ||
741 | ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); | ||
1904 | failed_qdio: | 742 | failed_qdio: |
1905 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | | 743 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | |
1906 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | | 744 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | |
1907 | ZFCP_STATUS_ADAPTER_XPORT_OK, | 745 | ZFCP_STATUS_ADAPTER_XPORT_OK, |
1908 | &erp_action->adapter->status); | 746 | &act->adapter->status); |
1909 | out: | ||
1910 | return retval; | 747 | return retval; |
1911 | } | 748 | } |
1912 | 749 | ||
1913 | /* | 750 | static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act) |
1914 | * function: zfcp_qdio_init | ||
1915 | * | ||
1916 | * purpose: setup QDIO operation for specified adapter | ||
1917 | * | ||
1918 | * returns: 0 - successful setup | ||
1919 | * !0 - failed setup | ||
1920 | */ | ||
1921 | static int | ||
1922 | zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) | ||
1923 | { | 751 | { |
1924 | int retval; | 752 | int retval; |
1925 | int i; | ||
1926 | volatile struct qdio_buffer_element *sbale; | ||
1927 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1928 | |||
1929 | if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) { | ||
1930 | ZFCP_LOG_NORMAL("bug: second attempt to set up QDIO on " | ||
1931 | "adapter %s\n", | ||
1932 | zfcp_get_busid_by_adapter(adapter)); | ||
1933 | goto failed_sanity; | ||
1934 | } | ||
1935 | |||
1936 | if (qdio_establish(&adapter->qdio_init_data) != 0) { | ||
1937 | ZFCP_LOG_INFO("error: establishment of QDIO queues failed " | ||
1938 | "on adapter %s\n", | ||
1939 | zfcp_get_busid_by_adapter(adapter)); | ||
1940 | goto failed_qdio_establish; | ||
1941 | } | ||
1942 | |||
1943 | if (qdio_activate(adapter->ccw_device, 0) != 0) { | ||
1944 | ZFCP_LOG_INFO("error: activation of QDIO queues failed " | ||
1945 | "on adapter %s\n", | ||
1946 | zfcp_get_busid_by_adapter(adapter)); | ||
1947 | goto failed_qdio_activate; | ||
1948 | } | ||
1949 | |||
1950 | /* | ||
1951 | * put buffers into response queue, | ||
1952 | */ | ||
1953 | for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { | ||
1954 | sbale = &(adapter->response_queue.buffer[i]->element[0]); | ||
1955 | sbale->length = 0; | ||
1956 | sbale->flags = SBAL_FLAGS_LAST_ENTRY; | ||
1957 | sbale->addr = NULL; | ||
1958 | } | ||
1959 | |||
1960 | ZFCP_LOG_TRACE("calling do_QDIO on adapter %s (flags=0x%x, " | ||
1961 | "queue_no=%i, index_in_queue=%i, count=%i)\n", | ||
1962 | zfcp_get_busid_by_adapter(adapter), | ||
1963 | QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q); | ||
1964 | |||
1965 | retval = do_QDIO(adapter->ccw_device, | ||
1966 | QDIO_FLAG_SYNC_INPUT, | ||
1967 | 0, 0, QDIO_MAX_BUFFERS_PER_Q, NULL); | ||
1968 | |||
1969 | if (retval) { | ||
1970 | ZFCP_LOG_NORMAL("bug: setup of QDIO failed (retval=%d)\n", | ||
1971 | retval); | ||
1972 | goto failed_do_qdio; | ||
1973 | } else { | ||
1974 | adapter->response_queue.free_index = 0; | ||
1975 | atomic_set(&adapter->response_queue.free_count, 0); | ||
1976 | ZFCP_LOG_DEBUG("%i buffers successfully enqueued to " | ||
1977 | "response queue\n", QDIO_MAX_BUFFERS_PER_Q); | ||
1978 | } | ||
1979 | /* set index of first avalable SBALS / number of available SBALS */ | ||
1980 | adapter->request_queue.free_index = 0; | ||
1981 | atomic_set(&adapter->request_queue.free_count, QDIO_MAX_BUFFERS_PER_Q); | ||
1982 | adapter->request_queue.distance_from_int = 0; | ||
1983 | |||
1984 | /* initialize waitqueue used to wait for free SBALs in requests queue */ | ||
1985 | init_waitqueue_head(&adapter->request_wq); | ||
1986 | 753 | ||
1987 | /* ok, we did it - skip all cleanups for different failures */ | 754 | atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status); |
1988 | atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); | 755 | zfcp_erp_adapter_strategy_generic(act, 1); /* close */ |
1989 | retval = ZFCP_ERP_SUCCEEDED; | 756 | atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status); |
1990 | goto out; | 757 | if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY) |
758 | return ZFCP_ERP_EXIT; | ||
1991 | 759 | ||
1992 | failed_do_qdio: | 760 | atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status); |
1993 | /* NOP */ | 761 | retval = zfcp_erp_adapter_strategy_generic(act, 0); /* open */ |
762 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status); | ||
1994 | 763 | ||
1995 | failed_qdio_activate: | 764 | if (retval == ZFCP_ERP_FAILED) |
1996 | while (qdio_shutdown(adapter->ccw_device, | 765 | ssleep(8); |
1997 | QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) | ||
1998 | ssleep(1); | ||
1999 | |||
2000 | failed_qdio_establish: | ||
2001 | failed_sanity: | ||
2002 | retval = ZFCP_ERP_FAILED; | ||
2003 | 766 | ||
2004 | out: | ||
2005 | return retval; | 767 | return retval; |
2006 | } | 768 | } |
2007 | 769 | ||
2008 | 770 | static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act) | |
2009 | static int | ||
2010 | zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action) | ||
2011 | { | 771 | { |
2012 | int retval; | 772 | int retval; |
2013 | 773 | ||
2014 | retval = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action); | 774 | retval = zfcp_fsf_close_physical_port(act); |
2015 | if (retval == ZFCP_ERP_FAILED) | 775 | if (retval == -ENOMEM) |
776 | return ZFCP_ERP_NOMEM; | ||
777 | act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING; | ||
778 | if (retval) | ||
2016 | return ZFCP_ERP_FAILED; | 779 | return ZFCP_ERP_FAILED; |
2017 | 780 | ||
2018 | retval = zfcp_erp_adapter_strategy_open_fsf_xport(erp_action); | 781 | return ZFCP_ERP_CONTINUES; |
2019 | if (retval == ZFCP_ERP_FAILED) | ||
2020 | return ZFCP_ERP_FAILED; | ||
2021 | |||
2022 | return zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action); | ||
2023 | } | 782 | } |
2024 | 783 | ||
2025 | static int | 784 | static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port) |
2026 | zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) | ||
2027 | { | 785 | { |
2028 | int retval = ZFCP_ERP_SUCCEEDED; | 786 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | |
2029 | int retries; | 787 | ZFCP_STATUS_COMMON_CLOSING | |
2030 | int sleep = ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP; | 788 | ZFCP_STATUS_COMMON_ACCESS_DENIED | |
2031 | struct zfcp_adapter *adapter = erp_action->adapter; | 789 | ZFCP_STATUS_PORT_DID_DID | |
2032 | 790 | ZFCP_STATUS_PORT_PHYS_CLOSING | | |
2033 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); | 791 | ZFCP_STATUS_PORT_INVALID_WWPN, |
2034 | 792 | &port->status); | |
2035 | for (retries = ZFCP_EXCHANGE_CONFIG_DATA_RETRIES; retries; retries--) { | 793 | } |
2036 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | ||
2037 | &adapter->status); | ||
2038 | ZFCP_LOG_DEBUG("Doing exchange config data\n"); | ||
2039 | write_lock_irq(&adapter->erp_lock); | ||
2040 | zfcp_erp_action_to_running(erp_action); | ||
2041 | write_unlock_irq(&adapter->erp_lock); | ||
2042 | if (zfcp_fsf_exchange_config_data(erp_action)) { | ||
2043 | retval = ZFCP_ERP_FAILED; | ||
2044 | ZFCP_LOG_INFO("error: initiation of exchange of " | ||
2045 | "configuration data failed for " | ||
2046 | "adapter %s\n", | ||
2047 | zfcp_get_busid_by_adapter(adapter)); | ||
2048 | break; | ||
2049 | } | ||
2050 | ZFCP_LOG_DEBUG("Xchange underway\n"); | ||
2051 | |||
2052 | /* | ||
2053 | * Why this works: | ||
2054 | * Both the normal completion handler as well as the timeout | ||
2055 | * handler will do an 'up' when the 'exchange config data' | ||
2056 | * request completes or times out. Thus, the signal to go on | ||
2057 | * won't be lost utilizing this semaphore. | ||
2058 | * Furthermore, this 'adapter_reopen' action is | ||
2059 | * guaranteed to be the only action being there (highest action | ||
2060 | * which prevents other actions from being created). | ||
2061 | * Resulting from that, the wake signal recognized here | ||
2062 | * _must_ be the one belonging to the 'exchange config | ||
2063 | * data' request. | ||
2064 | */ | ||
2065 | zfcp_rec_dbf_event_thread(6, adapter, 1); | ||
2066 | down(&adapter->erp_ready_sem); | ||
2067 | zfcp_rec_dbf_event_thread(7, adapter, 1); | ||
2068 | if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { | ||
2069 | ZFCP_LOG_INFO("error: exchange of configuration data " | ||
2070 | "for adapter %s timed out\n", | ||
2071 | zfcp_get_busid_by_adapter(adapter)); | ||
2072 | break; | ||
2073 | } | ||
2074 | |||
2075 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | ||
2076 | &adapter->status)) | ||
2077 | break; | ||
2078 | 794 | ||
2079 | ZFCP_LOG_DEBUG("host connection still initialising... " | 795 | static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) |
2080 | "waiting and retrying...\n"); | 796 | { |
2081 | /* sleep a little bit before retry */ | 797 | struct zfcp_port *port = erp_action->port; |
2082 | ssleep(sleep); | 798 | int status = atomic_read(&port->status); |
2083 | sleep *= 2; | ||
2084 | } | ||
2085 | 799 | ||
2086 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | 800 | switch (erp_action->step) { |
2087 | &adapter->status); | 801 | case ZFCP_ERP_STEP_UNINITIALIZED: |
802 | zfcp_erp_port_strategy_clearstati(port); | ||
803 | if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) && | ||
804 | (status & ZFCP_STATUS_COMMON_OPEN)) | ||
805 | return zfcp_erp_port_forced_strategy_close(erp_action); | ||
806 | else | ||
807 | return ZFCP_ERP_FAILED; | ||
2088 | 808 | ||
2089 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | 809 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: |
2090 | &adapter->status)) { | 810 | if (status & ZFCP_STATUS_PORT_PHYS_OPEN) |
2091 | ZFCP_LOG_INFO("error: exchange of configuration data for " | 811 | return ZFCP_ERP_SUCCEEDED; |
2092 | "adapter %s failed\n", | ||
2093 | zfcp_get_busid_by_adapter(adapter)); | ||
2094 | retval = ZFCP_ERP_FAILED; | ||
2095 | } | 812 | } |
2096 | 813 | return ZFCP_ERP_FAILED; | |
2097 | return retval; | ||
2098 | } | 814 | } |
2099 | 815 | ||
2100 | static int | 816 | static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action) |
2101 | zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action) | ||
2102 | { | 817 | { |
2103 | int ret; | 818 | int retval; |
2104 | struct zfcp_adapter *adapter; | ||
2105 | |||
2106 | adapter = erp_action->adapter; | ||
2107 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); | ||
2108 | |||
2109 | write_lock_irq(&adapter->erp_lock); | ||
2110 | zfcp_erp_action_to_running(erp_action); | ||
2111 | write_unlock_irq(&adapter->erp_lock); | ||
2112 | 819 | ||
2113 | ret = zfcp_fsf_exchange_port_data(erp_action); | 820 | retval = zfcp_fsf_close_port(erp_action); |
2114 | if (ret == -EOPNOTSUPP) { | 821 | if (retval == -ENOMEM) |
2115 | return ZFCP_ERP_SUCCEEDED; | 822 | return ZFCP_ERP_NOMEM; |
2116 | } else if (ret) { | 823 | erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING; |
824 | if (retval) | ||
2117 | return ZFCP_ERP_FAILED; | 825 | return ZFCP_ERP_FAILED; |
2118 | } | 826 | return ZFCP_ERP_CONTINUES; |
2119 | |||
2120 | ret = ZFCP_ERP_SUCCEEDED; | ||
2121 | zfcp_rec_dbf_event_thread(8, adapter, 1); | ||
2122 | down(&adapter->erp_ready_sem); | ||
2123 | zfcp_rec_dbf_event_thread(9, adapter, 1); | ||
2124 | if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { | ||
2125 | ZFCP_LOG_INFO("error: exchange port data timed out (adapter " | ||
2126 | "%s)\n", zfcp_get_busid_by_adapter(adapter)); | ||
2127 | ret = ZFCP_ERP_FAILED; | ||
2128 | } | ||
2129 | |||
2130 | /* don't treat as error for the sake of compatibility */ | ||
2131 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status)) | ||
2132 | ZFCP_LOG_INFO("warning: exchange port data failed (adapter " | ||
2133 | "%s\n", zfcp_get_busid_by_adapter(adapter)); | ||
2134 | |||
2135 | return ret; | ||
2136 | } | 827 | } |
2137 | 828 | ||
2138 | static int | 829 | static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action) |
2139 | zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action | ||
2140 | *erp_action) | ||
2141 | { | 830 | { |
2142 | int retval = ZFCP_ERP_SUCCEEDED; | 831 | int retval; |
2143 | int temp_ret; | ||
2144 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2145 | int i; | ||
2146 | |||
2147 | adapter->status_read_failed = 0; | ||
2148 | for (i = 0; i < ZFCP_STATUS_READS_RECOM; i++) { | ||
2149 | temp_ret = zfcp_fsf_status_read(adapter, ZFCP_WAIT_FOR_SBAL); | ||
2150 | if (temp_ret < 0) { | ||
2151 | ZFCP_LOG_INFO("error: set-up of unsolicited status " | ||
2152 | "notification failed on adapter %s\n", | ||
2153 | zfcp_get_busid_by_adapter(adapter)); | ||
2154 | retval = ZFCP_ERP_FAILED; | ||
2155 | i--; | ||
2156 | break; | ||
2157 | } | ||
2158 | } | ||
2159 | 832 | ||
2160 | return retval; | 833 | retval = zfcp_fsf_open_port(erp_action); |
834 | if (retval == -ENOMEM) | ||
835 | return ZFCP_ERP_NOMEM; | ||
836 | erp_action->step = ZFCP_ERP_STEP_PORT_OPENING; | ||
837 | if (retval) | ||
838 | return ZFCP_ERP_FAILED; | ||
839 | return ZFCP_ERP_CONTINUES; | ||
2161 | } | 840 | } |
2162 | 841 | ||
2163 | /* | 842 | static void zfcp_erp_port_strategy_open_ns_wake(struct zfcp_erp_action *ns_act) |
2164 | * function: | ||
2165 | * | ||
2166 | * purpose: this routine executes the 'Reopen Physical Port' action | ||
2167 | * | ||
2168 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2169 | * ZFCP_ERP_SUCCEEDED - action finished successfully | ||
2170 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2171 | */ | ||
2172 | static int | ||
2173 | zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) | ||
2174 | { | 843 | { |
2175 | int retval = ZFCP_ERP_FAILED; | 844 | unsigned long flags; |
2176 | struct zfcp_port *port = erp_action->port; | 845 | struct zfcp_adapter *adapter = ns_act->adapter; |
2177 | 846 | struct zfcp_erp_action *act, *tmp; | |
2178 | switch (erp_action->step) { | 847 | int status; |
2179 | |||
2180 | /* | ||
2181 | * FIXME: | ||
2182 | * the ULP spec. begs for waiting for oustanding commands | ||
2183 | */ | ||
2184 | case ZFCP_ERP_STEP_UNINITIALIZED: | ||
2185 | zfcp_erp_port_strategy_clearstati(port); | ||
2186 | /* | ||
2187 | * it would be sufficient to test only the normal open flag | ||
2188 | * since the phys. open flag cannot be set if the normal | ||
2189 | * open flag is unset - however, this is for readabilty ... | ||
2190 | */ | ||
2191 | if (atomic_test_mask((ZFCP_STATUS_PORT_PHYS_OPEN | | ||
2192 | ZFCP_STATUS_COMMON_OPEN), | ||
2193 | &port->status)) { | ||
2194 | ZFCP_LOG_DEBUG("port 0x%016Lx is open -> trying " | ||
2195 | "close physical\n", port->wwpn); | ||
2196 | retval = | ||
2197 | zfcp_erp_port_forced_strategy_close(erp_action); | ||
2198 | } else | ||
2199 | retval = ZFCP_ERP_FAILED; | ||
2200 | break; | ||
2201 | 848 | ||
2202 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: | 849 | read_lock_irqsave(&adapter->erp_lock, flags); |
2203 | if (atomic_test_mask(ZFCP_STATUS_PORT_PHYS_OPEN, | 850 | list_for_each_entry_safe(act, tmp, &adapter->erp_running_head, list) { |
2204 | &port->status)) { | 851 | if (act->step == ZFCP_ERP_STEP_NAMESERVER_OPEN) { |
2205 | ZFCP_LOG_DEBUG("close physical failed for port " | 852 | status = atomic_read(&adapter->nameserver_port->status); |
2206 | "0x%016Lx\n", port->wwpn); | 853 | if (status & ZFCP_STATUS_COMMON_ERP_FAILED) |
2207 | retval = ZFCP_ERP_FAILED; | 854 | zfcp_erp_port_failed(act->port, 27, NULL); |
2208 | } else | 855 | zfcp_erp_action_ready(act); |
2209 | retval = ZFCP_ERP_SUCCEEDED; | 856 | } |
2210 | break; | ||
2211 | } | 857 | } |
2212 | 858 | read_unlock_irqrestore(&adapter->erp_lock, flags); | |
2213 | return retval; | ||
2214 | } | 859 | } |
2215 | 860 | ||
2216 | /* | 861 | static int zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *act) |
2217 | * function: | ||
2218 | * | ||
2219 | * purpose: this routine executes the 'Reopen Port' action | ||
2220 | * | ||
2221 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2222 | * ZFCP_ERP_SUCCEEDED - action finished successfully | ||
2223 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2224 | */ | ||
2225 | static int | ||
2226 | zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) | ||
2227 | { | 862 | { |
2228 | int retval = ZFCP_ERP_FAILED; | 863 | int retval; |
2229 | struct zfcp_port *port = erp_action->port; | ||
2230 | |||
2231 | switch (erp_action->step) { | ||
2232 | 864 | ||
2233 | /* | 865 | switch (act->step) { |
2234 | * FIXME: | ||
2235 | * the ULP spec. begs for waiting for oustanding commands | ||
2236 | */ | ||
2237 | case ZFCP_ERP_STEP_UNINITIALIZED: | 866 | case ZFCP_ERP_STEP_UNINITIALIZED: |
2238 | zfcp_erp_port_strategy_clearstati(port); | 867 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: |
2239 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { | ||
2240 | ZFCP_LOG_DEBUG("port 0x%016Lx is open -> trying " | ||
2241 | "close\n", port->wwpn); | ||
2242 | retval = zfcp_erp_port_strategy_close(erp_action); | ||
2243 | goto out; | ||
2244 | } /* else it's already closed, open it */ | ||
2245 | break; | ||
2246 | |||
2247 | case ZFCP_ERP_STEP_PORT_CLOSING: | 868 | case ZFCP_ERP_STEP_PORT_CLOSING: |
2248 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { | 869 | return zfcp_erp_port_strategy_open_port(act); |
2249 | ZFCP_LOG_DEBUG("close failed for port 0x%016Lx\n", | 870 | |
2250 | port->wwpn); | 871 | case ZFCP_ERP_STEP_PORT_OPENING: |
872 | if (atomic_read(&act->port->status) & ZFCP_STATUS_COMMON_OPEN) | ||
873 | retval = ZFCP_ERP_SUCCEEDED; | ||
874 | else | ||
2251 | retval = ZFCP_ERP_FAILED; | 875 | retval = ZFCP_ERP_FAILED; |
2252 | goto out; | 876 | /* this is needed anyway */ |
2253 | } /* else it's closed now, open it */ | 877 | zfcp_erp_port_strategy_open_ns_wake(act); |
2254 | break; | 878 | return retval; |
2255 | } | ||
2256 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) | ||
2257 | retval = ZFCP_ERP_EXIT; | ||
2258 | else | ||
2259 | retval = zfcp_erp_port_strategy_open(erp_action); | ||
2260 | 879 | ||
2261 | out: | 880 | default: |
2262 | return retval; | 881 | return ZFCP_ERP_FAILED; |
882 | } | ||
2263 | } | 883 | } |
2264 | 884 | ||
2265 | static int | 885 | static int zfcp_erp_port_strategy_open_lookup(struct zfcp_erp_action *act) |
2266 | zfcp_erp_port_strategy_open(struct zfcp_erp_action *erp_action) | ||
2267 | { | 886 | { |
2268 | int retval; | 887 | int retval; |
2269 | 888 | ||
2270 | if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, | 889 | retval = zfcp_fc_ns_gid_pn_request(act); |
2271 | &erp_action->port->status)) | 890 | if (retval == -ENOMEM) |
2272 | retval = zfcp_erp_port_strategy_open_nameserver(erp_action); | 891 | return ZFCP_ERP_NOMEM; |
2273 | else | 892 | act->step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; |
2274 | retval = zfcp_erp_port_strategy_open_common(erp_action); | 893 | if (retval) |
2275 | 894 | return ZFCP_ERP_FAILED; | |
2276 | return retval; | 895 | return ZFCP_ERP_CONTINUES; |
2277 | } | 896 | } |
2278 | 897 | ||
2279 | static int | 898 | static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) |
2280 | zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action) | ||
2281 | { | 899 | { |
2282 | int retval = 0; | 900 | struct zfcp_adapter *adapter = act->adapter; |
2283 | struct zfcp_adapter *adapter = erp_action->adapter; | 901 | struct zfcp_port *port = act->port; |
2284 | struct zfcp_port *port = erp_action->port; | ||
2285 | 902 | ||
2286 | switch (erp_action->step) { | 903 | if (port->wwpn != adapter->peer_wwpn) { |
904 | dev_err(&adapter->ccw_device->dev, | ||
905 | "Failed to open port 0x%016Lx, " | ||
906 | "Peer WWPN 0x%016Lx does not " | ||
907 | "match.\n", port->wwpn, | ||
908 | adapter->peer_wwpn); | ||
909 | zfcp_erp_port_failed(port, 25, NULL); | ||
910 | return ZFCP_ERP_FAILED; | ||
911 | } | ||
912 | port->d_id = adapter->peer_d_id; | ||
913 | atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); | ||
914 | return zfcp_erp_port_strategy_open_port(act); | ||
915 | } | ||
916 | |||
917 | static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) | ||
918 | { | ||
919 | struct zfcp_adapter *adapter = act->adapter; | ||
920 | struct zfcp_port *port = act->port; | ||
921 | struct zfcp_port *ns_port = adapter->nameserver_port; | ||
922 | int p_status = atomic_read(&port->status); | ||
2287 | 923 | ||
924 | switch (act->step) { | ||
2288 | case ZFCP_ERP_STEP_UNINITIALIZED: | 925 | case ZFCP_ERP_STEP_UNINITIALIZED: |
2289 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: | 926 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: |
2290 | case ZFCP_ERP_STEP_PORT_CLOSING: | 927 | case ZFCP_ERP_STEP_PORT_CLOSING: |
2291 | if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) { | 928 | if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) |
2292 | if (port->wwpn != adapter->peer_wwpn) { | 929 | return zfcp_erp_open_ptp_port(act); |
2293 | ZFCP_LOG_NORMAL("Failed to open port 0x%016Lx " | 930 | if (!ns_port) { |
2294 | "on adapter %s.\nPeer WWPN " | 931 | dev_err(&adapter->ccw_device->dev, |
2295 | "0x%016Lx does not match\n", | 932 | "Nameserver port unavailable.\n"); |
2296 | port->wwpn, | 933 | return ZFCP_ERP_FAILED; |
2297 | zfcp_get_busid_by_adapter(adapter), | ||
2298 | adapter->peer_wwpn); | ||
2299 | zfcp_erp_port_failed(port, 25, NULL); | ||
2300 | retval = ZFCP_ERP_FAILED; | ||
2301 | break; | ||
2302 | } | ||
2303 | port->d_id = adapter->peer_d_id; | ||
2304 | atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); | ||
2305 | retval = zfcp_erp_port_strategy_open_port(erp_action); | ||
2306 | break; | ||
2307 | } | 934 | } |
2308 | if (!(adapter->nameserver_port)) { | 935 | if (!(atomic_read(&ns_port->status) & |
2309 | retval = zfcp_nameserver_enqueue(adapter); | 936 | ZFCP_STATUS_COMMON_UNBLOCKED)) { |
2310 | if (retval != 0) { | ||
2311 | ZFCP_LOG_NORMAL("error: nameserver port " | ||
2312 | "unavailable for adapter %s\n", | ||
2313 | zfcp_get_busid_by_adapter(adapter)); | ||
2314 | retval = ZFCP_ERP_FAILED; | ||
2315 | break; | ||
2316 | } | ||
2317 | } | ||
2318 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
2319 | &adapter->nameserver_port->status)) { | ||
2320 | ZFCP_LOG_DEBUG("nameserver port is not open -> open " | ||
2321 | "nameserver port\n"); | ||
2322 | /* nameserver port may live again */ | 937 | /* nameserver port may live again */ |
2323 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, | 938 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, |
2324 | &adapter->nameserver_port->status); | 939 | &ns_port->status); |
2325 | if (zfcp_erp_port_reopen(adapter->nameserver_port, 0, | 940 | if (zfcp_erp_port_reopen(ns_port, 0, 77, act) >= 0) { |
2326 | 77, erp_action) >= 0) { | 941 | act->step = ZFCP_ERP_STEP_NAMESERVER_OPEN; |
2327 | erp_action->step = | 942 | return ZFCP_ERP_CONTINUES; |
2328 | ZFCP_ERP_STEP_NAMESERVER_OPEN; | 943 | } |
2329 | retval = ZFCP_ERP_CONTINUES; | 944 | return ZFCP_ERP_FAILED; |
2330 | } else | ||
2331 | retval = ZFCP_ERP_FAILED; | ||
2332 | break; | ||
2333 | } | 945 | } |
2334 | /* else nameserver port is already open, fall through */ | 946 | /* else nameserver port is already open, fall through */ |
2335 | case ZFCP_ERP_STEP_NAMESERVER_OPEN: | 947 | case ZFCP_ERP_STEP_NAMESERVER_OPEN: |
2336 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, | 948 | if (!(atomic_read(&ns_port->status) & ZFCP_STATUS_COMMON_OPEN)) |
2337 | &adapter->nameserver_port->status)) { | 949 | return ZFCP_ERP_FAILED; |
2338 | ZFCP_LOG_DEBUG("open failed for nameserver port\n"); | 950 | return zfcp_erp_port_strategy_open_lookup(act); |
2339 | retval = ZFCP_ERP_FAILED; | ||
2340 | } else { | ||
2341 | ZFCP_LOG_DEBUG("nameserver port is open -> " | ||
2342 | "nameserver look-up for port 0x%016Lx\n", | ||
2343 | port->wwpn); | ||
2344 | retval = zfcp_erp_port_strategy_open_common_lookup | ||
2345 | (erp_action); | ||
2346 | } | ||
2347 | break; | ||
2348 | 951 | ||
2349 | case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: | 952 | case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: |
2350 | if (!atomic_test_mask(ZFCP_STATUS_PORT_DID_DID, &port->status)) { | 953 | if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) { |
2351 | if (atomic_test_mask | 954 | if (p_status & (ZFCP_STATUS_PORT_INVALID_WWPN)) { |
2352 | (ZFCP_STATUS_PORT_INVALID_WWPN, &port->status)) { | ||
2353 | ZFCP_LOG_DEBUG("nameserver look-up failed " | ||
2354 | "for port 0x%016Lx " | ||
2355 | "(misconfigured WWPN?)\n", | ||
2356 | port->wwpn); | ||
2357 | zfcp_erp_port_failed(port, 26, NULL); | 955 | zfcp_erp_port_failed(port, 26, NULL); |
2358 | retval = ZFCP_ERP_EXIT; | 956 | return ZFCP_ERP_EXIT; |
2359 | } else { | ||
2360 | ZFCP_LOG_DEBUG("nameserver look-up failed for " | ||
2361 | "port 0x%016Lx\n", port->wwpn); | ||
2362 | retval = ZFCP_ERP_FAILED; | ||
2363 | } | 957 | } |
2364 | } else { | 958 | return ZFCP_ERP_FAILED; |
2365 | ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> " | ||
2366 | "trying open\n", port->wwpn, port->d_id); | ||
2367 | retval = zfcp_erp_port_strategy_open_port(erp_action); | ||
2368 | } | 959 | } |
2369 | break; | 960 | return zfcp_erp_port_strategy_open_port(act); |
2370 | 961 | ||
2371 | case ZFCP_ERP_STEP_PORT_OPENING: | 962 | case ZFCP_ERP_STEP_PORT_OPENING: |
2372 | /* D_ID might have changed during open */ | 963 | /* D_ID might have changed during open */ |
2373 | if (atomic_test_mask((ZFCP_STATUS_COMMON_OPEN | | 964 | if ((p_status & ZFCP_STATUS_COMMON_OPEN) && |
2374 | ZFCP_STATUS_PORT_DID_DID), | 965 | (p_status & ZFCP_STATUS_PORT_DID_DID)) |
2375 | &port->status)) { | 966 | return ZFCP_ERP_SUCCEEDED; |
2376 | ZFCP_LOG_DEBUG("port 0x%016Lx is open\n", port->wwpn); | 967 | /* fall through otherwise */ |
2377 | retval = ZFCP_ERP_SUCCEEDED; | ||
2378 | } else { | ||
2379 | ZFCP_LOG_DEBUG("open failed for port 0x%016Lx\n", | ||
2380 | port->wwpn); | ||
2381 | retval = ZFCP_ERP_FAILED; | ||
2382 | } | ||
2383 | break; | ||
2384 | |||
2385 | default: | ||
2386 | ZFCP_LOG_NORMAL("bug: unknown erp step 0x%08x\n", | ||
2387 | erp_action->step); | ||
2388 | retval = ZFCP_ERP_FAILED; | ||
2389 | } | 968 | } |
969 | return ZFCP_ERP_FAILED; | ||
970 | } | ||
2390 | 971 | ||
2391 | return retval; | 972 | static int zfcp_erp_port_strategy_open(struct zfcp_erp_action *act) |
973 | { | ||
974 | if (atomic_read(&act->port->status) & (ZFCP_STATUS_PORT_WKA)) | ||
975 | return zfcp_erp_port_strategy_open_nameserver(act); | ||
976 | return zfcp_erp_port_strategy_open_common(act); | ||
2392 | } | 977 | } |
2393 | 978 | ||
2394 | static int | 979 | static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) |
2395 | zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action) | ||
2396 | { | 980 | { |
2397 | int retval; | ||
2398 | struct zfcp_port *port = erp_action->port; | 981 | struct zfcp_port *port = erp_action->port; |
2399 | 982 | ||
2400 | switch (erp_action->step) { | 983 | switch (erp_action->step) { |
2401 | |||
2402 | case ZFCP_ERP_STEP_UNINITIALIZED: | 984 | case ZFCP_ERP_STEP_UNINITIALIZED: |
2403 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: | 985 | zfcp_erp_port_strategy_clearstati(port); |
2404 | case ZFCP_ERP_STEP_PORT_CLOSING: | 986 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) |
2405 | ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> trying open\n", | 987 | return zfcp_erp_port_strategy_close(erp_action); |
2406 | port->wwpn, port->d_id); | ||
2407 | retval = zfcp_erp_port_strategy_open_port(erp_action); | ||
2408 | break; | 988 | break; |
2409 | 989 | ||
2410 | case ZFCP_ERP_STEP_PORT_OPENING: | 990 | case ZFCP_ERP_STEP_PORT_CLOSING: |
2411 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { | 991 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) |
2412 | ZFCP_LOG_DEBUG("WKA port is open\n"); | 992 | return ZFCP_ERP_FAILED; |
2413 | retval = ZFCP_ERP_SUCCEEDED; | ||
2414 | } else { | ||
2415 | ZFCP_LOG_DEBUG("open failed for WKA port\n"); | ||
2416 | retval = ZFCP_ERP_FAILED; | ||
2417 | } | ||
2418 | /* this is needed anyway (dont care for retval of wakeup) */ | ||
2419 | ZFCP_LOG_DEBUG("continue other open port operations\n"); | ||
2420 | zfcp_erp_port_strategy_open_nameserver_wakeup(erp_action); | ||
2421 | break; | 993 | break; |
2422 | |||
2423 | default: | ||
2424 | ZFCP_LOG_NORMAL("bug: unknown erp step 0x%08x\n", | ||
2425 | erp_action->step); | ||
2426 | retval = ZFCP_ERP_FAILED; | ||
2427 | } | 994 | } |
995 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) | ||
996 | return ZFCP_ERP_EXIT; | ||
997 | else | ||
998 | return zfcp_erp_port_strategy_open(erp_action); | ||
2428 | 999 | ||
2429 | return retval; | 1000 | return ZFCP_ERP_FAILED; |
2430 | } | ||
2431 | |||
2432 | /* | ||
2433 | * function: | ||
2434 | * | ||
2435 | * purpose: makes the erp thread continue with reopen (physical) port | ||
2436 | * actions which have been paused until the name server port | ||
2437 | * is opened (or failed) | ||
2438 | * | ||
2439 | * returns: 0 (a kind of void retval, its not used) | ||
2440 | */ | ||
2441 | static int | ||
2442 | zfcp_erp_port_strategy_open_nameserver_wakeup(struct zfcp_erp_action | ||
2443 | *ns_erp_action) | ||
2444 | { | ||
2445 | int retval = 0; | ||
2446 | unsigned long flags; | ||
2447 | struct zfcp_adapter *adapter = ns_erp_action->adapter; | ||
2448 | struct zfcp_erp_action *erp_action, *tmp; | ||
2449 | |||
2450 | read_lock_irqsave(&adapter->erp_lock, flags); | ||
2451 | list_for_each_entry_safe(erp_action, tmp, &adapter->erp_running_head, | ||
2452 | list) { | ||
2453 | if (erp_action->step == ZFCP_ERP_STEP_NAMESERVER_OPEN) { | ||
2454 | if (atomic_test_mask( | ||
2455 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
2456 | &adapter->nameserver_port->status)) | ||
2457 | zfcp_erp_port_failed(erp_action->port, 27, | ||
2458 | NULL); | ||
2459 | zfcp_erp_action_ready(erp_action); | ||
2460 | } | ||
2461 | } | ||
2462 | read_unlock_irqrestore(&adapter->erp_lock, flags); | ||
2463 | |||
2464 | return retval; | ||
2465 | } | ||
2466 | |||
2467 | /* | ||
2468 | * function: | ||
2469 | * | ||
2470 | * purpose: | ||
2471 | * | ||
2472 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2473 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2474 | */ | ||
2475 | static int | ||
2476 | zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *erp_action) | ||
2477 | { | ||
2478 | int retval; | ||
2479 | |||
2480 | retval = zfcp_fsf_close_physical_port(erp_action); | ||
2481 | if (retval == -ENOMEM) { | ||
2482 | retval = ZFCP_ERP_NOMEM; | ||
2483 | goto out; | ||
2484 | } | ||
2485 | erp_action->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING; | ||
2486 | if (retval != 0) { | ||
2487 | /* could not send 'open', fail */ | ||
2488 | retval = ZFCP_ERP_FAILED; | ||
2489 | goto out; | ||
2490 | } | ||
2491 | retval = ZFCP_ERP_CONTINUES; | ||
2492 | out: | ||
2493 | return retval; | ||
2494 | } | 1001 | } |
2495 | 1002 | ||
2496 | static int | 1003 | static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) |
2497 | zfcp_erp_port_strategy_clearstati(struct zfcp_port *port) | ||
2498 | { | 1004 | { |
2499 | int retval = 0; | ||
2500 | |||
2501 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | | 1005 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | |
2502 | ZFCP_STATUS_COMMON_CLOSING | | 1006 | ZFCP_STATUS_COMMON_CLOSING | |
2503 | ZFCP_STATUS_COMMON_ACCESS_DENIED | | 1007 | ZFCP_STATUS_COMMON_ACCESS_DENIED | |
2504 | ZFCP_STATUS_PORT_DID_DID | | 1008 | ZFCP_STATUS_UNIT_SHARED | |
2505 | ZFCP_STATUS_PORT_PHYS_CLOSING | | 1009 | ZFCP_STATUS_UNIT_READONLY, |
2506 | ZFCP_STATUS_PORT_INVALID_WWPN, | 1010 | &unit->status); |
2507 | &port->status); | ||
2508 | return retval; | ||
2509 | } | ||
2510 | |||
2511 | /* | ||
2512 | * function: | ||
2513 | * | ||
2514 | * purpose: | ||
2515 | * | ||
2516 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2517 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2518 | */ | ||
2519 | static int | ||
2520 | zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action) | ||
2521 | { | ||
2522 | int retval; | ||
2523 | |||
2524 | retval = zfcp_fsf_close_port(erp_action); | ||
2525 | if (retval == -ENOMEM) { | ||
2526 | retval = ZFCP_ERP_NOMEM; | ||
2527 | goto out; | ||
2528 | } | ||
2529 | erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING; | ||
2530 | if (retval != 0) { | ||
2531 | /* could not send 'close', fail */ | ||
2532 | retval = ZFCP_ERP_FAILED; | ||
2533 | goto out; | ||
2534 | } | ||
2535 | retval = ZFCP_ERP_CONTINUES; | ||
2536 | out: | ||
2537 | return retval; | ||
2538 | } | 1011 | } |
2539 | 1012 | ||
2540 | /* | 1013 | static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) |
2541 | * function: | ||
2542 | * | ||
2543 | * purpose: | ||
2544 | * | ||
2545 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2546 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2547 | */ | ||
2548 | static int | ||
2549 | zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action) | ||
2550 | { | 1014 | { |
2551 | int retval; | 1015 | int retval = zfcp_fsf_close_unit(erp_action); |
2552 | 1016 | if (retval == -ENOMEM) | |
2553 | retval = zfcp_fsf_open_port(erp_action); | 1017 | return ZFCP_ERP_NOMEM; |
2554 | if (retval == -ENOMEM) { | 1018 | erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; |
2555 | retval = ZFCP_ERP_NOMEM; | 1019 | if (retval) |
2556 | goto out; | 1020 | return ZFCP_ERP_FAILED; |
2557 | } | 1021 | return ZFCP_ERP_CONTINUES; |
2558 | erp_action->step = ZFCP_ERP_STEP_PORT_OPENING; | ||
2559 | if (retval != 0) { | ||
2560 | /* could not send 'open', fail */ | ||
2561 | retval = ZFCP_ERP_FAILED; | ||
2562 | goto out; | ||
2563 | } | ||
2564 | retval = ZFCP_ERP_CONTINUES; | ||
2565 | out: | ||
2566 | return retval; | ||
2567 | } | 1022 | } |
2568 | 1023 | ||
2569 | /* | 1024 | static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) |
2570 | * function: | ||
2571 | * | ||
2572 | * purpose: | ||
2573 | * | ||
2574 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2575 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2576 | */ | ||
2577 | static int | ||
2578 | zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action) | ||
2579 | { | 1025 | { |
2580 | int retval; | 1026 | int retval = zfcp_fsf_open_unit(erp_action); |
2581 | 1027 | if (retval == -ENOMEM) | |
2582 | retval = zfcp_ns_gid_pn_request(erp_action); | 1028 | return ZFCP_ERP_NOMEM; |
2583 | if (retval == -ENOMEM) { | 1029 | erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; |
2584 | retval = ZFCP_ERP_NOMEM; | 1030 | if (retval) |
2585 | goto out; | 1031 | return ZFCP_ERP_FAILED; |
2586 | } | 1032 | return ZFCP_ERP_CONTINUES; |
2587 | erp_action->step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; | ||
2588 | if (retval != 0) { | ||
2589 | /* could not send nameserver request, fail */ | ||
2590 | retval = ZFCP_ERP_FAILED; | ||
2591 | goto out; | ||
2592 | } | ||
2593 | retval = ZFCP_ERP_CONTINUES; | ||
2594 | out: | ||
2595 | return retval; | ||
2596 | } | 1033 | } |
2597 | 1034 | ||
2598 | /* | 1035 | static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) |
2599 | * function: | ||
2600 | * | ||
2601 | * purpose: this routine executes the 'Reopen Unit' action | ||
2602 | * currently no retries | ||
2603 | * | ||
2604 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2605 | * ZFCP_ERP_SUCCEEDED - action finished successfully | ||
2606 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2607 | */ | ||
2608 | static int | ||
2609 | zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) | ||
2610 | { | 1036 | { |
2611 | int retval = ZFCP_ERP_FAILED; | ||
2612 | struct zfcp_unit *unit = erp_action->unit; | 1037 | struct zfcp_unit *unit = erp_action->unit; |
2613 | 1038 | ||
2614 | switch (erp_action->step) { | 1039 | switch (erp_action->step) { |
2615 | |||
2616 | /* | ||
2617 | * FIXME: | ||
2618 | * the ULP spec. begs for waiting for oustanding commands | ||
2619 | */ | ||
2620 | case ZFCP_ERP_STEP_UNINITIALIZED: | 1040 | case ZFCP_ERP_STEP_UNINITIALIZED: |
2621 | zfcp_erp_unit_strategy_clearstati(unit); | 1041 | zfcp_erp_unit_strategy_clearstati(unit); |
2622 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) { | 1042 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) |
2623 | ZFCP_LOG_DEBUG("unit 0x%016Lx is open -> " | 1043 | return zfcp_erp_unit_strategy_close(erp_action); |
2624 | "trying close\n", unit->fcp_lun); | 1044 | /* already closed, fall through */ |
2625 | retval = zfcp_erp_unit_strategy_close(erp_action); | ||
2626 | break; | ||
2627 | } | ||
2628 | /* else it's already closed, fall through */ | ||
2629 | case ZFCP_ERP_STEP_UNIT_CLOSING: | 1045 | case ZFCP_ERP_STEP_UNIT_CLOSING: |
2630 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) { | 1046 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) |
2631 | ZFCP_LOG_DEBUG("close failed for unit 0x%016Lx\n", | 1047 | return ZFCP_ERP_FAILED; |
2632 | unit->fcp_lun); | 1048 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) |
2633 | retval = ZFCP_ERP_FAILED; | 1049 | return ZFCP_ERP_EXIT; |
2634 | } else { | 1050 | return zfcp_erp_unit_strategy_open(erp_action); |
2635 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) | ||
2636 | retval = ZFCP_ERP_EXIT; | ||
2637 | else { | ||
2638 | ZFCP_LOG_DEBUG("unit 0x%016Lx is not open -> " | ||
2639 | "trying open\n", unit->fcp_lun); | ||
2640 | retval = | ||
2641 | zfcp_erp_unit_strategy_open(erp_action); | ||
2642 | } | ||
2643 | } | ||
2644 | break; | ||
2645 | 1051 | ||
2646 | case ZFCP_ERP_STEP_UNIT_OPENING: | 1052 | case ZFCP_ERP_STEP_UNIT_OPENING: |
2647 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) { | 1053 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) |
2648 | ZFCP_LOG_DEBUG("unit 0x%016Lx is open\n", | 1054 | return ZFCP_ERP_SUCCEEDED; |
2649 | unit->fcp_lun); | ||
2650 | retval = ZFCP_ERP_SUCCEEDED; | ||
2651 | } else { | ||
2652 | ZFCP_LOG_DEBUG("open failed for unit 0x%016Lx\n", | ||
2653 | unit->fcp_lun); | ||
2654 | retval = ZFCP_ERP_FAILED; | ||
2655 | } | ||
2656 | break; | ||
2657 | } | 1055 | } |
2658 | 1056 | return ZFCP_ERP_FAILED; | |
2659 | return retval; | ||
2660 | } | 1057 | } |
2661 | 1058 | ||
2662 | static int | 1059 | static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) |
2663 | zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) | ||
2664 | { | 1060 | { |
2665 | int retval = 0; | 1061 | switch (result) { |
2666 | 1062 | case ZFCP_ERP_SUCCEEDED : | |
2667 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | | 1063 | atomic_set(&unit->erp_counter, 0); |
2668 | ZFCP_STATUS_COMMON_CLOSING | | 1064 | zfcp_erp_unit_unblock(unit); |
2669 | ZFCP_STATUS_COMMON_ACCESS_DENIED | | 1065 | break; |
2670 | ZFCP_STATUS_UNIT_SHARED | | 1066 | case ZFCP_ERP_FAILED : |
2671 | ZFCP_STATUS_UNIT_READONLY, | 1067 | atomic_inc(&unit->erp_counter); |
2672 | &unit->status); | 1068 | if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) |
1069 | zfcp_erp_unit_failed(unit, 21, NULL); | ||
1070 | break; | ||
1071 | } | ||
2673 | 1072 | ||
2674 | return retval; | 1073 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
1074 | zfcp_erp_unit_block(unit, 0); | ||
1075 | result = ZFCP_ERP_EXIT; | ||
1076 | } | ||
1077 | return result; | ||
2675 | } | 1078 | } |
2676 | 1079 | ||
2677 | /* | 1080 | static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) |
2678 | * function: | ||
2679 | * | ||
2680 | * purpose: | ||
2681 | * | ||
2682 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2683 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2684 | */ | ||
2685 | static int | ||
2686 | zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) | ||
2687 | { | 1081 | { |
2688 | int retval; | 1082 | switch (result) { |
1083 | case ZFCP_ERP_SUCCEEDED : | ||
1084 | atomic_set(&port->erp_counter, 0); | ||
1085 | zfcp_erp_port_unblock(port); | ||
1086 | break; | ||
2689 | 1087 | ||
2690 | retval = zfcp_fsf_close_unit(erp_action); | 1088 | case ZFCP_ERP_FAILED : |
2691 | if (retval == -ENOMEM) { | 1089 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) { |
2692 | retval = ZFCP_ERP_NOMEM; | 1090 | zfcp_erp_port_block(port, 0); |
2693 | goto out; | 1091 | result = ZFCP_ERP_EXIT; |
2694 | } | 1092 | } |
2695 | erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; | 1093 | atomic_inc(&port->erp_counter); |
2696 | if (retval != 0) { | 1094 | if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) |
2697 | /* could not send 'close', fail */ | 1095 | zfcp_erp_port_failed(port, 22, NULL); |
2698 | retval = ZFCP_ERP_FAILED; | 1096 | break; |
2699 | goto out; | ||
2700 | } | 1097 | } |
2701 | retval = ZFCP_ERP_CONTINUES; | ||
2702 | 1098 | ||
2703 | out: | 1099 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
2704 | return retval; | 1100 | zfcp_erp_port_block(port, 0); |
1101 | result = ZFCP_ERP_EXIT; | ||
1102 | } | ||
1103 | return result; | ||
2705 | } | 1104 | } |
2706 | 1105 | ||
2707 | /* | 1106 | static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, |
2708 | * function: | 1107 | int result) |
2709 | * | ||
2710 | * purpose: | ||
2711 | * | ||
2712 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2713 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2714 | */ | ||
2715 | static int | ||
2716 | zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) | ||
2717 | { | 1108 | { |
2718 | int retval; | 1109 | switch (result) { |
1110 | case ZFCP_ERP_SUCCEEDED : | ||
1111 | atomic_set(&adapter->erp_counter, 0); | ||
1112 | zfcp_erp_adapter_unblock(adapter); | ||
1113 | break; | ||
2719 | 1114 | ||
2720 | retval = zfcp_fsf_open_unit(erp_action); | 1115 | case ZFCP_ERP_FAILED : |
2721 | if (retval == -ENOMEM) { | 1116 | atomic_inc(&adapter->erp_counter); |
2722 | retval = ZFCP_ERP_NOMEM; | 1117 | if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) |
2723 | goto out; | 1118 | zfcp_erp_adapter_failed(adapter, 23, NULL); |
2724 | } | 1119 | break; |
2725 | erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; | ||
2726 | if (retval != 0) { | ||
2727 | /* could not send 'open', fail */ | ||
2728 | retval = ZFCP_ERP_FAILED; | ||
2729 | goto out; | ||
2730 | } | 1120 | } |
2731 | retval = ZFCP_ERP_CONTINUES; | ||
2732 | out: | ||
2733 | return retval; | ||
2734 | } | ||
2735 | 1121 | ||
2736 | void zfcp_erp_start_timer(struct zfcp_fsf_req *fsf_req) | 1122 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
2737 | { | 1123 | zfcp_erp_adapter_block(adapter, 0); |
2738 | BUG_ON(!fsf_req->erp_action); | 1124 | result = ZFCP_ERP_EXIT; |
2739 | fsf_req->timer.function = zfcp_erp_timeout_handler; | 1125 | } |
2740 | fsf_req->timer.data = (unsigned long) fsf_req->erp_action; | 1126 | return result; |
2741 | fsf_req->timer.expires = jiffies + ZFCP_ERP_FSFREQ_TIMEOUT; | ||
2742 | add_timer(&fsf_req->timer); | ||
2743 | } | 1127 | } |
2744 | 1128 | ||
2745 | /* | 1129 | static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, |
2746 | * function: | 1130 | int result) |
2747 | * | ||
2748 | * purpose: enqueue the specified error recovery action, if needed | ||
2749 | * | ||
2750 | * returns: | ||
2751 | */ | ||
2752 | static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, | ||
2753 | struct zfcp_port *port, | ||
2754 | struct zfcp_unit *unit, u8 id, void *ref) | ||
2755 | { | 1131 | { |
2756 | int retval = 1, need = want; | 1132 | struct zfcp_adapter *adapter = erp_action->adapter; |
2757 | struct zfcp_erp_action *erp_action = NULL; | 1133 | struct zfcp_port *port = erp_action->port; |
2758 | u32 status = 0; | 1134 | struct zfcp_unit *unit = erp_action->unit; |
2759 | 1135 | ||
2760 | /* | 1136 | switch (erp_action->action) { |
2761 | * We need some rules here which check whether we really need | ||
2762 | * this action or whether we should just drop it. | ||
2763 | * E.g. if there is a unfinished 'Reopen Port' request then we drop a | ||
2764 | * 'Reopen Unit' request for an associated unit since we can't | ||
2765 | * satisfy this request now. A 'Reopen Port' action will trigger | ||
2766 | * 'Reopen Unit' actions when it completes. | ||
2767 | * Thus, there are only actions in the queue which can immediately be | ||
2768 | * executed. This makes the processing of the action queue more | ||
2769 | * efficient. | ||
2770 | */ | ||
2771 | |||
2772 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, | ||
2773 | &adapter->status)) | ||
2774 | return -EIO; | ||
2775 | 1137 | ||
2776 | /* check whether we really need this */ | ||
2777 | switch (want) { | ||
2778 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 1138 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
2779 | if (atomic_test_mask | 1139 | result = zfcp_erp_strategy_check_unit(unit, result); |
2780 | (ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)) { | 1140 | break; |
2781 | goto out; | ||
2782 | } | ||
2783 | if (!atomic_test_mask | ||
2784 | (ZFCP_STATUS_COMMON_RUNNING, &port->status) || | ||
2785 | atomic_test_mask | ||
2786 | (ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { | ||
2787 | goto out; | ||
2788 | } | ||
2789 | if (!atomic_test_mask | ||
2790 | (ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) | ||
2791 | need = ZFCP_ERP_ACTION_REOPEN_PORT; | ||
2792 | /* fall through !!! */ | ||
2793 | |||
2794 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
2795 | if (atomic_test_mask | ||
2796 | (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)) { | ||
2797 | goto out; | ||
2798 | } | ||
2799 | /* fall through !!! */ | ||
2800 | 1141 | ||
2801 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | 1142 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
2802 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | 1143 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
2803 | &port->status)) { | 1144 | result = zfcp_erp_strategy_check_port(port, result); |
2804 | if (port->erp_action.action != | 1145 | break; |
2805 | ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) { | ||
2806 | ZFCP_LOG_INFO("dropped erp action %i (port " | ||
2807 | "0x%016Lx, action in use: %i)\n", | ||
2808 | want, port->wwpn, | ||
2809 | port->erp_action.action); | ||
2810 | } | ||
2811 | goto out; | ||
2812 | } | ||
2813 | if (!atomic_test_mask | ||
2814 | (ZFCP_STATUS_COMMON_RUNNING, &adapter->status) || | ||
2815 | atomic_test_mask | ||
2816 | (ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { | ||
2817 | goto out; | ||
2818 | } | ||
2819 | if (!atomic_test_mask | ||
2820 | (ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) | ||
2821 | need = ZFCP_ERP_ACTION_REOPEN_ADAPTER; | ||
2822 | /* fall through !!! */ | ||
2823 | 1146 | ||
2824 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 1147 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
2825 | if (atomic_test_mask | 1148 | result = zfcp_erp_strategy_check_adapter(adapter, result); |
2826 | (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)) { | ||
2827 | goto out; | ||
2828 | } | ||
2829 | break; | 1149 | break; |
2830 | |||
2831 | default: | ||
2832 | ZFCP_LOG_NORMAL("bug: unknown erp action requested " | ||
2833 | "on adapter %s (action=%d)\n", | ||
2834 | zfcp_get_busid_by_adapter(adapter), want); | ||
2835 | goto out; | ||
2836 | } | 1150 | } |
1151 | return result; | ||
1152 | } | ||
2837 | 1153 | ||
2838 | /* check whether we need something stronger first */ | 1154 | static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status) |
2839 | if (need) { | 1155 | { |
2840 | ZFCP_LOG_DEBUG("stronger erp action %d needed before " | 1156 | int status = atomic_read(target_status); |
2841 | "erp action %d on adapter %s\n", | ||
2842 | need, want, zfcp_get_busid_by_adapter(adapter)); | ||
2843 | } | ||
2844 | 1157 | ||
2845 | /* mark adapter to have some error recovery pending */ | 1158 | if ((status & ZFCP_STATUS_COMMON_RUNNING) && |
2846 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); | 1159 | (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) |
1160 | return 1; /* take it online */ | ||
2847 | 1161 | ||
2848 | /* setup error recovery action */ | 1162 | if (!(status & ZFCP_STATUS_COMMON_RUNNING) && |
2849 | switch (need) { | 1163 | !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) |
1164 | return 1; /* take it offline */ | ||
2850 | 1165 | ||
2851 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 1166 | return 0; |
2852 | zfcp_unit_get(unit); | 1167 | } |
2853 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); | 1168 | |
2854 | erp_action = &unit->erp_action; | 1169 | static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) |
2855 | if (!atomic_test_mask | 1170 | { |
2856 | (ZFCP_STATUS_COMMON_RUNNING, &unit->status)) | 1171 | int action = act->action; |
2857 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | 1172 | struct zfcp_adapter *adapter = act->adapter; |
1173 | struct zfcp_port *port = act->port; | ||
1174 | struct zfcp_unit *unit = act->unit; | ||
1175 | u32 erp_status = act->status; | ||
1176 | |||
1177 | switch (action) { | ||
1178 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1179 | if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) { | ||
1180 | _zfcp_erp_adapter_reopen(adapter, | ||
1181 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
1182 | 67, NULL); | ||
1183 | return ZFCP_ERP_EXIT; | ||
1184 | } | ||
2858 | break; | 1185 | break; |
2859 | 1186 | ||
2860 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
2861 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | 1187 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
2862 | zfcp_port_get(port); | 1188 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
2863 | zfcp_erp_action_dismiss_port(port); | 1189 | if (zfcp_erp_strat_change_det(&port->status, erp_status)) { |
2864 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); | 1190 | _zfcp_erp_port_reopen(port, |
2865 | erp_action = &port->erp_action; | 1191 | ZFCP_STATUS_COMMON_ERP_FAILED, |
2866 | if (!atomic_test_mask | 1192 | 68, NULL); |
2867 | (ZFCP_STATUS_COMMON_RUNNING, &port->status)) | 1193 | return ZFCP_ERP_EXIT; |
2868 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | 1194 | } |
2869 | break; | 1195 | break; |
2870 | 1196 | ||
2871 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 1197 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
2872 | zfcp_adapter_get(adapter); | 1198 | if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { |
2873 | zfcp_erp_action_dismiss_adapter(adapter); | 1199 | _zfcp_erp_unit_reopen(unit, |
2874 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); | 1200 | ZFCP_STATUS_COMMON_ERP_FAILED, |
2875 | erp_action = &adapter->erp_action; | 1201 | 69, NULL); |
2876 | if (!atomic_test_mask | 1202 | return ZFCP_ERP_EXIT; |
2877 | (ZFCP_STATUS_COMMON_RUNNING, &adapter->status)) | 1203 | } |
2878 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | ||
2879 | break; | 1204 | break; |
2880 | } | 1205 | } |
2881 | 1206 | return ret; | |
2882 | memset(erp_action, 0, sizeof (struct zfcp_erp_action)); | ||
2883 | erp_action->adapter = adapter; | ||
2884 | erp_action->port = port; | ||
2885 | erp_action->unit = unit; | ||
2886 | erp_action->action = need; | ||
2887 | erp_action->status = status; | ||
2888 | |||
2889 | ++adapter->erp_total_count; | ||
2890 | |||
2891 | /* finally put it into 'ready' queue and kick erp thread */ | ||
2892 | list_add_tail(&erp_action->list, &adapter->erp_ready_head); | ||
2893 | up(&adapter->erp_ready_sem); | ||
2894 | zfcp_rec_dbf_event_thread(1, adapter, 0); | ||
2895 | retval = 0; | ||
2896 | out: | ||
2897 | zfcp_rec_dbf_event_trigger(id, ref, want, need, erp_action, | ||
2898 | adapter, port, unit); | ||
2899 | return retval; | ||
2900 | } | 1207 | } |
2901 | 1208 | ||
2902 | static int | 1209 | static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) |
2903 | zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) | ||
2904 | { | 1210 | { |
2905 | int retval = 0; | ||
2906 | struct zfcp_adapter *adapter = erp_action->adapter; | 1211 | struct zfcp_adapter *adapter = erp_action->adapter; |
2907 | 1212 | ||
2908 | --adapter->erp_total_count; | 1213 | adapter->erp_total_count--; |
2909 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { | 1214 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { |
2910 | --adapter->erp_low_mem_count; | 1215 | adapter->erp_low_mem_count--; |
2911 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; | 1216 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; |
2912 | } | 1217 | } |
2913 | 1218 | ||
@@ -2919,141 +1224,458 @@ zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) | |||
2919 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | 1224 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, |
2920 | &erp_action->unit->status); | 1225 | &erp_action->unit->status); |
2921 | break; | 1226 | break; |
1227 | |||
2922 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | 1228 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
2923 | case ZFCP_ERP_ACTION_REOPEN_PORT: | 1229 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
2924 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | 1230 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, |
2925 | &erp_action->port->status); | 1231 | &erp_action->port->status); |
2926 | break; | 1232 | break; |
1233 | |||
2927 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 1234 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
2928 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | 1235 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, |
2929 | &erp_action->adapter->status); | 1236 | &erp_action->adapter->status); |
2930 | break; | 1237 | break; |
2931 | default: | ||
2932 | /* bug */ | ||
2933 | break; | ||
2934 | } | 1238 | } |
2935 | return retval; | ||
2936 | } | 1239 | } |
2937 | 1240 | ||
2938 | /** | 1241 | struct zfcp_erp_add_work { |
2939 | * zfcp_erp_action_cleanup | 1242 | struct zfcp_unit *unit; |
2940 | * | 1243 | struct work_struct work; |
2941 | * Register unit with scsi stack if appropriate and fix reference counts. | 1244 | }; |
2942 | * Note: Temporary units are not registered with scsi stack. | 1245 | |
2943 | */ | 1246 | static void zfcp_erp_scsi_scan(struct work_struct *work) |
2944 | static void | ||
2945 | zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, | ||
2946 | struct zfcp_port *port, struct zfcp_unit *unit, | ||
2947 | int result) | ||
2948 | { | 1247 | { |
2949 | switch (action) { | 1248 | struct zfcp_erp_add_work *p = |
1249 | container_of(work, struct zfcp_erp_add_work, work); | ||
1250 | struct zfcp_unit *unit = p->unit; | ||
1251 | struct fc_rport *rport = unit->port->rport; | ||
1252 | scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, | ||
1253 | unit->scsi_lun, 0); | ||
1254 | atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); | ||
1255 | zfcp_unit_put(unit); | ||
1256 | kfree(p); | ||
1257 | } | ||
1258 | |||
1259 | static void zfcp_erp_schedule_work(struct zfcp_unit *unit) | ||
1260 | { | ||
1261 | struct zfcp_erp_add_work *p; | ||
1262 | |||
1263 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
1264 | if (!p) { | ||
1265 | dev_err(&unit->port->adapter->ccw_device->dev, | ||
1266 | "Out of resources. Could not register unit " | ||
1267 | "0x%016Lx on port 0x%016Lx with SCSI stack.\n", | ||
1268 | unit->fcp_lun, unit->port->wwpn); | ||
1269 | return; | ||
1270 | } | ||
1271 | |||
1272 | zfcp_unit_get(unit); | ||
1273 | atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); | ||
1274 | INIT_WORK(&p->work, zfcp_erp_scsi_scan); | ||
1275 | p->unit = unit; | ||
1276 | schedule_work(&p->work); | ||
1277 | } | ||
1278 | |||
1279 | static void zfcp_erp_rport_register(struct zfcp_port *port) | ||
1280 | { | ||
1281 | struct fc_rport_identifiers ids; | ||
1282 | ids.node_name = port->wwnn; | ||
1283 | ids.port_name = port->wwpn; | ||
1284 | ids.port_id = port->d_id; | ||
1285 | ids.roles = FC_RPORT_ROLE_FCP_TARGET; | ||
1286 | port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); | ||
1287 | if (!port->rport) { | ||
1288 | dev_err(&port->adapter->ccw_device->dev, | ||
1289 | "Failed registration of rport " | ||
1290 | "0x%016Lx.\n", port->wwpn); | ||
1291 | return; | ||
1292 | } | ||
1293 | |||
1294 | scsi_target_unblock(&port->rport->dev); | ||
1295 | port->rport->maxframe_size = port->maxframe_size; | ||
1296 | port->rport->supported_classes = port->supported_classes; | ||
1297 | } | ||
1298 | |||
1299 | static void zfcp_erp_rports_del(struct zfcp_adapter *adapter) | ||
1300 | { | ||
1301 | struct zfcp_port *port; | ||
1302 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
1303 | if (port->rport && !(atomic_read(&port->status) & | ||
1304 | ZFCP_STATUS_PORT_WKA)) { | ||
1305 | fc_remote_port_delete(port->rport); | ||
1306 | port->rport = NULL; | ||
1307 | } | ||
1308 | } | ||
1309 | |||
1310 | static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) | ||
1311 | { | ||
1312 | struct zfcp_adapter *adapter = act->adapter; | ||
1313 | struct zfcp_port *port = act->port; | ||
1314 | struct zfcp_unit *unit = act->unit; | ||
1315 | |||
1316 | switch (act->action) { | ||
2950 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 1317 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
2951 | if ((result == ZFCP_ERP_SUCCEEDED) | 1318 | if ((result == ZFCP_ERP_SUCCEEDED) && |
2952 | && (!atomic_test_mask(ZFCP_STATUS_UNIT_TEMPORARY, | 1319 | !unit->device && port->rport) { |
2953 | &unit->status)) | ||
2954 | && !unit->device | ||
2955 | && port->rport) { | ||
2956 | atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, | 1320 | atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, |
2957 | &unit->status); | 1321 | &unit->status); |
2958 | if (atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, | 1322 | if (!(atomic_read(&unit->status) & |
2959 | &unit->status) == 0) | 1323 | ZFCP_STATUS_UNIT_SCSI_WORK_PENDING)) |
2960 | zfcp_erp_schedule_work(unit); | 1324 | zfcp_erp_schedule_work(unit); |
2961 | } | 1325 | } |
2962 | zfcp_unit_put(unit); | 1326 | zfcp_unit_put(unit); |
2963 | break; | 1327 | break; |
1328 | |||
2964 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | 1329 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
2965 | case ZFCP_ERP_ACTION_REOPEN_PORT: | 1330 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
2966 | if (atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, | 1331 | if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN) { |
2967 | &port->status)) { | ||
2968 | zfcp_port_put(port); | 1332 | zfcp_port_put(port); |
2969 | break; | 1333 | return; |
2970 | } | ||
2971 | |||
2972 | if ((result == ZFCP_ERP_SUCCEEDED) | ||
2973 | && !port->rport) { | ||
2974 | struct fc_rport_identifiers ids; | ||
2975 | ids.node_name = port->wwnn; | ||
2976 | ids.port_name = port->wwpn; | ||
2977 | ids.port_id = port->d_id; | ||
2978 | ids.roles = FC_RPORT_ROLE_FCP_TARGET; | ||
2979 | port->rport = | ||
2980 | fc_remote_port_add(adapter->scsi_host, 0, &ids); | ||
2981 | if (!port->rport) | ||
2982 | ZFCP_LOG_NORMAL("failed registration of rport" | ||
2983 | "(adapter %s, wwpn=0x%016Lx)\n", | ||
2984 | zfcp_get_busid_by_port(port), | ||
2985 | port->wwpn); | ||
2986 | else { | ||
2987 | scsi_target_unblock(&port->rport->dev); | ||
2988 | port->rport->maxframe_size = port->maxframe_size; | ||
2989 | port->rport->supported_classes = | ||
2990 | port->supported_classes; | ||
2991 | } | ||
2992 | } | 1334 | } |
1335 | if ((result == ZFCP_ERP_SUCCEEDED) && !port->rport) | ||
1336 | zfcp_erp_rport_register(port); | ||
2993 | if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) { | 1337 | if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) { |
2994 | fc_remote_port_delete(port->rport); | 1338 | fc_remote_port_delete(port->rport); |
2995 | port->rport = NULL; | 1339 | port->rport = NULL; |
2996 | } | 1340 | } |
2997 | zfcp_port_put(port); | 1341 | zfcp_port_put(port); |
2998 | break; | 1342 | break; |
1343 | |||
2999 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 1344 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
3000 | if (result != ZFCP_ERP_SUCCEEDED) { | 1345 | if (result != ZFCP_ERP_SUCCEEDED) |
3001 | list_for_each_entry(port, &adapter->port_list_head, list) | 1346 | zfcp_erp_rports_del(adapter); |
3002 | if (port->rport && | ||
3003 | !atomic_test_mask(ZFCP_STATUS_PORT_WKA, | ||
3004 | &port->status)) { | ||
3005 | fc_remote_port_delete(port->rport); | ||
3006 | port->rport = NULL; | ||
3007 | } | ||
3008 | } | ||
3009 | zfcp_adapter_put(adapter); | 1347 | zfcp_adapter_put(adapter); |
3010 | break; | 1348 | break; |
3011 | default: | ||
3012 | break; | ||
3013 | } | 1349 | } |
3014 | } | 1350 | } |
3015 | 1351 | ||
1352 | static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) | ||
1353 | { | ||
1354 | switch (erp_action->action) { | ||
1355 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1356 | return zfcp_erp_adapter_strategy(erp_action); | ||
1357 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
1358 | return zfcp_erp_port_forced_strategy(erp_action); | ||
1359 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
1360 | return zfcp_erp_port_strategy(erp_action); | ||
1361 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
1362 | return zfcp_erp_unit_strategy(erp_action); | ||
1363 | } | ||
1364 | return ZFCP_ERP_FAILED; | ||
1365 | } | ||
3016 | 1366 | ||
3017 | static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) | 1367 | static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) |
3018 | { | 1368 | { |
3019 | struct zfcp_port *port; | 1369 | int retval; |
1370 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1371 | unsigned long flags; | ||
3020 | 1372 | ||
3021 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)) | 1373 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
3022 | zfcp_erp_action_dismiss(&adapter->erp_action); | 1374 | write_lock(&adapter->erp_lock); |
3023 | else | 1375 | |
3024 | list_for_each_entry(port, &adapter->port_list_head, list) | 1376 | zfcp_erp_strategy_check_fsfreq(erp_action); |
3025 | zfcp_erp_action_dismiss_port(port); | 1377 | |
1378 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { | ||
1379 | zfcp_erp_action_dequeue(erp_action); | ||
1380 | retval = ZFCP_ERP_DISMISSED; | ||
1381 | goto unlock; | ||
1382 | } | ||
1383 | |||
1384 | zfcp_erp_action_to_running(erp_action); | ||
1385 | |||
1386 | /* no lock to allow for blocking operations */ | ||
1387 | write_unlock(&adapter->erp_lock); | ||
1388 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1389 | retval = zfcp_erp_strategy_do_action(erp_action); | ||
1390 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1391 | write_lock(&adapter->erp_lock); | ||
1392 | |||
1393 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) | ||
1394 | retval = ZFCP_ERP_CONTINUES; | ||
1395 | |||
1396 | switch (retval) { | ||
1397 | case ZFCP_ERP_NOMEM: | ||
1398 | if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { | ||
1399 | ++adapter->erp_low_mem_count; | ||
1400 | erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; | ||
1401 | } | ||
1402 | if (adapter->erp_total_count == adapter->erp_low_mem_count) | ||
1403 | _zfcp_erp_adapter_reopen(adapter, 0, 66, NULL); | ||
1404 | else { | ||
1405 | zfcp_erp_strategy_memwait(erp_action); | ||
1406 | retval = ZFCP_ERP_CONTINUES; | ||
1407 | } | ||
1408 | goto unlock; | ||
1409 | |||
1410 | case ZFCP_ERP_CONTINUES: | ||
1411 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { | ||
1412 | --adapter->erp_low_mem_count; | ||
1413 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; | ||
1414 | } | ||
1415 | goto unlock; | ||
1416 | } | ||
1417 | |||
1418 | retval = zfcp_erp_strategy_check_target(erp_action, retval); | ||
1419 | zfcp_erp_action_dequeue(erp_action); | ||
1420 | retval = zfcp_erp_strategy_statechange(erp_action, retval); | ||
1421 | if (retval == ZFCP_ERP_EXIT) | ||
1422 | goto unlock; | ||
1423 | zfcp_erp_strategy_followup_actions(erp_action); | ||
1424 | |||
1425 | unlock: | ||
1426 | write_unlock(&adapter->erp_lock); | ||
1427 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1428 | |||
1429 | if (retval != ZFCP_ERP_CONTINUES) | ||
1430 | zfcp_erp_action_cleanup(erp_action, retval); | ||
1431 | |||
1432 | return retval; | ||
3026 | } | 1433 | } |
3027 | 1434 | ||
3028 | static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) | 1435 | static int zfcp_erp_thread(void *data) |
3029 | { | 1436 | { |
3030 | struct zfcp_unit *unit; | 1437 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; |
1438 | struct list_head *next; | ||
1439 | struct zfcp_erp_action *act; | ||
1440 | unsigned long flags; | ||
3031 | 1441 | ||
3032 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)) | 1442 | daemonize("zfcperp%s", adapter->ccw_device->dev.bus_id); |
3033 | zfcp_erp_action_dismiss(&port->erp_action); | 1443 | /* Block all signals */ |
1444 | siginitsetinv(¤t->blocked, 0); | ||
1445 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
1446 | wake_up(&adapter->erp_thread_wqh); | ||
1447 | |||
1448 | while (!(atomic_read(&adapter->status) & | ||
1449 | ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) { | ||
1450 | write_lock_irqsave(&adapter->erp_lock, flags); | ||
1451 | next = adapter->erp_ready_head.next; | ||
1452 | write_unlock_irqrestore(&adapter->erp_lock, flags); | ||
1453 | |||
1454 | if (next != &adapter->erp_ready_head) { | ||
1455 | act = list_entry(next, struct zfcp_erp_action, list); | ||
1456 | |||
1457 | /* there is more to come after dismission, no notify */ | ||
1458 | if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED) | ||
1459 | zfcp_erp_wakeup(adapter); | ||
1460 | } | ||
1461 | |||
1462 | zfcp_rec_dbf_event_thread(4, adapter); | ||
1463 | down_interruptible(&adapter->erp_ready_sem); | ||
1464 | zfcp_rec_dbf_event_thread(5, adapter); | ||
1465 | } | ||
1466 | |||
1467 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
1468 | wake_up(&adapter->erp_thread_wqh); | ||
1469 | |||
1470 | return 0; | ||
1471 | } | ||
1472 | |||
1473 | /** | ||
1474 | * zfcp_erp_thread_setup - Start ERP thread for adapter | ||
1475 | * @adapter: Adapter to start the ERP thread for | ||
1476 | * | ||
1477 | * Returns 0 on success or error code from kernel_thread() | ||
1478 | */ | ||
1479 | int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) | ||
1480 | { | ||
1481 | int retval; | ||
1482 | |||
1483 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
1484 | retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); | ||
1485 | if (retval < 0) { | ||
1486 | dev_err(&adapter->ccw_device->dev, | ||
1487 | "Creation of ERP thread failed.\n"); | ||
1488 | return retval; | ||
1489 | } | ||
1490 | wait_event(adapter->erp_thread_wqh, | ||
1491 | atomic_read(&adapter->status) & | ||
1492 | ZFCP_STATUS_ADAPTER_ERP_THREAD_UP); | ||
1493 | return 0; | ||
1494 | } | ||
1495 | |||
1496 | /** | ||
1497 | * zfcp_erp_thread_kill - Stop ERP thread. | ||
1498 | * @adapter: Adapter where the ERP thread should be stopped. | ||
1499 | * | ||
1500 | * The caller of this routine ensures that the specified adapter has | ||
1501 | * been shut down and that this operation has been completed. Thus, | ||
1502 | * there are no pending erp_actions which would need to be handled | ||
1503 | * here. | ||
1504 | */ | ||
1505 | void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) | ||
1506 | { | ||
1507 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); | ||
1508 | up(&adapter->erp_ready_sem); | ||
1509 | zfcp_rec_dbf_event_thread_lock(2, adapter); | ||
1510 | |||
1511 | wait_event(adapter->erp_thread_wqh, | ||
1512 | !(atomic_read(&adapter->status) & | ||
1513 | ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)); | ||
1514 | |||
1515 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, | ||
1516 | &adapter->status); | ||
1517 | } | ||
1518 | |||
1519 | /** | ||
1520 | * zfcp_erp_adapter_failed - Set adapter status to failed. | ||
1521 | * @adapter: Failed adapter. | ||
1522 | * @id: Event id for debug trace. | ||
1523 | * @ref: Reference for debug trace. | ||
1524 | */ | ||
1525 | void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, u8 id, void *ref) | ||
1526 | { | ||
1527 | zfcp_erp_modify_adapter_status(adapter, id, ref, | ||
1528 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | ||
1529 | dev_err(&adapter->ccw_device->dev, "Adapter ERP failed.\n"); | ||
1530 | } | ||
1531 | |||
1532 | /** | ||
1533 | * zfcp_erp_port_failed - Set port status to failed. | ||
1534 | * @port: Failed port. | ||
1535 | * @id: Event id for debug trace. | ||
1536 | * @ref: Reference for debug trace. | ||
1537 | */ | ||
1538 | void zfcp_erp_port_failed(struct zfcp_port *port, u8 id, void *ref) | ||
1539 | { | ||
1540 | zfcp_erp_modify_port_status(port, id, ref, | ||
1541 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | ||
1542 | |||
1543 | if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA) | ||
1544 | dev_err(&port->adapter->ccw_device->dev, | ||
1545 | "Port ERP failed for WKA port d_id=0x%06x.\n", | ||
1546 | port->d_id); | ||
3034 | else | 1547 | else |
3035 | list_for_each_entry(unit, &port->unit_list_head, list) | 1548 | dev_err(&port->adapter->ccw_device->dev, |
3036 | zfcp_erp_action_dismiss_unit(unit); | 1549 | "Port ERP failed for port wwpn=0x%016Lx.\n", |
1550 | port->wwpn); | ||
3037 | } | 1551 | } |
3038 | 1552 | ||
3039 | static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) | 1553 | /** |
1554 | * zfcp_erp_unit_failed - Set unit status to failed. | ||
1555 | * @unit: Failed unit. | ||
1556 | * @id: Event id for debug trace. | ||
1557 | * @ref: Reference for debug trace. | ||
1558 | */ | ||
1559 | void zfcp_erp_unit_failed(struct zfcp_unit *unit, u8 id, void *ref) | ||
3040 | { | 1560 | { |
3041 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)) | 1561 | zfcp_erp_modify_unit_status(unit, id, ref, |
3042 | zfcp_erp_action_dismiss(&unit->erp_action); | 1562 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); |
1563 | |||
1564 | dev_err(&unit->port->adapter->ccw_device->dev, | ||
1565 | "Unit ERP failed for unit 0x%016Lx on port 0x%016Lx.\n", | ||
1566 | unit->fcp_lun, unit->port->wwpn); | ||
3043 | } | 1567 | } |
3044 | 1568 | ||
3045 | static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) | 1569 | /** |
1570 | * zfcp_erp_wait - wait for completion of error recovery on an adapter | ||
1571 | * @adapter: adapter for which to wait for completion of its error recovery | ||
1572 | */ | ||
1573 | void zfcp_erp_wait(struct zfcp_adapter *adapter) | ||
3046 | { | 1574 | { |
3047 | list_move(&erp_action->list, &erp_action->adapter->erp_running_head); | 1575 | wait_event(adapter->erp_done_wqh, |
3048 | zfcp_rec_dbf_event_action(145, erp_action); | 1576 | !(atomic_read(&adapter->status) & |
1577 | ZFCP_STATUS_ADAPTER_ERP_PENDING)); | ||
1578 | } | ||
1579 | |||
1580 | /** | ||
1581 | * zfcp_erp_modify_adapter_status - change adapter status bits | ||
1582 | * @adapter: adapter to change the status | ||
1583 | * @id: id for the debug trace | ||
1584 | * @ref: reference for the debug trace | ||
1585 | * @mask: status bits to change | ||
1586 | * @set_or_clear: ZFCP_SET or ZFCP_CLEAR | ||
1587 | * | ||
1588 | * Changes in common status bits are propagated to attached ports and units. | ||
1589 | */ | ||
1590 | void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, u8 id, | ||
1591 | void *ref, u32 mask, int set_or_clear) | ||
1592 | { | ||
1593 | struct zfcp_port *port; | ||
1594 | u32 common_mask = mask & ZFCP_COMMON_FLAGS; | ||
1595 | |||
1596 | if (set_or_clear == ZFCP_SET) { | ||
1597 | if (status_change_set(mask, &adapter->status)) | ||
1598 | zfcp_rec_dbf_event_adapter(id, ref, adapter); | ||
1599 | atomic_set_mask(mask, &adapter->status); | ||
1600 | } else { | ||
1601 | if (status_change_clear(mask, &adapter->status)) | ||
1602 | zfcp_rec_dbf_event_adapter(id, ref, adapter); | ||
1603 | atomic_clear_mask(mask, &adapter->status); | ||
1604 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
1605 | atomic_set(&adapter->erp_counter, 0); | ||
1606 | } | ||
1607 | |||
1608 | if (common_mask) | ||
1609 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
1610 | zfcp_erp_modify_port_status(port, id, ref, common_mask, | ||
1611 | set_or_clear); | ||
3049 | } | 1612 | } |
3050 | 1613 | ||
3051 | static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action) | 1614 | /** |
1615 | * zfcp_erp_modify_port_status - change port status bits | ||
1616 | * @port: port to change the status bits | ||
1617 | * @id: id for the debug trace | ||
1618 | * @ref: reference for the debug trace | ||
1619 | * @mask: status bits to change | ||
1620 | * @set_or_clear: ZFCP_SET or ZFCP_CLEAR | ||
1621 | * | ||
1622 | * Changes in common status bits are propagated to attached units. | ||
1623 | */ | ||
1624 | void zfcp_erp_modify_port_status(struct zfcp_port *port, u8 id, void *ref, | ||
1625 | u32 mask, int set_or_clear) | ||
3052 | { | 1626 | { |
3053 | list_move(&erp_action->list, &erp_action->adapter->erp_ready_head); | 1627 | struct zfcp_unit *unit; |
3054 | zfcp_rec_dbf_event_action(146, erp_action); | 1628 | u32 common_mask = mask & ZFCP_COMMON_FLAGS; |
1629 | |||
1630 | if (set_or_clear == ZFCP_SET) { | ||
1631 | if (status_change_set(mask, &port->status)) | ||
1632 | zfcp_rec_dbf_event_port(id, ref, port); | ||
1633 | atomic_set_mask(mask, &port->status); | ||
1634 | } else { | ||
1635 | if (status_change_clear(mask, &port->status)) | ||
1636 | zfcp_rec_dbf_event_port(id, ref, port); | ||
1637 | atomic_clear_mask(mask, &port->status); | ||
1638 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
1639 | atomic_set(&port->erp_counter, 0); | ||
1640 | } | ||
1641 | |||
1642 | if (common_mask) | ||
1643 | list_for_each_entry(unit, &port->unit_list_head, list) | ||
1644 | zfcp_erp_modify_unit_status(unit, id, ref, common_mask, | ||
1645 | set_or_clear); | ||
3055 | } | 1646 | } |
3056 | 1647 | ||
1648 | /** | ||
1649 | * zfcp_erp_modify_unit_status - change unit status bits | ||
1650 | * @unit: unit to change the status bits | ||
1651 | * @id: id for the debug trace | ||
1652 | * @ref: reference for the debug trace | ||
1653 | * @mask: status bits to change | ||
1654 | * @set_or_clear: ZFCP_SET or ZFCP_CLEAR | ||
1655 | */ | ||
1656 | void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u8 id, void *ref, | ||
1657 | u32 mask, int set_or_clear) | ||
1658 | { | ||
1659 | if (set_or_clear == ZFCP_SET) { | ||
1660 | if (status_change_set(mask, &unit->status)) | ||
1661 | zfcp_rec_dbf_event_unit(id, ref, unit); | ||
1662 | atomic_set_mask(mask, &unit->status); | ||
1663 | } else { | ||
1664 | if (status_change_clear(mask, &unit->status)) | ||
1665 | zfcp_rec_dbf_event_unit(id, ref, unit); | ||
1666 | atomic_clear_mask(mask, &unit->status); | ||
1667 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { | ||
1668 | atomic_set(&unit->erp_counter, 0); | ||
1669 | } | ||
1670 | } | ||
1671 | } | ||
1672 | |||
1673 | /** | ||
1674 | * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP | ||
1675 | * @port: The "boxed" port. | ||
1676 | * @id: The debug trace id. | ||
1677 | * @id: Reference for the debug trace. | ||
1678 | */ | ||
3057 | void zfcp_erp_port_boxed(struct zfcp_port *port, u8 id, void *ref) | 1679 | void zfcp_erp_port_boxed(struct zfcp_port *port, u8 id, void *ref) |
3058 | { | 1680 | { |
3059 | unsigned long flags; | 1681 | unsigned long flags; |
@@ -3065,6 +1687,12 @@ void zfcp_erp_port_boxed(struct zfcp_port *port, u8 id, void *ref) | |||
3065 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); | 1687 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
3066 | } | 1688 | } |
3067 | 1689 | ||
1690 | /** | ||
1691 | * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP | ||
1692 | * @port: The "boxed" unit. | ||
1693 | * @id: The debug trace id. | ||
1694 | * @id: Reference for the debug trace. | ||
1695 | */ | ||
3068 | void zfcp_erp_unit_boxed(struct zfcp_unit *unit, u8 id, void *ref) | 1696 | void zfcp_erp_unit_boxed(struct zfcp_unit *unit, u8 id, void *ref) |
3069 | { | 1697 | { |
3070 | zfcp_erp_modify_unit_status(unit, id, ref, | 1698 | zfcp_erp_modify_unit_status(unit, id, ref, |
@@ -3072,6 +1700,15 @@ void zfcp_erp_unit_boxed(struct zfcp_unit *unit, u8 id, void *ref) | |||
3072 | zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); | 1700 | zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
3073 | } | 1701 | } |
3074 | 1702 | ||
1703 | /** | ||
1704 | * zfcp_erp_port_access_denied - Adapter denied access to port. | ||
1705 | * @port: port where access has been denied | ||
1706 | * @id: id for debug trace | ||
1707 | * @ref: reference for debug trace | ||
1708 | * | ||
1709 | * Since the adapter has denied access, stop using the port and the | ||
1710 | * attached units. | ||
1711 | */ | ||
3075 | void zfcp_erp_port_access_denied(struct zfcp_port *port, u8 id, void *ref) | 1712 | void zfcp_erp_port_access_denied(struct zfcp_port *port, u8 id, void *ref) |
3076 | { | 1713 | { |
3077 | unsigned long flags; | 1714 | unsigned long flags; |
@@ -3083,6 +1720,14 @@ void zfcp_erp_port_access_denied(struct zfcp_port *port, u8 id, void *ref) | |||
3083 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 1720 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
3084 | } | 1721 | } |
3085 | 1722 | ||
1723 | /** | ||
1724 | * zfcp_erp_unit_access_denied - Adapter denied access to unit. | ||
1725 | * @unit: unit where access has been denied | ||
1726 | * @id: id for debug trace | ||
1727 | * @ref: reference for debug trace | ||
1728 | * | ||
1729 | * Since the adapter has denied access, stop using the unit. | ||
1730 | */ | ||
3086 | void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, u8 id, void *ref) | 1731 | void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, u8 id, void *ref) |
3087 | { | 1732 | { |
3088 | zfcp_erp_modify_unit_status(unit, id, ref, | 1733 | zfcp_erp_modify_unit_status(unit, id, ref, |
@@ -3090,67 +1735,54 @@ void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, u8 id, void *ref) | |||
3090 | ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); | 1735 | ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); |
3091 | } | 1736 | } |
3092 | 1737 | ||
3093 | void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, u8 id, | 1738 | static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, u8 id, |
3094 | void *ref) | 1739 | void *ref) |
3095 | { | 1740 | { |
3096 | struct zfcp_port *port; | 1741 | int status = atomic_read(&unit->status); |
3097 | unsigned long flags; | 1742 | if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | |
3098 | 1743 | ZFCP_STATUS_COMMON_ACCESS_BOXED))) | |
3099 | if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) | ||
3100 | return; | 1744 | return; |
3101 | 1745 | ||
3102 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 1746 | zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
3103 | if (adapter->nameserver_port) | ||
3104 | zfcp_erp_port_access_changed(adapter->nameserver_port, id, ref); | ||
3105 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
3106 | if (port != adapter->nameserver_port) | ||
3107 | zfcp_erp_port_access_changed(port, id, ref); | ||
3108 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
3109 | } | 1747 | } |
3110 | 1748 | ||
3111 | void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id, void *ref) | 1749 | static void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id, |
1750 | void *ref) | ||
3112 | { | 1751 | { |
3113 | struct zfcp_adapter *adapter = port->adapter; | ||
3114 | struct zfcp_unit *unit; | 1752 | struct zfcp_unit *unit; |
1753 | int status = atomic_read(&port->status); | ||
3115 | 1754 | ||
3116 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, | 1755 | if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | |
3117 | &port->status) && | 1756 | ZFCP_STATUS_COMMON_ACCESS_BOXED))) { |
3118 | !atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_BOXED, | 1757 | if (!(status & ZFCP_STATUS_PORT_WKA)) |
3119 | &port->status)) { | ||
3120 | if (!atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) | ||
3121 | list_for_each_entry(unit, &port->unit_list_head, list) | 1758 | list_for_each_entry(unit, &port->unit_list_head, list) |
3122 | zfcp_erp_unit_access_changed(unit, id, ref); | 1759 | zfcp_erp_unit_access_changed(unit, id, ref); |
3123 | return; | 1760 | return; |
3124 | } | 1761 | } |
3125 | 1762 | ||
3126 | ZFCP_LOG_NORMAL("reopen of port 0x%016Lx on adapter %s " | 1763 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
3127 | "(due to ACT update)\n", | ||
3128 | port->wwpn, zfcp_get_busid_by_adapter(adapter)); | ||
3129 | if (zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref)) | ||
3130 | ZFCP_LOG_NORMAL("failed reopen of port" | ||
3131 | "(adapter %s, wwpn=0x%016Lx)\n", | ||
3132 | zfcp_get_busid_by_adapter(adapter), port->wwpn); | ||
3133 | } | 1764 | } |
3134 | 1765 | ||
3135 | void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, u8 id, void *ref) | 1766 | /** |
1767 | * zfcp_erp_adapter_access_changed - Process change in adapter ACT | ||
1768 | * @adapter: Adapter where the Access Control Table (ACT) changed | ||
1769 | * @id: Id for debug trace | ||
1770 | * @ref: Reference for debug trace | ||
1771 | */ | ||
1772 | void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, u8 id, | ||
1773 | void *ref) | ||
3136 | { | 1774 | { |
3137 | struct zfcp_adapter *adapter = unit->port->adapter; | 1775 | struct zfcp_port *port; |
1776 | unsigned long flags; | ||
3138 | 1777 | ||
3139 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, | 1778 | if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) |
3140 | &unit->status) && | ||
3141 | !atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_BOXED, | ||
3142 | &unit->status)) | ||
3143 | return; | 1779 | return; |
3144 | 1780 | ||
3145 | ZFCP_LOG_NORMAL("reopen of unit 0x%016Lx on port 0x%016Lx " | 1781 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
3146 | " on adapter %s (due to ACT update)\n", | 1782 | if (adapter->nameserver_port) |
3147 | unit->fcp_lun, unit->port->wwpn, | 1783 | zfcp_erp_port_access_changed(adapter->nameserver_port, id, ref); |
3148 | zfcp_get_busid_by_adapter(adapter)); | 1784 | list_for_each_entry(port, &adapter->port_list_head, list) |
3149 | if (zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref)) | 1785 | if (port != adapter->nameserver_port) |
3150 | ZFCP_LOG_NORMAL("failed reopen of unit (adapter %s, " | 1786 | zfcp_erp_port_access_changed(port, id, ref); |
3151 | "wwpn=0x%016Lx, fcp_lun=0x%016Lx)\n", | 1787 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
3152 | zfcp_get_busid_by_adapter(adapter), | ||
3153 | unit->port->wwpn, unit->fcp_lun); | ||
3154 | } | 1788 | } |
3155 | |||
3156 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 6abf178fda5d..8065b2b224b7 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -1,22 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * External function declarations. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #ifndef ZFCP_EXT_H | 9 | #ifndef ZFCP_EXT_H |
@@ -24,172 +11,51 @@ | |||
24 | 11 | ||
25 | #include "zfcp_def.h" | 12 | #include "zfcp_def.h" |
26 | 13 | ||
27 | extern struct zfcp_data zfcp_data; | 14 | /* zfcp_aux.c */ |
28 | 15 | extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, | |
29 | /******************************** SYSFS *************************************/ | 16 | fcp_lun_t); |
30 | extern struct attribute_group *zfcp_driver_attr_groups[]; | 17 | extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, |
31 | extern int zfcp_sysfs_adapter_create_files(struct device *); | 18 | wwn_t); |
32 | extern void zfcp_sysfs_adapter_remove_files(struct device *); | 19 | extern int zfcp_adapter_enqueue(struct ccw_device *); |
33 | extern int zfcp_sysfs_port_create_files(struct device *, u32); | 20 | extern void zfcp_adapter_dequeue(struct zfcp_adapter *); |
34 | extern void zfcp_sysfs_port_remove_files(struct device *, u32); | 21 | extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, u32, |
35 | extern int zfcp_sysfs_unit_create_files(struct device *); | 22 | u32); |
36 | extern void zfcp_sysfs_unit_remove_files(struct device *); | 23 | extern void zfcp_port_dequeue(struct zfcp_port *); |
37 | extern void zfcp_sysfs_port_release(struct device *); | ||
38 | extern void zfcp_sysfs_unit_release(struct device *); | ||
39 | |||
40 | /**************************** CONFIGURATION *********************************/ | ||
41 | extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, fcp_lun_t); | ||
42 | extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, wwn_t); | ||
43 | extern struct zfcp_port *zfcp_get_port_by_did(struct zfcp_adapter *, u32); | ||
44 | struct zfcp_adapter *zfcp_get_adapter_by_busid(char *); | ||
45 | extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *); | ||
46 | extern int zfcp_adapter_debug_register(struct zfcp_adapter *); | ||
47 | extern void zfcp_adapter_dequeue(struct zfcp_adapter *); | ||
48 | extern void zfcp_adapter_debug_unregister(struct zfcp_adapter *); | ||
49 | extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, | ||
50 | u32, u32); | ||
51 | extern void zfcp_port_dequeue(struct zfcp_port *); | ||
52 | extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t); | 24 | extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t); |
53 | extern void zfcp_unit_dequeue(struct zfcp_unit *); | 25 | extern void zfcp_unit_dequeue(struct zfcp_unit *); |
54 | 26 | extern int zfcp_reqlist_isempty(struct zfcp_adapter *); | |
55 | /******************************* S/390 IO ************************************/ | 27 | extern void zfcp_sg_free_table(struct scatterlist *, int); |
56 | extern int zfcp_ccw_register(void); | 28 | extern int zfcp_sg_setup_table(struct scatterlist *, int); |
57 | 29 | ||
58 | extern void zfcp_qdio_zero_sbals(struct qdio_buffer **, int, int); | 30 | /* zfcp_ccw.c */ |
59 | extern int zfcp_qdio_allocate(struct zfcp_adapter *); | 31 | extern int zfcp_ccw_register(void); |
60 | extern int zfcp_qdio_allocate_queues(struct zfcp_adapter *); | 32 | |
61 | extern void zfcp_qdio_free_queues(struct zfcp_adapter *); | 33 | /* zfcp_cfdc.c */ |
62 | extern int zfcp_qdio_determine_pci(struct zfcp_qdio_queue *, | 34 | extern struct miscdevice zfcp_cfdc_misc; |
63 | struct zfcp_fsf_req *); | 35 | |
64 | 36 | /* zfcp_dbf.c */ | |
65 | extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req | 37 | extern int zfcp_adapter_debug_register(struct zfcp_adapter *); |
66 | (struct zfcp_fsf_req *, int, int); | 38 | extern void zfcp_adapter_debug_unregister(struct zfcp_adapter *); |
67 | extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr | 39 | extern void zfcp_rec_dbf_event_thread(u8, struct zfcp_adapter *); |
68 | (struct zfcp_fsf_req *); | 40 | extern void zfcp_rec_dbf_event_thread_lock(u8, struct zfcp_adapter *); |
69 | extern int zfcp_qdio_sbals_from_sg | 41 | extern void zfcp_rec_dbf_event_adapter(u8, void *, struct zfcp_adapter *); |
70 | (struct zfcp_fsf_req *, unsigned long, struct scatterlist *, int, int); | 42 | extern void zfcp_rec_dbf_event_port(u8, void *, struct zfcp_port *); |
71 | extern int zfcp_qdio_sbals_from_scsicmnd | 43 | extern void zfcp_rec_dbf_event_unit(u8, void *, struct zfcp_unit *); |
72 | (struct zfcp_fsf_req *, unsigned long, struct scsi_cmnd *); | 44 | extern void zfcp_rec_dbf_event_trigger(u8, void *, u8, u8, void *, |
73 | 45 | struct zfcp_adapter *, | |
74 | |||
75 | /******************************** FSF ****************************************/ | ||
76 | extern int zfcp_fsf_open_port(struct zfcp_erp_action *); | ||
77 | extern int zfcp_fsf_close_port(struct zfcp_erp_action *); | ||
78 | extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *); | ||
79 | |||
80 | extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); | ||
81 | extern int zfcp_fsf_close_unit(struct zfcp_erp_action *); | ||
82 | |||
83 | extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *); | ||
84 | extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *, | ||
85 | struct fsf_qtcb_bottom_config *); | ||
86 | extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *); | ||
87 | extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, | ||
88 | struct fsf_qtcb_bottom_port *); | ||
89 | extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **, | ||
90 | u32, u32, struct zfcp_sg_list *); | ||
91 | extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long); | ||
92 | extern void zfcp_erp_start_timer(struct zfcp_fsf_req *); | ||
93 | extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); | ||
94 | extern int zfcp_fsf_status_read(struct zfcp_adapter *, int); | ||
95 | extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *, | ||
96 | unsigned long *, struct zfcp_fsf_req **); | ||
97 | extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, | ||
98 | struct zfcp_erp_action *); | ||
99 | extern int zfcp_fsf_send_els(struct zfcp_send_els *); | ||
100 | extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, | ||
101 | struct zfcp_unit *, | ||
102 | struct scsi_cmnd *, int, int); | ||
103 | extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *); | ||
104 | extern void zfcp_fsf_incoming_els(struct zfcp_fsf_req *); | ||
105 | extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); | ||
106 | extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_command_task_management( | ||
107 | struct zfcp_adapter *, struct zfcp_unit *, u8, int); | ||
108 | extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command( | ||
109 | unsigned long, struct zfcp_adapter *, struct zfcp_unit *, int); | ||
110 | |||
111 | /******************************* FC/FCP **************************************/ | ||
112 | extern int zfcp_nameserver_enqueue(struct zfcp_adapter *); | ||
113 | extern int zfcp_ns_gid_pn_request(struct zfcp_erp_action *); | ||
114 | extern int zfcp_check_ct_response(struct ct_hdr *); | ||
115 | extern int zfcp_handle_els_rjt(u32, struct zfcp_ls_rjt_par *); | ||
116 | extern void zfcp_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); | ||
117 | |||
118 | /******************************* SCSI ****************************************/ | ||
119 | extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); | ||
120 | extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); | ||
121 | extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); | ||
122 | extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *); | ||
123 | extern void set_host_byte(int *, char); | ||
124 | extern void set_driver_byte(int *, char); | ||
125 | extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); | ||
126 | extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *); | ||
127 | |||
128 | extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *, | ||
129 | struct scsi_cmnd *, int); | ||
130 | extern int zfcp_scsi_command_sync(struct zfcp_unit *, struct scsi_cmnd *, int); | ||
131 | extern struct fc_function_template zfcp_transport_functions; | ||
132 | |||
133 | /******************************** ERP ****************************************/ | ||
134 | extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u8, void *, | ||
135 | u32, int); | ||
136 | extern int zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, u8, void *); | ||
137 | extern int zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, u8, void *); | ||
138 | extern void zfcp_erp_adapter_failed(struct zfcp_adapter *, u8, void *); | ||
139 | |||
140 | extern void zfcp_erp_modify_port_status(struct zfcp_port *, u8, void *, u32, | ||
141 | int); | ||
142 | extern int zfcp_erp_port_reopen(struct zfcp_port *, int, u8, void *); | ||
143 | extern int zfcp_erp_port_shutdown(struct zfcp_port *, int, u8, void *); | ||
144 | extern int zfcp_erp_port_forced_reopen(struct zfcp_port *, int, u8, void *); | ||
145 | extern void zfcp_erp_port_failed(struct zfcp_port *, u8, void *); | ||
146 | extern int zfcp_erp_port_reopen_all(struct zfcp_adapter *, int, u8, void *); | ||
147 | |||
148 | extern void zfcp_erp_modify_unit_status(struct zfcp_unit *, u8, void *, u32, | ||
149 | int); | ||
150 | extern int zfcp_erp_unit_reopen(struct zfcp_unit *, int, u8, void *); | ||
151 | extern int zfcp_erp_unit_shutdown(struct zfcp_unit *, int, u8, void *); | ||
152 | extern void zfcp_erp_unit_failed(struct zfcp_unit *, u8, void *); | ||
153 | |||
154 | extern int zfcp_erp_thread_setup(struct zfcp_adapter *); | ||
155 | extern int zfcp_erp_thread_kill(struct zfcp_adapter *); | ||
156 | extern int zfcp_erp_wait(struct zfcp_adapter *); | ||
157 | extern void zfcp_erp_async_handler(struct zfcp_erp_action *, unsigned long); | ||
158 | |||
159 | extern int zfcp_test_link(struct zfcp_port *); | ||
160 | |||
161 | extern void zfcp_erp_port_boxed(struct zfcp_port *, u8 id, void *ref); | ||
162 | extern void zfcp_erp_unit_boxed(struct zfcp_unit *, u8 id, void *ref); | ||
163 | extern void zfcp_erp_port_access_denied(struct zfcp_port *, u8 id, void *ref); | ||
164 | extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, u8 id, void *ref); | ||
165 | extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, u8, void *); | ||
166 | extern void zfcp_erp_port_access_changed(struct zfcp_port *, u8, void *); | ||
167 | extern void zfcp_erp_unit_access_changed(struct zfcp_unit *, u8, void *); | ||
168 | |||
169 | /******************************** AUX ****************************************/ | ||
170 | extern void zfcp_rec_dbf_event_thread(u8 id, struct zfcp_adapter *adapter, | ||
171 | int lock); | ||
172 | extern void zfcp_rec_dbf_event_adapter(u8 id, void *ref, struct zfcp_adapter *); | ||
173 | extern void zfcp_rec_dbf_event_port(u8 id, void *ref, struct zfcp_port *port); | ||
174 | extern void zfcp_rec_dbf_event_unit(u8 id, void *ref, struct zfcp_unit *unit); | ||
175 | extern void zfcp_rec_dbf_event_trigger(u8 id, void *ref, u8 want, u8 need, | ||
176 | void *action, struct zfcp_adapter *, | ||
177 | struct zfcp_port *, struct zfcp_unit *); | 46 | struct zfcp_port *, struct zfcp_unit *); |
178 | extern void zfcp_rec_dbf_event_action(u8 id, struct zfcp_erp_action *); | 47 | extern void zfcp_rec_dbf_event_action(u8, struct zfcp_erp_action *); |
179 | |||
180 | extern void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *); | 48 | extern void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *); |
181 | extern void zfcp_hba_dbf_event_fsf_unsol(const char *, struct zfcp_adapter *, | 49 | extern void zfcp_hba_dbf_event_fsf_unsol(const char *, struct zfcp_adapter *, |
182 | struct fsf_status_read_buffer *); | 50 | struct fsf_status_read_buffer *); |
183 | extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *, | 51 | extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *, |
184 | unsigned int, unsigned int, unsigned int, | 52 | unsigned int, unsigned int, unsigned int, |
185 | int, int); | 53 | int, int); |
186 | |||
187 | extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *); | 54 | extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *); |
188 | extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *); | 55 | extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *); |
189 | extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *); | 56 | extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *); |
190 | extern void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *); | 57 | extern void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *); |
191 | extern void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *); | 58 | extern void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *); |
192 | |||
193 | extern void zfcp_scsi_dbf_event_result(const char *, int, struct zfcp_adapter *, | 59 | extern void zfcp_scsi_dbf_event_result(const char *, int, struct zfcp_adapter *, |
194 | struct scsi_cmnd *, | 60 | struct scsi_cmnd *, |
195 | struct zfcp_fsf_req *); | 61 | struct zfcp_fsf_req *); |
@@ -198,6 +64,101 @@ extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *, | |||
198 | unsigned long); | 64 | unsigned long); |
199 | extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *, | 65 | extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *, |
200 | struct scsi_cmnd *); | 66 | struct scsi_cmnd *); |
201 | extern int zfcp_reqlist_isempty(struct zfcp_adapter *); | 67 | |
68 | /* zfcp_erp.c */ | ||
69 | extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u8, void *, | ||
70 | u32, int); | ||
71 | extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, u8, void *); | ||
72 | extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, u8, void *); | ||
73 | extern void zfcp_erp_adapter_failed(struct zfcp_adapter *, u8, void *); | ||
74 | extern void zfcp_erp_modify_port_status(struct zfcp_port *, u8, void *, u32, | ||
75 | int); | ||
76 | extern int zfcp_erp_port_reopen(struct zfcp_port *, int, u8, void *); | ||
77 | extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, u8, void *); | ||
78 | extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, u8, void *); | ||
79 | extern void zfcp_erp_port_failed(struct zfcp_port *, u8, void *); | ||
80 | extern void zfcp_erp_modify_unit_status(struct zfcp_unit *, u8, void *, u32, | ||
81 | int); | ||
82 | extern void zfcp_erp_unit_reopen(struct zfcp_unit *, int, u8, void *); | ||
83 | extern void zfcp_erp_unit_shutdown(struct zfcp_unit *, int, u8, void *); | ||
84 | extern void zfcp_erp_unit_failed(struct zfcp_unit *, u8, void *); | ||
85 | extern int zfcp_erp_thread_setup(struct zfcp_adapter *); | ||
86 | extern void zfcp_erp_thread_kill(struct zfcp_adapter *); | ||
87 | extern void zfcp_erp_wait(struct zfcp_adapter *); | ||
88 | extern void zfcp_erp_notify(struct zfcp_erp_action *, unsigned long); | ||
89 | extern void zfcp_erp_port_boxed(struct zfcp_port *, u8, void *); | ||
90 | extern void zfcp_erp_unit_boxed(struct zfcp_unit *, u8, void *); | ||
91 | extern void zfcp_erp_port_access_denied(struct zfcp_port *, u8, void *); | ||
92 | extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, u8, void *); | ||
93 | extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, u8, void *); | ||
94 | extern void zfcp_erp_timeout_handler(unsigned long); | ||
95 | |||
96 | /* zfcp_fc.c */ | ||
97 | extern int zfcp_scan_ports(struct zfcp_adapter *); | ||
98 | extern void _zfcp_scan_ports_later(struct work_struct *); | ||
99 | extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); | ||
100 | extern int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *); | ||
101 | extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); | ||
102 | extern void zfcp_test_link(struct zfcp_port *); | ||
103 | |||
104 | /* zfcp_fsf.c */ | ||
105 | extern int zfcp_fsf_open_port(struct zfcp_erp_action *); | ||
106 | extern int zfcp_fsf_close_port(struct zfcp_erp_action *); | ||
107 | extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *); | ||
108 | extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); | ||
109 | extern int zfcp_fsf_close_unit(struct zfcp_erp_action *); | ||
110 | extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *); | ||
111 | extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *, | ||
112 | struct fsf_qtcb_bottom_config *); | ||
113 | extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *); | ||
114 | extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, | ||
115 | struct fsf_qtcb_bottom_port *); | ||
116 | extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *, | ||
117 | struct zfcp_fsf_cfdc *); | ||
118 | extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); | ||
119 | extern int zfcp_fsf_status_read(struct zfcp_adapter *); | ||
120 | extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); | ||
121 | extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, | ||
122 | struct zfcp_erp_action *); | ||
123 | extern int zfcp_fsf_send_els(struct zfcp_send_els *); | ||
124 | extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, | ||
125 | struct zfcp_unit *, | ||
126 | struct scsi_cmnd *, int, int); | ||
127 | extern void zfcp_fsf_req_complete(struct zfcp_fsf_req *); | ||
128 | extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); | ||
129 | extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *, | ||
130 | struct zfcp_unit *, u8, int); | ||
131 | extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long, | ||
132 | struct zfcp_adapter *, | ||
133 | struct zfcp_unit *, int); | ||
134 | |||
135 | /* zfcp_qdio.c */ | ||
136 | extern int zfcp_qdio_allocate(struct zfcp_adapter *); | ||
137 | extern void zfcp_qdio_free(struct zfcp_adapter *); | ||
138 | extern int zfcp_qdio_send(struct zfcp_fsf_req *); | ||
139 | extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req( | ||
140 | struct zfcp_fsf_req *); | ||
141 | extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr( | ||
142 | struct zfcp_fsf_req *); | ||
143 | extern int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *, unsigned long, | ||
144 | struct scatterlist *, int); | ||
145 | extern int zfcp_qdio_open(struct zfcp_adapter *); | ||
146 | extern void zfcp_qdio_close(struct zfcp_adapter *); | ||
147 | |||
148 | /* zfcp_scsi.c */ | ||
149 | extern struct zfcp_data zfcp_data; | ||
150 | extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); | ||
151 | extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); | ||
152 | extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); | ||
153 | extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); | ||
154 | extern struct fc_function_template zfcp_transport_functions; | ||
155 | |||
156 | /* zfcp_sysfs.c */ | ||
157 | extern struct attribute_group zfcp_sysfs_unit_attrs; | ||
158 | extern struct attribute_group zfcp_sysfs_adapter_attrs; | ||
159 | extern struct attribute_group zfcp_sysfs_ns_port_attrs; | ||
160 | extern struct attribute_group zfcp_sysfs_port_attrs; | ||
161 | extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; | ||
162 | extern struct device_attribute *zfcp_sysfs_shost_attrs[]; | ||
202 | 163 | ||
203 | #endif /* ZFCP_EXT_H */ | 164 | #endif /* ZFCP_EXT_H */ |
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c new file mode 100644 index 000000000000..e984469bb98b --- /dev/null +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -0,0 +1,567 @@ | |||
1 | /* | ||
2 | * zfcp device driver | ||
3 | * | ||
4 | * Fibre Channel related functions for the zfcp device driver. | ||
5 | * | ||
6 | * Copyright IBM Corporation 2008 | ||
7 | */ | ||
8 | |||
9 | #include "zfcp_ext.h" | ||
10 | |||
11 | struct ct_iu_gpn_ft_req { | ||
12 | struct ct_hdr header; | ||
13 | u8 flags; | ||
14 | u8 domain_id_scope; | ||
15 | u8 area_id_scope; | ||
16 | u8 fc4_type; | ||
17 | } __attribute__ ((packed)); | ||
18 | |||
19 | struct gpn_ft_resp_acc { | ||
20 | u8 control; | ||
21 | u8 port_id[3]; | ||
22 | u8 reserved[4]; | ||
23 | u64 wwpn; | ||
24 | } __attribute__ ((packed)); | ||
25 | |||
26 | #define ZFCP_GPN_FT_ENTRIES ((PAGE_SIZE - sizeof(struct ct_hdr)) \ | ||
27 | / sizeof(struct gpn_ft_resp_acc)) | ||
28 | #define ZFCP_GPN_FT_BUFFERS 4 | ||
29 | #define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1) | ||
30 | |||
31 | struct ct_iu_gpn_ft_resp { | ||
32 | struct ct_hdr header; | ||
33 | struct gpn_ft_resp_acc accept[ZFCP_GPN_FT_ENTRIES]; | ||
34 | } __attribute__ ((packed)); | ||
35 | |||
36 | struct zfcp_gpn_ft { | ||
37 | struct zfcp_send_ct ct; | ||
38 | struct scatterlist sg_req; | ||
39 | struct scatterlist sg_resp[ZFCP_GPN_FT_BUFFERS]; | ||
40 | }; | ||
41 | |||
42 | static struct zfcp_port *zfcp_get_port_by_did(struct zfcp_adapter *adapter, | ||
43 | u32 d_id) | ||
44 | { | ||
45 | struct zfcp_port *port; | ||
46 | |||
47 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
48 | if ((port->d_id == d_id) && | ||
49 | !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) | ||
50 | return port; | ||
51 | return NULL; | ||
52 | } | ||
53 | |||
54 | static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, | ||
55 | struct fcp_rscn_element *elem) | ||
56 | { | ||
57 | unsigned long flags; | ||
58 | struct zfcp_port *port; | ||
59 | |||
60 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
61 | list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { | ||
62 | if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) | ||
63 | continue; | ||
64 | /* FIXME: ZFCP_STATUS_PORT_DID_DID check is racy */ | ||
65 | if (!atomic_test_mask(ZFCP_STATUS_PORT_DID_DID, &port->status)) | ||
66 | /* Try to connect to unused ports anyway. */ | ||
67 | zfcp_erp_port_reopen(port, | ||
68 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
69 | 82, fsf_req); | ||
70 | else if ((port->d_id & range) == (elem->nport_did & range)) | ||
71 | /* Check connection status for connected ports */ | ||
72 | zfcp_test_link(port); | ||
73 | } | ||
74 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
75 | } | ||
76 | |||
77 | static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) | ||
78 | { | ||
79 | struct fsf_status_read_buffer *status_buffer = (void *)fsf_req->data; | ||
80 | struct fcp_rscn_head *fcp_rscn_head; | ||
81 | struct fcp_rscn_element *fcp_rscn_element; | ||
82 | u16 i; | ||
83 | u16 no_entries; | ||
84 | u32 range_mask; | ||
85 | |||
86 | fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload.data; | ||
87 | fcp_rscn_element = (struct fcp_rscn_element *) fcp_rscn_head; | ||
88 | |||
89 | /* see FC-FS */ | ||
90 | no_entries = fcp_rscn_head->payload_len / | ||
91 | sizeof(struct fcp_rscn_element); | ||
92 | |||
93 | for (i = 1; i < no_entries; i++) { | ||
94 | /* skip head and start with 1st element */ | ||
95 | fcp_rscn_element++; | ||
96 | switch (fcp_rscn_element->addr_format) { | ||
97 | case ZFCP_PORT_ADDRESS: | ||
98 | range_mask = ZFCP_PORTS_RANGE_PORT; | ||
99 | break; | ||
100 | case ZFCP_AREA_ADDRESS: | ||
101 | range_mask = ZFCP_PORTS_RANGE_AREA; | ||
102 | break; | ||
103 | case ZFCP_DOMAIN_ADDRESS: | ||
104 | range_mask = ZFCP_PORTS_RANGE_DOMAIN; | ||
105 | break; | ||
106 | case ZFCP_FABRIC_ADDRESS: | ||
107 | range_mask = ZFCP_PORTS_RANGE_FABRIC; | ||
108 | break; | ||
109 | default: | ||
110 | continue; | ||
111 | } | ||
112 | _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); | ||
113 | } | ||
114 | schedule_work(&fsf_req->adapter->scan_work); | ||
115 | } | ||
116 | |||
117 | static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, wwn_t wwpn) | ||
118 | { | ||
119 | struct zfcp_adapter *adapter = req->adapter; | ||
120 | struct zfcp_port *port; | ||
121 | unsigned long flags; | ||
122 | |||
123 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
124 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
125 | if (port->wwpn == wwpn) | ||
126 | break; | ||
127 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
128 | |||
129 | if (port && (port->wwpn == wwpn)) | ||
130 | zfcp_erp_port_forced_reopen(port, 0, 83, req); | ||
131 | } | ||
132 | |||
133 | static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req) | ||
134 | { | ||
135 | struct fsf_status_read_buffer *status_buffer = | ||
136 | (struct fsf_status_read_buffer *)req->data; | ||
137 | struct fsf_plogi *els_plogi = | ||
138 | (struct fsf_plogi *) status_buffer->payload.data; | ||
139 | |||
140 | zfcp_fc_incoming_wwpn(req, els_plogi->serv_param.wwpn); | ||
141 | } | ||
142 | |||
143 | static void zfcp_fc_incoming_logo(struct zfcp_fsf_req *req) | ||
144 | { | ||
145 | struct fsf_status_read_buffer *status_buffer = | ||
146 | (struct fsf_status_read_buffer *)req->data; | ||
147 | struct fcp_logo *els_logo = | ||
148 | (struct fcp_logo *) status_buffer->payload.data; | ||
149 | |||
150 | zfcp_fc_incoming_wwpn(req, els_logo->nport_wwpn); | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * zfcp_fc_incoming_els - handle incoming ELS | ||
155 | * @fsf_req - request which contains incoming ELS | ||
156 | */ | ||
157 | void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req) | ||
158 | { | ||
159 | struct fsf_status_read_buffer *status_buffer = | ||
160 | (struct fsf_status_read_buffer *) fsf_req->data; | ||
161 | unsigned int els_type = status_buffer->payload.data[0]; | ||
162 | |||
163 | zfcp_san_dbf_event_incoming_els(fsf_req); | ||
164 | if (els_type == LS_PLOGI) | ||
165 | zfcp_fc_incoming_plogi(fsf_req); | ||
166 | else if (els_type == LS_LOGO) | ||
167 | zfcp_fc_incoming_logo(fsf_req); | ||
168 | else if (els_type == LS_RSCN) | ||
169 | zfcp_fc_incoming_rscn(fsf_req); | ||
170 | } | ||
171 | |||
172 | static void zfcp_ns_gid_pn_handler(unsigned long data) | ||
173 | { | ||
174 | struct zfcp_gid_pn_data *gid_pn = (struct zfcp_gid_pn_data *) data; | ||
175 | struct zfcp_send_ct *ct = &gid_pn->ct; | ||
176 | struct ct_iu_gid_pn_req *ct_iu_req = sg_virt(ct->req); | ||
177 | struct ct_iu_gid_pn_resp *ct_iu_resp = sg_virt(ct->resp); | ||
178 | struct zfcp_port *port = gid_pn->port; | ||
179 | |||
180 | if (ct->status) | ||
181 | goto out; | ||
182 | if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) { | ||
183 | atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); | ||
184 | goto out; | ||
185 | } | ||
186 | /* paranoia */ | ||
187 | if (ct_iu_req->wwpn != port->wwpn) | ||
188 | goto out; | ||
189 | /* looks like a valid d_id */ | ||
190 | port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; | ||
191 | atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); | ||
192 | out: | ||
193 | mempool_free(gid_pn, port->adapter->pool.data_gid_pn); | ||
194 | } | ||
195 | |||
196 | /** | ||
197 | * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request | ||
198 | * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed | ||
199 | * return: -ENOMEM on error, 0 otherwise | ||
200 | */ | ||
201 | int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action) | ||
202 | { | ||
203 | int ret; | ||
204 | struct zfcp_gid_pn_data *gid_pn; | ||
205 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
206 | |||
207 | gid_pn = mempool_alloc(adapter->pool.data_gid_pn, GFP_ATOMIC); | ||
208 | if (!gid_pn) | ||
209 | return -ENOMEM; | ||
210 | |||
211 | memset(gid_pn, 0, sizeof(*gid_pn)); | ||
212 | |||
213 | /* setup parameters for send generic command */ | ||
214 | gid_pn->port = erp_action->port; | ||
215 | gid_pn->ct.port = adapter->nameserver_port; | ||
216 | gid_pn->ct.handler = zfcp_ns_gid_pn_handler; | ||
217 | gid_pn->ct.handler_data = (unsigned long) gid_pn; | ||
218 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; | ||
219 | gid_pn->ct.req = &gid_pn->req; | ||
220 | gid_pn->ct.resp = &gid_pn->resp; | ||
221 | gid_pn->ct.req_count = 1; | ||
222 | gid_pn->ct.resp_count = 1; | ||
223 | sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, | ||
224 | sizeof(struct ct_iu_gid_pn_req)); | ||
225 | sg_init_one(&gid_pn->resp, &gid_pn->ct_iu_resp, | ||
226 | sizeof(struct ct_iu_gid_pn_resp)); | ||
227 | |||
228 | /* setup nameserver request */ | ||
229 | gid_pn->ct_iu_req.header.revision = ZFCP_CT_REVISION; | ||
230 | gid_pn->ct_iu_req.header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; | ||
231 | gid_pn->ct_iu_req.header.gs_subtype = ZFCP_CT_NAME_SERVER; | ||
232 | gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; | ||
233 | gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN; | ||
234 | gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_MAX_SIZE; | ||
235 | gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; | ||
236 | |||
237 | ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp, | ||
238 | erp_action); | ||
239 | if (ret) | ||
240 | mempool_free(gid_pn, adapter->pool.data_gid_pn); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * zfcp_fc_plogi_evaluate - evaluate PLOGI playload | ||
246 | * @port: zfcp_port structure | ||
247 | * @plogi: plogi payload | ||
248 | * | ||
249 | * Evaluate PLOGI playload and copy important fields into zfcp_port structure | ||
250 | */ | ||
251 | void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi) | ||
252 | { | ||
253 | port->maxframe_size = plogi->serv_param.common_serv_param[7] | | ||
254 | ((plogi->serv_param.common_serv_param[6] & 0x0F) << 8); | ||
255 | if (plogi->serv_param.class1_serv_param[0] & 0x80) | ||
256 | port->supported_classes |= FC_COS_CLASS1; | ||
257 | if (plogi->serv_param.class2_serv_param[0] & 0x80) | ||
258 | port->supported_classes |= FC_COS_CLASS2; | ||
259 | if (plogi->serv_param.class3_serv_param[0] & 0x80) | ||
260 | port->supported_classes |= FC_COS_CLASS3; | ||
261 | if (plogi->serv_param.class4_serv_param[0] & 0x80) | ||
262 | port->supported_classes |= FC_COS_CLASS4; | ||
263 | } | ||
264 | |||
265 | struct zfcp_els_adisc { | ||
266 | struct zfcp_send_els els; | ||
267 | struct scatterlist req; | ||
268 | struct scatterlist resp; | ||
269 | struct zfcp_ls_adisc ls_adisc; | ||
270 | struct zfcp_ls_adisc_acc ls_adisc_acc; | ||
271 | }; | ||
272 | |||
273 | static void zfcp_fc_adisc_handler(unsigned long data) | ||
274 | { | ||
275 | struct zfcp_els_adisc *adisc = (struct zfcp_els_adisc *) data; | ||
276 | struct zfcp_port *port = adisc->els.port; | ||
277 | struct zfcp_ls_adisc_acc *ls_adisc = &adisc->ls_adisc_acc; | ||
278 | |||
279 | if (adisc->els.status) { | ||
280 | /* request rejected or timed out */ | ||
281 | zfcp_erp_port_forced_reopen(port, 0, 63, NULL); | ||
282 | goto out; | ||
283 | } | ||
284 | |||
285 | if (!port->wwnn) | ||
286 | port->wwnn = ls_adisc->wwnn; | ||
287 | |||
288 | if (port->wwpn != ls_adisc->wwpn) | ||
289 | zfcp_erp_port_reopen(port, 0, 64, NULL); | ||
290 | |||
291 | out: | ||
292 | zfcp_port_put(port); | ||
293 | kfree(adisc); | ||
294 | } | ||
295 | |||
296 | static int zfcp_fc_adisc(struct zfcp_port *port) | ||
297 | { | ||
298 | struct zfcp_els_adisc *adisc; | ||
299 | struct zfcp_adapter *adapter = port->adapter; | ||
300 | |||
301 | adisc = kzalloc(sizeof(struct zfcp_els_adisc), GFP_ATOMIC); | ||
302 | if (!adisc) | ||
303 | return -ENOMEM; | ||
304 | |||
305 | adisc->els.req = &adisc->req; | ||
306 | adisc->els.resp = &adisc->resp; | ||
307 | sg_init_one(adisc->els.req, &adisc->ls_adisc, | ||
308 | sizeof(struct zfcp_ls_adisc)); | ||
309 | sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, | ||
310 | sizeof(struct zfcp_ls_adisc_acc)); | ||
311 | |||
312 | adisc->els.req_count = 1; | ||
313 | adisc->els.resp_count = 1; | ||
314 | adisc->els.adapter = adapter; | ||
315 | adisc->els.port = port; | ||
316 | adisc->els.d_id = port->d_id; | ||
317 | adisc->els.handler = zfcp_fc_adisc_handler; | ||
318 | adisc->els.handler_data = (unsigned long) adisc; | ||
319 | adisc->els.ls_code = adisc->ls_adisc.code = ZFCP_LS_ADISC; | ||
320 | |||
321 | /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports | ||
322 | without FC-AL-2 capability, so we don't set it */ | ||
323 | adisc->ls_adisc.wwpn = fc_host_port_name(adapter->scsi_host); | ||
324 | adisc->ls_adisc.wwnn = fc_host_node_name(adapter->scsi_host); | ||
325 | adisc->ls_adisc.nport_id = fc_host_port_id(adapter->scsi_host); | ||
326 | |||
327 | return zfcp_fsf_send_els(&adisc->els); | ||
328 | } | ||
329 | |||
330 | /** | ||
331 | * zfcp_test_link - lightweight link test procedure | ||
332 | * @port: port to be tested | ||
333 | * | ||
334 | * Test status of a link to a remote port using the ELS command ADISC. | ||
335 | * If there is a problem with the remote port, error recovery steps | ||
336 | * will be triggered. | ||
337 | */ | ||
338 | void zfcp_test_link(struct zfcp_port *port) | ||
339 | { | ||
340 | int retval; | ||
341 | |||
342 | zfcp_port_get(port); | ||
343 | retval = zfcp_fc_adisc(port); | ||
344 | if (retval == 0 || retval == -EBUSY) | ||
345 | return; | ||
346 | |||
347 | /* send of ADISC was not possible */ | ||
348 | zfcp_port_put(port); | ||
349 | zfcp_erp_port_forced_reopen(port, 0, 65, NULL); | ||
350 | } | ||
351 | |||
352 | static int zfcp_scan_get_nameserver(struct zfcp_adapter *adapter) | ||
353 | { | ||
354 | int ret; | ||
355 | |||
356 | if (!adapter->nameserver_port) | ||
357 | return -EINTR; | ||
358 | |||
359 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
360 | &adapter->nameserver_port->status)) { | ||
361 | ret = zfcp_erp_port_reopen(adapter->nameserver_port, 0, 148, | ||
362 | NULL); | ||
363 | if (ret) | ||
364 | return ret; | ||
365 | zfcp_erp_wait(adapter); | ||
366 | zfcp_port_put(adapter->nameserver_port); | ||
367 | } | ||
368 | return !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
369 | &adapter->nameserver_port->status); | ||
370 | } | ||
371 | |||
372 | static void zfcp_gpn_ft_handler(unsigned long _done) | ||
373 | { | ||
374 | complete((struct completion *)_done); | ||
375 | } | ||
376 | |||
377 | static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft) | ||
378 | { | ||
379 | struct scatterlist *sg = &gpn_ft->sg_req; | ||
380 | |||
381 | kfree(sg_virt(sg)); /* free request buffer */ | ||
382 | zfcp_sg_free_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS); | ||
383 | |||
384 | kfree(gpn_ft); | ||
385 | } | ||
386 | |||
387 | static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) | ||
388 | { | ||
389 | struct zfcp_gpn_ft *gpn_ft; | ||
390 | struct ct_iu_gpn_ft_req *req; | ||
391 | |||
392 | gpn_ft = kzalloc(sizeof(*gpn_ft), GFP_KERNEL); | ||
393 | if (!gpn_ft) | ||
394 | return NULL; | ||
395 | |||
396 | req = kzalloc(sizeof(struct ct_iu_gpn_ft_req), GFP_KERNEL); | ||
397 | if (!req) { | ||
398 | kfree(gpn_ft); | ||
399 | gpn_ft = NULL; | ||
400 | goto out; | ||
401 | } | ||
402 | sg_init_one(&gpn_ft->sg_req, req, sizeof(*req)); | ||
403 | |||
404 | if (zfcp_sg_setup_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS)) { | ||
405 | zfcp_free_sg_env(gpn_ft); | ||
406 | gpn_ft = NULL; | ||
407 | } | ||
408 | out: | ||
409 | return gpn_ft; | ||
410 | } | ||
411 | |||
412 | |||
413 | static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, | ||
414 | struct zfcp_adapter *adapter) | ||
415 | { | ||
416 | struct zfcp_send_ct *ct = &gpn_ft->ct; | ||
417 | struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); | ||
418 | struct completion done; | ||
419 | int ret; | ||
420 | |||
421 | /* prepare CT IU for GPN_FT */ | ||
422 | req->header.revision = ZFCP_CT_REVISION; | ||
423 | req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; | ||
424 | req->header.gs_subtype = ZFCP_CT_NAME_SERVER; | ||
425 | req->header.options = ZFCP_CT_SYNCHRONOUS; | ||
426 | req->header.cmd_rsp_code = ZFCP_CT_GPN_FT; | ||
427 | req->header.max_res_size = (sizeof(struct gpn_ft_resp_acc) * | ||
428 | (ZFCP_GPN_FT_MAX_ENTRIES - 1)) >> 2; | ||
429 | req->flags = 0; | ||
430 | req->domain_id_scope = 0; | ||
431 | req->area_id_scope = 0; | ||
432 | req->fc4_type = ZFCP_CT_SCSI_FCP; | ||
433 | |||
434 | /* prepare zfcp_send_ct */ | ||
435 | ct->port = adapter->nameserver_port; | ||
436 | ct->handler = zfcp_gpn_ft_handler; | ||
437 | ct->handler_data = (unsigned long)&done; | ||
438 | ct->timeout = 10; | ||
439 | ct->req = &gpn_ft->sg_req; | ||
440 | ct->resp = gpn_ft->sg_resp; | ||
441 | ct->req_count = 1; | ||
442 | ct->resp_count = ZFCP_GPN_FT_BUFFERS; | ||
443 | |||
444 | init_completion(&done); | ||
445 | ret = zfcp_fsf_send_ct(ct, NULL, NULL); | ||
446 | if (!ret) | ||
447 | wait_for_completion(&done); | ||
448 | return ret; | ||
449 | } | ||
450 | |||
451 | static void zfcp_validate_port(struct zfcp_port *port) | ||
452 | { | ||
453 | struct zfcp_adapter *adapter = port->adapter; | ||
454 | |||
455 | atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); | ||
456 | |||
457 | if (port == adapter->nameserver_port) | ||
458 | return; | ||
459 | if ((port->supported_classes != 0) || (port->units != 0)) { | ||
460 | zfcp_port_put(port); | ||
461 | return; | ||
462 | } | ||
463 | zfcp_erp_port_shutdown(port, 0, 151, NULL); | ||
464 | zfcp_erp_wait(adapter); | ||
465 | zfcp_port_put(port); | ||
466 | zfcp_port_dequeue(port); | ||
467 | } | ||
468 | |||
469 | static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) | ||
470 | { | ||
471 | struct zfcp_send_ct *ct = &gpn_ft->ct; | ||
472 | struct scatterlist *sg = gpn_ft->sg_resp; | ||
473 | struct ct_hdr *hdr = sg_virt(sg); | ||
474 | struct gpn_ft_resp_acc *acc = sg_virt(sg); | ||
475 | struct zfcp_adapter *adapter = ct->port->adapter; | ||
476 | struct zfcp_port *port, *tmp; | ||
477 | u32 d_id; | ||
478 | int ret = 0, x; | ||
479 | |||
480 | if (ct->status) | ||
481 | return -EIO; | ||
482 | |||
483 | if (hdr->cmd_rsp_code != ZFCP_CT_ACCEPT) { | ||
484 | if (hdr->reason_code == ZFCP_CT_UNABLE_TO_PERFORM_CMD) | ||
485 | return -EAGAIN; /* might be a temporary condition */ | ||
486 | return -EIO; | ||
487 | } | ||
488 | |||
489 | if (hdr->max_res_size) | ||
490 | return -E2BIG; | ||
491 | |||
492 | down(&zfcp_data.config_sema); | ||
493 | |||
494 | /* first entry is the header */ | ||
495 | for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES; x++) { | ||
496 | if (x % (ZFCP_GPN_FT_ENTRIES + 1)) | ||
497 | acc++; | ||
498 | else | ||
499 | acc = sg_virt(++sg); | ||
500 | |||
501 | d_id = acc->port_id[0] << 16 | acc->port_id[1] << 8 | | ||
502 | acc->port_id[2]; | ||
503 | |||
504 | /* skip the adapter's port and known remote ports */ | ||
505 | if (acc->wwpn == fc_host_port_name(adapter->scsi_host) || | ||
506 | zfcp_get_port_by_did(adapter, d_id)) | ||
507 | continue; | ||
508 | |||
509 | port = zfcp_port_enqueue(adapter, acc->wwpn, | ||
510 | ZFCP_STATUS_PORT_DID_DID | | ||
511 | ZFCP_STATUS_COMMON_NOESC, d_id); | ||
512 | if (IS_ERR(port)) | ||
513 | ret = PTR_ERR(port); | ||
514 | else | ||
515 | zfcp_erp_port_reopen(port, 0, 149, NULL); | ||
516 | if (acc->control & 0x80) /* last entry */ | ||
517 | break; | ||
518 | } | ||
519 | |||
520 | zfcp_erp_wait(adapter); | ||
521 | list_for_each_entry_safe(port, tmp, &adapter->port_list_head, list) | ||
522 | zfcp_validate_port(port); | ||
523 | up(&zfcp_data.config_sema); | ||
524 | return ret; | ||
525 | } | ||
526 | |||
527 | /** | ||
528 | * zfcp_scan_ports - scan remote ports and attach new ports | ||
529 | * @adapter: pointer to struct zfcp_adapter | ||
530 | */ | ||
531 | int zfcp_scan_ports(struct zfcp_adapter *adapter) | ||
532 | { | ||
533 | int ret, i; | ||
534 | struct zfcp_gpn_ft *gpn_ft; | ||
535 | |||
536 | zfcp_erp_wait(adapter); /* wait until adapter is finished with ERP */ | ||
537 | if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) | ||
538 | return 0; | ||
539 | |||
540 | ret = zfcp_scan_get_nameserver(adapter); | ||
541 | if (ret) | ||
542 | return ret; | ||
543 | |||
544 | gpn_ft = zfcp_alloc_sg_env(); | ||
545 | if (!gpn_ft) | ||
546 | return -ENOMEM; | ||
547 | |||
548 | for (i = 0; i < 3; i++) { | ||
549 | ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter); | ||
550 | if (!ret) { | ||
551 | ret = zfcp_scan_eval_gpn_ft(gpn_ft); | ||
552 | if (ret == -EAGAIN) | ||
553 | ssleep(1); | ||
554 | else | ||
555 | break; | ||
556 | } | ||
557 | } | ||
558 | zfcp_free_sg_env(gpn_ft); | ||
559 | |||
560 | return ret; | ||
561 | } | ||
562 | |||
563 | |||
564 | void _zfcp_scan_ports_later(struct work_struct *work) | ||
565 | { | ||
566 | zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); | ||
567 | } | ||
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index b2ea4ea051f5..19c1ca913874 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -1,54 +1,37 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Implementation of FSF commands. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #include "zfcp_ext.h" | 9 | #include "zfcp_ext.h" |
23 | 10 | ||
24 | static int zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *); | 11 | static void zfcp_fsf_request_timeout_handler(unsigned long data) |
25 | static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *); | 12 | { |
26 | static int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *); | 13 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; |
27 | static int zfcp_fsf_close_port_handler(struct zfcp_fsf_req *); | 14 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 62, |
28 | static int zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *); | 15 | NULL); |
29 | static int zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *); | 16 | } |
30 | static int zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *); | 17 | |
31 | static int zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *); | 18 | static void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, |
32 | static int zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *); | 19 | unsigned long timeout) |
33 | static int zfcp_fsf_send_fcp_command_task_management_handler( | 20 | { |
34 | struct zfcp_fsf_req *); | 21 | fsf_req->timer.function = zfcp_fsf_request_timeout_handler; |
35 | static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *); | 22 | fsf_req->timer.data = (unsigned long) fsf_req->adapter; |
36 | static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *); | 23 | fsf_req->timer.expires = jiffies + timeout; |
37 | static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *); | 24 | add_timer(&fsf_req->timer); |
38 | static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *); | 25 | } |
39 | static int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *); | 26 | |
40 | static inline int zfcp_fsf_req_sbal_check( | 27 | static void zfcp_fsf_start_erp_timer(struct zfcp_fsf_req *fsf_req) |
41 | unsigned long *, struct zfcp_qdio_queue *, int); | 28 | { |
42 | static inline int zfcp_use_one_sbal( | 29 | BUG_ON(!fsf_req->erp_action); |
43 | struct scatterlist *, int, struct scatterlist *, int); | 30 | fsf_req->timer.function = zfcp_erp_timeout_handler; |
44 | static struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *, int); | 31 | fsf_req->timer.data = (unsigned long) fsf_req->erp_action; |
45 | static int zfcp_fsf_req_send(struct zfcp_fsf_req *); | 32 | fsf_req->timer.expires = jiffies + 30 * HZ; |
46 | static int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *); | 33 | add_timer(&fsf_req->timer); |
47 | static int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *); | 34 | } |
48 | static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *); | ||
49 | static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *, u8, | ||
50 | struct fsf_link_down_info *); | ||
51 | static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *); | ||
52 | 35 | ||
53 | /* association between FSF command and FSF QTCB type */ | 36 | /* association between FSF command and FSF QTCB type */ |
54 | static u32 fsf_qtcb_type[] = { | 37 | static u32 fsf_qtcb_type[] = { |
@@ -67,96 +50,77 @@ static u32 fsf_qtcb_type[] = { | |||
67 | [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND | 50 | [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND |
68 | }; | 51 | }; |
69 | 52 | ||
70 | static const char zfcp_act_subtable_type[5][8] = { | 53 | static const char *zfcp_act_subtable_type[] = { |
71 | "unknown", "OS", "WWPN", "DID", "LUN" | 54 | "unknown", "OS", "WWPN", "DID", "LUN" |
72 | }; | 55 | }; |
73 | 56 | ||
74 | /****************************************************************/ | 57 | static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table) |
75 | /*************** FSF related Functions *************************/ | ||
76 | /****************************************************************/ | ||
77 | |||
78 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF | ||
79 | |||
80 | /* | ||
81 | * function: zfcp_fsf_req_alloc | ||
82 | * | ||
83 | * purpose: Obtains an fsf_req and potentially a qtcb (for all but | ||
84 | * unsolicited requests) via helper functions | ||
85 | * Does some initial fsf request set-up. | ||
86 | * | ||
87 | * returns: pointer to allocated fsf_req if successfull | ||
88 | * NULL otherwise | ||
89 | * | ||
90 | * locks: none | ||
91 | * | ||
92 | */ | ||
93 | static struct zfcp_fsf_req * | ||
94 | zfcp_fsf_req_alloc(mempool_t *pool, int req_flags) | ||
95 | { | 58 | { |
96 | size_t size; | 59 | u16 subtable = table >> 16; |
97 | void *ptr; | 60 | u16 rule = table & 0xffff; |
98 | struct zfcp_fsf_req *fsf_req = NULL; | ||
99 | 61 | ||
100 | if (req_flags & ZFCP_REQ_NO_QTCB) | 62 | if (subtable && subtable < ARRAY_SIZE(zfcp_act_subtable_type)) |
101 | size = sizeof(struct zfcp_fsf_req); | 63 | dev_warn(&adapter->ccw_device->dev, |
102 | else | 64 | "Access denied in subtable %s, rule %d.\n", |
103 | size = sizeof(struct zfcp_fsf_req_qtcb); | 65 | zfcp_act_subtable_type[subtable], rule); |
104 | 66 | } | |
105 | if (likely(pool)) | ||
106 | ptr = mempool_alloc(pool, GFP_ATOMIC); | ||
107 | else { | ||
108 | if (req_flags & ZFCP_REQ_NO_QTCB) | ||
109 | ptr = kmalloc(size, GFP_ATOMIC); | ||
110 | else | ||
111 | ptr = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache, | ||
112 | GFP_ATOMIC); | ||
113 | } | ||
114 | |||
115 | if (unlikely(!ptr)) | ||
116 | goto out; | ||
117 | |||
118 | memset(ptr, 0, size); | ||
119 | 67 | ||
120 | if (req_flags & ZFCP_REQ_NO_QTCB) { | 68 | static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req, |
121 | fsf_req = (struct zfcp_fsf_req *) ptr; | 69 | struct zfcp_port *port) |
122 | } else { | 70 | { |
123 | fsf_req = &((struct zfcp_fsf_req_qtcb *) ptr)->fsf_req; | 71 | struct fsf_qtcb_header *header = &req->qtcb->header; |
124 | fsf_req->qtcb = &((struct zfcp_fsf_req_qtcb *) ptr)->qtcb; | 72 | dev_warn(&req->adapter->ccw_device->dev, |
125 | } | 73 | "Access denied, cannot send command to port 0x%016Lx.\n", |
74 | port->wwpn); | ||
75 | zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); | ||
76 | zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); | ||
77 | zfcp_erp_port_access_denied(port, 55, req); | ||
78 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
79 | } | ||
126 | 80 | ||
127 | fsf_req->pool = pool; | 81 | static void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req, |
82 | struct zfcp_unit *unit) | ||
83 | { | ||
84 | struct fsf_qtcb_header *header = &req->qtcb->header; | ||
85 | dev_warn(&req->adapter->ccw_device->dev, | ||
86 | "Access denied for unit 0x%016Lx on port 0x%016Lx.\n", | ||
87 | unit->fcp_lun, unit->port->wwpn); | ||
88 | zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); | ||
89 | zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); | ||
90 | zfcp_erp_unit_access_denied(unit, 59, req); | ||
91 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
92 | } | ||
128 | 93 | ||
129 | out: | 94 | static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req) |
130 | return fsf_req; | 95 | { |
96 | dev_err(&req->adapter->ccw_device->dev, | ||
97 | "Required FC class not supported by adapter, " | ||
98 | "shutting down adapter.\n"); | ||
99 | zfcp_erp_adapter_shutdown(req->adapter, 0, 123, req); | ||
100 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
131 | } | 101 | } |
132 | 102 | ||
133 | /* | 103 | /** |
134 | * function: zfcp_fsf_req_free | 104 | * zfcp_fsf_req_free - free memory used by fsf request |
135 | * | 105 | * @fsf_req: pointer to struct zfcp_fsf_req |
136 | * purpose: Frees the memory of an fsf_req (and potentially a qtcb) or | ||
137 | * returns it into the pool via helper functions. | ||
138 | * | ||
139 | * returns: sod all | ||
140 | * | ||
141 | * locks: none | ||
142 | */ | 106 | */ |
143 | void | 107 | void zfcp_fsf_req_free(struct zfcp_fsf_req *req) |
144 | zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req) | ||
145 | { | 108 | { |
146 | if (likely(fsf_req->pool)) { | 109 | if (likely(req->pool)) { |
147 | mempool_free(fsf_req, fsf_req->pool); | 110 | mempool_free(req, req->pool); |
148 | return; | 111 | return; |
149 | } | 112 | } |
150 | 113 | ||
151 | if (fsf_req->qtcb) { | 114 | if (req->qtcb) { |
152 | kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, fsf_req); | 115 | kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, req); |
153 | return; | 116 | return; |
154 | } | 117 | } |
155 | |||
156 | kfree(fsf_req); | ||
157 | } | 118 | } |
158 | 119 | ||
159 | /* | 120 | /** |
121 | * zfcp_fsf_req_dismiss_all - dismiss all fsf requests | ||
122 | * @adapter: pointer to struct zfcp_adapter | ||
123 | * | ||
160 | * Never ever call this without shutting down the adapter first. | 124 | * Never ever call this without shutting down the adapter first. |
161 | * Otherwise the adapter would continue using and corrupting s390 storage. | 125 | * Otherwise the adapter would continue using and corrupting s390 storage. |
162 | * Included BUG_ON() call to ensure this is done. | 126 | * Included BUG_ON() call to ensure this is done. |
@@ -164,2353 +128,1359 @@ zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req) | |||
164 | */ | 128 | */ |
165 | void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) | 129 | void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) |
166 | { | 130 | { |
167 | struct zfcp_fsf_req *fsf_req, *tmp; | 131 | struct zfcp_fsf_req *req, *tmp; |
168 | unsigned long flags; | 132 | unsigned long flags; |
169 | LIST_HEAD(remove_queue); | 133 | LIST_HEAD(remove_queue); |
170 | unsigned int i; | 134 | unsigned int i; |
171 | 135 | ||
172 | BUG_ON(atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)); | 136 | BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP); |
173 | spin_lock_irqsave(&adapter->req_list_lock, flags); | 137 | spin_lock_irqsave(&adapter->req_list_lock, flags); |
174 | atomic_set(&adapter->reqs_active, 0); | ||
175 | for (i = 0; i < REQUEST_LIST_SIZE; i++) | 138 | for (i = 0; i < REQUEST_LIST_SIZE; i++) |
176 | list_splice_init(&adapter->req_list[i], &remove_queue); | 139 | list_splice_init(&adapter->req_list[i], &remove_queue); |
177 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); | 140 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); |
178 | 141 | ||
179 | list_for_each_entry_safe(fsf_req, tmp, &remove_queue, list) { | 142 | list_for_each_entry_safe(req, tmp, &remove_queue, list) { |
180 | list_del(&fsf_req->list); | 143 | list_del(&req->list); |
181 | fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; | 144 | req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; |
182 | zfcp_fsf_req_complete(fsf_req); | 145 | zfcp_fsf_req_complete(req); |
183 | } | 146 | } |
184 | } | 147 | } |
185 | 148 | ||
186 | /* | 149 | static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req) |
187 | * function: zfcp_fsf_req_complete | ||
188 | * | ||
189 | * purpose: Updates active counts and timers for openfcp-reqs | ||
190 | * May cleanup request after req_eval returns | ||
191 | * | ||
192 | * returns: 0 - success | ||
193 | * !0 - failure | ||
194 | * | ||
195 | * context: | ||
196 | */ | ||
197 | int | ||
198 | zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) | ||
199 | { | 150 | { |
200 | int retval = 0; | 151 | struct fsf_status_read_buffer *sr_buf = req->data; |
201 | int cleanup; | 152 | struct zfcp_adapter *adapter = req->adapter; |
202 | 153 | struct zfcp_port *port; | |
203 | if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { | 154 | int d_id = sr_buf->d_id & ZFCP_DID_MASK; |
204 | ZFCP_LOG_DEBUG("Status read response received\n"); | 155 | unsigned long flags; |
205 | /* | ||
206 | * Note: all cleanup handling is done in the callchain of | ||
207 | * the function call-chain below. | ||
208 | */ | ||
209 | zfcp_fsf_status_read_handler(fsf_req); | ||
210 | goto out; | ||
211 | } else { | ||
212 | del_timer(&fsf_req->timer); | ||
213 | zfcp_fsf_protstatus_eval(fsf_req); | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * fsf_req may be deleted due to waking up functions, so | ||
218 | * cleanup is saved here and used later | ||
219 | */ | ||
220 | if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP)) | ||
221 | cleanup = 1; | ||
222 | else | ||
223 | cleanup = 0; | ||
224 | |||
225 | fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED; | ||
226 | 156 | ||
227 | /* cleanup request if requested by initiator */ | 157 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
228 | if (likely(cleanup)) { | 158 | list_for_each_entry(port, &adapter->port_list_head, list) |
229 | ZFCP_LOG_TRACE("removing FSF request %p\n", fsf_req); | 159 | if (port->d_id == d_id) { |
230 | /* | 160 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
231 | * lock must not be held here since it will be | 161 | switch (sr_buf->status_subtype) { |
232 | * grabed by the called routine, too | 162 | case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT: |
233 | */ | 163 | zfcp_erp_port_reopen(port, 0, 101, req); |
234 | zfcp_fsf_req_free(fsf_req); | 164 | break; |
235 | } else { | 165 | case FSF_STATUS_READ_SUB_ERROR_PORT: |
236 | /* notify initiator waiting for the requests completion */ | 166 | zfcp_erp_port_shutdown(port, 0, 122, req); |
237 | ZFCP_LOG_TRACE("waking initiator of FSF request %p\n",fsf_req); | 167 | break; |
238 | /* | 168 | } |
239 | * FIXME: Race! We must not access fsf_req here as it might have been | 169 | return; |
240 | * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED | 170 | } |
241 | * flag. It's an improbable case. But, we have the same paranoia for | 171 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
242 | * the cleanup flag already. | 172 | } |
243 | * Might better be handled using complete()? | ||
244 | * (setting the flag and doing wakeup ought to be atomic | ||
245 | * with regard to checking the flag as long as waitqueue is | ||
246 | * part of the to be released structure) | ||
247 | */ | ||
248 | wake_up(&fsf_req->completion_wq); | ||
249 | } | ||
250 | 173 | ||
251 | out: | 174 | static void zfcp_fsf_bit_error_threshold(struct zfcp_fsf_req *req) |
252 | return retval; | 175 | { |
176 | struct zfcp_adapter *adapter = req->adapter; | ||
177 | struct fsf_status_read_buffer *sr_buf = req->data; | ||
178 | struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error; | ||
179 | |||
180 | dev_warn(&adapter->ccw_device->dev, | ||
181 | "Warning: bit error threshold data " | ||
182 | "received for the adapter: " | ||
183 | "link failures = %i, loss of sync errors = %i, " | ||
184 | "loss of signal errors = %i, " | ||
185 | "primitive sequence errors = %i, " | ||
186 | "invalid transmission word errors = %i, " | ||
187 | "CRC errors = %i).\n", | ||
188 | err->link_failure_error_count, | ||
189 | err->loss_of_sync_error_count, | ||
190 | err->loss_of_signal_error_count, | ||
191 | err->primitive_sequence_error_count, | ||
192 | err->invalid_transmission_word_error_count, | ||
193 | err->crc_error_count); | ||
194 | dev_warn(&adapter->ccw_device->dev, | ||
195 | "Additional bit error threshold data of the adapter: " | ||
196 | "primitive sequence event time-outs = %i, " | ||
197 | "elastic buffer overrun errors = %i, " | ||
198 | "advertised receive buffer-to-buffer credit = %i, " | ||
199 | "current receice buffer-to-buffer credit = %i, " | ||
200 | "advertised transmit buffer-to-buffer credit = %i, " | ||
201 | "current transmit buffer-to-buffer credit = %i).\n", | ||
202 | err->primitive_sequence_event_timeout_count, | ||
203 | err->elastic_buffer_overrun_error_count, | ||
204 | err->advertised_receive_b2b_credit, | ||
205 | err->current_receive_b2b_credit, | ||
206 | err->advertised_transmit_b2b_credit, | ||
207 | err->current_transmit_b2b_credit); | ||
253 | } | 208 | } |
254 | 209 | ||
255 | /* | 210 | static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, u8 id, |
256 | * function: zfcp_fsf_protstatus_eval | 211 | struct fsf_link_down_info *link_down) |
257 | * | ||
258 | * purpose: evaluates the QTCB of the finished FSF request | ||
259 | * and initiates appropriate actions | ||
260 | * (usually calling FSF command specific handlers) | ||
261 | * | ||
262 | * returns: | ||
263 | * | ||
264 | * context: | ||
265 | * | ||
266 | * locks: | ||
267 | */ | ||
268 | static int | ||
269 | zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) | ||
270 | { | 212 | { |
271 | int retval = 0; | 213 | struct zfcp_adapter *adapter = req->adapter; |
272 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
273 | struct fsf_qtcb *qtcb = fsf_req->qtcb; | ||
274 | union fsf_prot_status_qual *prot_status_qual = | ||
275 | &qtcb->prefix.prot_status_qual; | ||
276 | |||
277 | zfcp_hba_dbf_event_fsf_response(fsf_req); | ||
278 | |||
279 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { | ||
280 | ZFCP_LOG_DEBUG("fsf_req 0x%lx has been dismissed\n", | ||
281 | (unsigned long) fsf_req); | ||
282 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | ||
283 | ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */ | ||
284 | goto skip_protstatus; | ||
285 | } | ||
286 | 214 | ||
287 | /* evaluate FSF Protocol Status */ | 215 | if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) |
288 | switch (qtcb->prefix.prot_status) { | 216 | return; |
289 | 217 | ||
290 | case FSF_PROT_GOOD: | 218 | atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); |
291 | case FSF_PROT_FSF_STATUS_PRESENTED: | ||
292 | break; | ||
293 | 219 | ||
294 | case FSF_PROT_QTCB_VERSION_ERROR: | 220 | if (!link_down) |
295 | ZFCP_LOG_NORMAL("error: The adapter %s contains " | 221 | goto out; |
296 | "microcode of version 0x%x, the device driver " | ||
297 | "only supports 0x%x. Aborting.\n", | ||
298 | zfcp_get_busid_by_adapter(adapter), | ||
299 | prot_status_qual->version_error.fsf_version, | ||
300 | ZFCP_QTCB_VERSION); | ||
301 | zfcp_erp_adapter_shutdown(adapter, 0, 117, fsf_req); | ||
302 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
303 | break; | ||
304 | 222 | ||
305 | case FSF_PROT_SEQ_NUMB_ERROR: | 223 | switch (link_down->error_code) { |
306 | ZFCP_LOG_NORMAL("bug: Sequence number mismatch between " | 224 | case FSF_PSQ_LINK_NO_LIGHT: |
307 | "driver (0x%x) and adapter %s (0x%x). " | 225 | dev_warn(&req->adapter->ccw_device->dev, |
308 | "Restarting all operations on this adapter.\n", | 226 | "The local link is down: no light detected.\n"); |
309 | qtcb->prefix.req_seq_no, | ||
310 | zfcp_get_busid_by_adapter(adapter), | ||
311 | prot_status_qual->sequence_error.exp_req_seq_no); | ||
312 | zfcp_erp_adapter_reopen(adapter, 0, 98, fsf_req); | ||
313 | fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY; | ||
314 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
315 | break; | 227 | break; |
316 | 228 | case FSF_PSQ_LINK_WRAP_PLUG: | |
317 | case FSF_PROT_UNSUPP_QTCB_TYPE: | 229 | dev_warn(&req->adapter->ccw_device->dev, |
318 | ZFCP_LOG_NORMAL("error: Packet header type used by the " | 230 | "The local link is down: wrap plug detected.\n"); |
319 | "device driver is incompatible with " | ||
320 | "that used on adapter %s. " | ||
321 | "Stopping all operations on this adapter.\n", | ||
322 | zfcp_get_busid_by_adapter(adapter)); | ||
323 | zfcp_erp_adapter_shutdown(adapter, 0, 118, fsf_req); | ||
324 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
325 | break; | 231 | break; |
326 | 232 | case FSF_PSQ_LINK_NO_FCP: | |
327 | case FSF_PROT_HOST_CONNECTION_INITIALIZING: | 233 | dev_warn(&req->adapter->ccw_device->dev, |
328 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 234 | "The local link is down: " |
329 | atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | 235 | "adjacent node on link does not support FCP.\n"); |
330 | &(adapter->status)); | ||
331 | break; | 236 | break; |
332 | 237 | case FSF_PSQ_LINK_FIRMWARE_UPDATE: | |
333 | case FSF_PROT_DUPLICATE_REQUEST_ID: | 238 | dev_warn(&req->adapter->ccw_device->dev, |
334 | ZFCP_LOG_NORMAL("bug: The request identifier 0x%Lx " | 239 | "The local link is down: " |
335 | "to the adapter %s is ambiguous. " | 240 | "firmware update in progress.\n"); |
336 | "Stopping all operations on this adapter.\n", | ||
337 | *(unsigned long long*) | ||
338 | (&qtcb->bottom.support.req_handle), | ||
339 | zfcp_get_busid_by_adapter(adapter)); | ||
340 | zfcp_erp_adapter_shutdown(adapter, 0, 78, fsf_req); | ||
341 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
342 | break; | 241 | break; |
343 | 242 | case FSF_PSQ_LINK_INVALID_WWPN: | |
344 | case FSF_PROT_LINK_DOWN: | 243 | dev_warn(&req->adapter->ccw_device->dev, |
345 | zfcp_fsf_link_down_info_eval(fsf_req, 37, | 244 | "The local link is down: " |
346 | &prot_status_qual->link_down_info); | 245 | "duplicate or invalid WWPN detected.\n"); |
347 | /* FIXME: reopening adapter now? better wait for link up */ | ||
348 | zfcp_erp_adapter_reopen(adapter, 0, 79, fsf_req); | ||
349 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
350 | break; | 246 | break; |
351 | 247 | case FSF_PSQ_LINK_NO_NPIV_SUPPORT: | |
352 | case FSF_PROT_REEST_QUEUE: | 248 | dev_warn(&req->adapter->ccw_device->dev, |
353 | ZFCP_LOG_NORMAL("The local link to adapter with " | 249 | "The local link is down: " |
354 | "%s was re-plugged. " | 250 | "no support for NPIV by Fabric.\n"); |
355 | "Re-starting operations on this adapter.\n", | ||
356 | zfcp_get_busid_by_adapter(adapter)); | ||
357 | /* All ports should be marked as ready to run again */ | ||
358 | zfcp_erp_modify_adapter_status(adapter, 28, NULL, | ||
359 | ZFCP_STATUS_COMMON_RUNNING, | ||
360 | ZFCP_SET); | ||
361 | zfcp_erp_adapter_reopen(adapter, | ||
362 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ||
363 | | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
364 | 99, fsf_req); | ||
365 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
366 | break; | 251 | break; |
367 | 252 | case FSF_PSQ_LINK_NO_FCP_RESOURCES: | |
368 | case FSF_PROT_ERROR_STATE: | 253 | dev_warn(&req->adapter->ccw_device->dev, |
369 | ZFCP_LOG_NORMAL("error: The adapter %s " | 254 | "The local link is down: " |
370 | "has entered the error state. " | 255 | "out of resource in FCP daughtercard.\n"); |
371 | "Restarting all operations on this " | 256 | break; |
372 | "adapter.\n", | 257 | case FSF_PSQ_LINK_NO_FABRIC_RESOURCES: |
373 | zfcp_get_busid_by_adapter(adapter)); | 258 | dev_warn(&req->adapter->ccw_device->dev, |
374 | zfcp_erp_adapter_reopen(adapter, 0, 100, fsf_req); | 259 | "The local link is down: " |
375 | fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY; | 260 | "out of resource in Fabric.\n"); |
376 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 261 | break; |
262 | case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE: | ||
263 | dev_warn(&req->adapter->ccw_device->dev, | ||
264 | "The local link is down: " | ||
265 | "unable to login to Fabric.\n"); | ||
266 | break; | ||
267 | case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED: | ||
268 | dev_warn(&req->adapter->ccw_device->dev, | ||
269 | "WWPN assignment file corrupted on adapter.\n"); | ||
270 | break; | ||
271 | case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED: | ||
272 | dev_warn(&req->adapter->ccw_device->dev, | ||
273 | "Mode table corrupted on adapter.\n"); | ||
274 | break; | ||
275 | case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT: | ||
276 | dev_warn(&req->adapter->ccw_device->dev, | ||
277 | "No WWPN for assignment table on adapter.\n"); | ||
377 | break; | 278 | break; |
378 | |||
379 | default: | 279 | default: |
380 | ZFCP_LOG_NORMAL("bug: Transfer protocol status information " | 280 | dev_warn(&req->adapter->ccw_device->dev, |
381 | "provided by the adapter %s " | 281 | "The local link to adapter is down.\n"); |
382 | "is not compatible with the device driver. " | ||
383 | "Stopping all operations on this adapter. " | ||
384 | "(debug info 0x%x).\n", | ||
385 | zfcp_get_busid_by_adapter(adapter), | ||
386 | qtcb->prefix.prot_status); | ||
387 | zfcp_erp_adapter_shutdown(adapter, 0, 119, fsf_req); | ||
388 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
389 | } | 282 | } |
283 | out: | ||
284 | zfcp_erp_adapter_failed(adapter, id, req); | ||
285 | } | ||
390 | 286 | ||
391 | skip_protstatus: | 287 | static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req) |
392 | /* | 288 | { |
393 | * always call specific handlers to give them a chance to do | 289 | struct zfcp_adapter *adapter = req->adapter; |
394 | * something meaningful even in error cases | 290 | struct fsf_status_read_buffer *sr_buf = req->data; |
395 | */ | 291 | struct fsf_link_down_info *ldi = |
396 | zfcp_fsf_fsfstatus_eval(fsf_req); | 292 | (struct fsf_link_down_info *) &sr_buf->payload; |
397 | return retval; | 293 | |
294 | switch (sr_buf->status_subtype) { | ||
295 | case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: | ||
296 | dev_warn(&adapter->ccw_device->dev, | ||
297 | "Physical link is down.\n"); | ||
298 | zfcp_fsf_link_down_info_eval(req, 38, ldi); | ||
299 | break; | ||
300 | case FSF_STATUS_READ_SUB_FDISC_FAILED: | ||
301 | dev_warn(&adapter->ccw_device->dev, | ||
302 | "Local link is down " | ||
303 | "due to failed FDISC login.\n"); | ||
304 | zfcp_fsf_link_down_info_eval(req, 39, ldi); | ||
305 | break; | ||
306 | case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: | ||
307 | dev_warn(&adapter->ccw_device->dev, | ||
308 | "Local link is down " | ||
309 | "due to firmware update on adapter.\n"); | ||
310 | zfcp_fsf_link_down_info_eval(req, 40, NULL); | ||
311 | }; | ||
398 | } | 312 | } |
399 | 313 | ||
400 | /* | 314 | static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) |
401 | * function: zfcp_fsf_fsfstatus_eval | ||
402 | * | ||
403 | * purpose: evaluates FSF status of completed FSF request | ||
404 | * and acts accordingly | ||
405 | * | ||
406 | * returns: | ||
407 | */ | ||
408 | static int | ||
409 | zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req) | ||
410 | { | 315 | { |
411 | int retval = 0; | 316 | struct zfcp_adapter *adapter = req->adapter; |
317 | struct fsf_status_read_buffer *sr_buf = req->data; | ||
412 | 318 | ||
413 | if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { | 319 | if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { |
414 | goto skip_fsfstatus; | 320 | zfcp_hba_dbf_event_fsf_unsol("dism", adapter, sr_buf); |
321 | mempool_free(sr_buf, adapter->pool.data_status_read); | ||
322 | zfcp_fsf_req_free(req); | ||
323 | return; | ||
415 | } | 324 | } |
416 | 325 | ||
417 | /* evaluate FSF Status */ | 326 | zfcp_hba_dbf_event_fsf_unsol("read", adapter, sr_buf); |
418 | switch (fsf_req->qtcb->header.fsf_status) { | ||
419 | case FSF_UNKNOWN_COMMAND: | ||
420 | ZFCP_LOG_NORMAL("bug: Command issued by the device driver is " | ||
421 | "not known by the adapter %s " | ||
422 | "Stopping all operations on this adapter. " | ||
423 | "(debug info 0x%x).\n", | ||
424 | zfcp_get_busid_by_adapter(fsf_req->adapter), | ||
425 | fsf_req->qtcb->header.fsf_command); | ||
426 | zfcp_erp_adapter_shutdown(fsf_req->adapter, 0, 120, fsf_req); | ||
427 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
428 | break; | ||
429 | 327 | ||
430 | case FSF_FCP_RSP_AVAILABLE: | 328 | switch (sr_buf->status_type) { |
431 | ZFCP_LOG_DEBUG("FCP Sense data will be presented to the " | 329 | case FSF_STATUS_READ_PORT_CLOSED: |
432 | "SCSI stack.\n"); | 330 | zfcp_fsf_status_read_port_closed(req); |
433 | break; | 331 | break; |
434 | 332 | case FSF_STATUS_READ_INCOMING_ELS: | |
435 | case FSF_ADAPTER_STATUS_AVAILABLE: | 333 | zfcp_fc_incoming_els(req); |
436 | zfcp_fsf_fsfstatus_qual_eval(fsf_req); | 334 | break; |
335 | case FSF_STATUS_READ_SENSE_DATA_AVAIL: | ||
336 | break; | ||
337 | case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: | ||
338 | zfcp_fsf_bit_error_threshold(req); | ||
339 | break; | ||
340 | case FSF_STATUS_READ_LINK_DOWN: | ||
341 | zfcp_fsf_status_read_link_down(req); | ||
342 | break; | ||
343 | case FSF_STATUS_READ_LINK_UP: | ||
344 | dev_info(&adapter->ccw_device->dev, | ||
345 | "Local link was replugged.\n"); | ||
346 | /* All ports should be marked as ready to run again */ | ||
347 | zfcp_erp_modify_adapter_status(adapter, 30, NULL, | ||
348 | ZFCP_STATUS_COMMON_RUNNING, | ||
349 | ZFCP_SET); | ||
350 | zfcp_erp_adapter_reopen(adapter, | ||
351 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | | ||
352 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
353 | 102, req); | ||
354 | break; | ||
355 | case FSF_STATUS_READ_NOTIFICATION_LOST: | ||
356 | if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) | ||
357 | zfcp_erp_adapter_access_changed(adapter, 135, req); | ||
358 | if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) | ||
359 | schedule_work(&adapter->scan_work); | ||
360 | break; | ||
361 | case FSF_STATUS_READ_CFDC_UPDATED: | ||
362 | zfcp_erp_adapter_access_changed(adapter, 136, req); | ||
363 | break; | ||
364 | case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: | ||
365 | adapter->adapter_features = sr_buf->payload.word[0]; | ||
437 | break; | 366 | break; |
438 | } | 367 | } |
439 | 368 | ||
440 | skip_fsfstatus: | 369 | mempool_free(sr_buf, adapter->pool.data_status_read); |
441 | /* | 370 | zfcp_fsf_req_free(req); |
442 | * always call specific handlers to give them a chance to do | ||
443 | * something meaningful even in error cases | ||
444 | */ | ||
445 | zfcp_fsf_req_dispatch(fsf_req); | ||
446 | 371 | ||
447 | return retval; | 372 | atomic_inc(&adapter->stat_miss); |
373 | schedule_work(&adapter->stat_work); | ||
448 | } | 374 | } |
449 | 375 | ||
450 | /* | 376 | static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req) |
451 | * function: zfcp_fsf_fsfstatus_qual_eval | ||
452 | * | ||
453 | * purpose: evaluates FSF status-qualifier of completed FSF request | ||
454 | * and acts accordingly | ||
455 | * | ||
456 | * returns: | ||
457 | */ | ||
458 | static int | ||
459 | zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req) | ||
460 | { | 377 | { |
461 | int retval = 0; | 378 | switch (req->qtcb->header.fsf_status_qual.word[0]) { |
462 | |||
463 | switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) { | ||
464 | case FSF_SQ_FCP_RSP_AVAILABLE: | 379 | case FSF_SQ_FCP_RSP_AVAILABLE: |
465 | break; | ||
466 | case FSF_SQ_RETRY_IF_POSSIBLE: | ||
467 | /* The SCSI-stack may now issue retries or escalate */ | ||
468 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
469 | break; | ||
470 | case FSF_SQ_COMMAND_ABORTED: | ||
471 | /* Carry the aborted state on to upper layer */ | ||
472 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTED; | ||
473 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
474 | break; | ||
475 | case FSF_SQ_NO_RECOM: | ||
476 | ZFCP_LOG_NORMAL("bug: No recommendation could be given for a " | ||
477 | "problem on the adapter %s " | ||
478 | "Stopping all operations on this adapter. ", | ||
479 | zfcp_get_busid_by_adapter(fsf_req->adapter)); | ||
480 | zfcp_erp_adapter_shutdown(fsf_req->adapter, 0, 121, fsf_req); | ||
481 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
482 | break; | ||
483 | case FSF_SQ_ULP_PROGRAMMING_ERROR: | ||
484 | ZFCP_LOG_NORMAL("error: not enough SBALs for data transfer " | ||
485 | "(adapter %s)\n", | ||
486 | zfcp_get_busid_by_adapter(fsf_req->adapter)); | ||
487 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
488 | break; | ||
489 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 380 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
490 | case FSF_SQ_NO_RETRY_POSSIBLE: | 381 | case FSF_SQ_NO_RETRY_POSSIBLE: |
491 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 382 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
492 | /* dealt with in the respective functions */ | 383 | return; |
384 | case FSF_SQ_COMMAND_ABORTED: | ||
385 | req->status |= ZFCP_STATUS_FSFREQ_ABORTED; | ||
493 | break; | 386 | break; |
494 | default: | 387 | case FSF_SQ_NO_RECOM: |
495 | ZFCP_LOG_NORMAL("bug: Additional status info could " | 388 | dev_err(&req->adapter->ccw_device->dev, |
496 | "not be interpreted properly.\n"); | 389 | "No recommendation could be given for a " |
497 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, | 390 | "problem on the adapter.\n"); |
498 | (char *) &fsf_req->qtcb->header.fsf_status_qual, | 391 | zfcp_erp_adapter_shutdown(req->adapter, 0, 121, req); |
499 | sizeof (union fsf_status_qual)); | ||
500 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
501 | break; | 392 | break; |
502 | } | 393 | } |
503 | 394 | /* all non-return stats set FSFREQ_ERROR*/ | |
504 | return retval; | 395 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
505 | } | 396 | } |
506 | 397 | ||
507 | /** | 398 | static void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req) |
508 | * zfcp_fsf_link_down_info_eval - evaluate link down information block | ||
509 | */ | ||
510 | static void | ||
511 | zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *fsf_req, u8 id, | ||
512 | struct fsf_link_down_info *link_down) | ||
513 | { | 399 | { |
514 | struct zfcp_adapter *adapter = fsf_req->adapter; | 400 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) |
515 | |||
516 | if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, | ||
517 | &adapter->status)) | ||
518 | return; | 401 | return; |
519 | 402 | ||
520 | atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); | 403 | switch (req->qtcb->header.fsf_status) { |
521 | 404 | case FSF_UNKNOWN_COMMAND: | |
522 | if (link_down == NULL) | 405 | dev_err(&req->adapter->ccw_device->dev, |
523 | goto out; | 406 | "Command issued by the device driver (0x%x) is " |
524 | 407 | "not known by the adapter.\n", | |
525 | switch (link_down->error_code) { | 408 | req->qtcb->header.fsf_command); |
526 | case FSF_PSQ_LINK_NO_LIGHT: | 409 | zfcp_erp_adapter_shutdown(req->adapter, 0, 120, req); |
527 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 410 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
528 | "(no light detected)\n", | ||
529 | zfcp_get_busid_by_adapter(adapter)); | ||
530 | break; | ||
531 | case FSF_PSQ_LINK_WRAP_PLUG: | ||
532 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | ||
533 | "(wrap plug detected)\n", | ||
534 | zfcp_get_busid_by_adapter(adapter)); | ||
535 | break; | ||
536 | case FSF_PSQ_LINK_NO_FCP: | ||
537 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | ||
538 | "(adjacent node on link does not support FCP)\n", | ||
539 | zfcp_get_busid_by_adapter(adapter)); | ||
540 | break; | 411 | break; |
541 | case FSF_PSQ_LINK_FIRMWARE_UPDATE: | 412 | case FSF_ADAPTER_STATUS_AVAILABLE: |
542 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 413 | zfcp_fsf_fsfstatus_qual_eval(req); |
543 | "(firmware update in progress)\n", | ||
544 | zfcp_get_busid_by_adapter(adapter)); | ||
545 | break; | ||
546 | case FSF_PSQ_LINK_INVALID_WWPN: | ||
547 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | ||
548 | "(duplicate or invalid WWPN detected)\n", | ||
549 | zfcp_get_busid_by_adapter(adapter)); | ||
550 | break; | 414 | break; |
551 | case FSF_PSQ_LINK_NO_NPIV_SUPPORT: | 415 | } |
552 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 416 | } |
553 | "(no support for NPIV by Fabric)\n", | 417 | |
554 | zfcp_get_busid_by_adapter(adapter)); | 418 | static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) |
419 | { | ||
420 | struct zfcp_adapter *adapter = req->adapter; | ||
421 | struct fsf_qtcb *qtcb = req->qtcb; | ||
422 | union fsf_prot_status_qual *psq = &qtcb->prefix.prot_status_qual; | ||
423 | |||
424 | zfcp_hba_dbf_event_fsf_response(req); | ||
425 | |||
426 | if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { | ||
427 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | | ||
428 | ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */ | ||
429 | return; | ||
430 | } | ||
431 | |||
432 | switch (qtcb->prefix.prot_status) { | ||
433 | case FSF_PROT_GOOD: | ||
434 | case FSF_PROT_FSF_STATUS_PRESENTED: | ||
435 | return; | ||
436 | case FSF_PROT_QTCB_VERSION_ERROR: | ||
437 | dev_err(&adapter->ccw_device->dev, | ||
438 | "The QTCB version requested by zfcp (0x%x) is not " | ||
439 | "supported by the FCP adapter (lowest supported " | ||
440 | "0x%x, highest supported 0x%x).\n", | ||
441 | FSF_QTCB_CURRENT_VERSION, psq->word[0], | ||
442 | psq->word[1]); | ||
443 | zfcp_erp_adapter_shutdown(adapter, 0, 117, req); | ||
555 | break; | 444 | break; |
556 | case FSF_PSQ_LINK_NO_FCP_RESOURCES: | 445 | case FSF_PROT_ERROR_STATE: |
557 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 446 | case FSF_PROT_SEQ_NUMB_ERROR: |
558 | "(out of resource in FCP daughtercard)\n", | 447 | zfcp_erp_adapter_reopen(adapter, 0, 98, req); |
559 | zfcp_get_busid_by_adapter(adapter)); | 448 | req->status |= ZFCP_STATUS_FSFREQ_RETRY; |
560 | break; | 449 | break; |
561 | case FSF_PSQ_LINK_NO_FABRIC_RESOURCES: | 450 | case FSF_PROT_UNSUPP_QTCB_TYPE: |
562 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 451 | dev_err(&adapter->ccw_device->dev, |
563 | "(out of resource in Fabric)\n", | 452 | "Packet header type used by the device driver is " |
564 | zfcp_get_busid_by_adapter(adapter)); | 453 | "incompatible with that used on the adapter.\n"); |
454 | zfcp_erp_adapter_shutdown(adapter, 0, 118, req); | ||
565 | break; | 455 | break; |
566 | case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE: | 456 | case FSF_PROT_HOST_CONNECTION_INITIALIZING: |
567 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 457 | atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, |
568 | "(unable to Fabric login)\n", | 458 | &adapter->status); |
569 | zfcp_get_busid_by_adapter(adapter)); | ||
570 | break; | 459 | break; |
571 | case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED: | 460 | case FSF_PROT_DUPLICATE_REQUEST_ID: |
572 | ZFCP_LOG_NORMAL("WWPN assignment file corrupted on adapter %s\n", | 461 | dev_err(&adapter->ccw_device->dev, |
573 | zfcp_get_busid_by_adapter(adapter)); | 462 | "The request identifier 0x%Lx is ambiguous.\n", |
463 | (unsigned long long)qtcb->bottom.support.req_handle); | ||
464 | zfcp_erp_adapter_shutdown(adapter, 0, 78, req); | ||
574 | break; | 465 | break; |
575 | case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED: | 466 | case FSF_PROT_LINK_DOWN: |
576 | ZFCP_LOG_NORMAL("Mode table corrupted on adapter %s\n", | 467 | zfcp_fsf_link_down_info_eval(req, 37, &psq->link_down_info); |
577 | zfcp_get_busid_by_adapter(adapter)); | 468 | /* FIXME: reopening adapter now? better wait for link up */ |
469 | zfcp_erp_adapter_reopen(adapter, 0, 79, req); | ||
578 | break; | 470 | break; |
579 | case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT: | 471 | case FSF_PROT_REEST_QUEUE: |
580 | ZFCP_LOG_NORMAL("No WWPN for assignment table on adapter %s\n", | 472 | /* All ports should be marked as ready to run again */ |
581 | zfcp_get_busid_by_adapter(adapter)); | 473 | zfcp_erp_modify_adapter_status(adapter, 28, NULL, |
474 | ZFCP_STATUS_COMMON_RUNNING, | ||
475 | ZFCP_SET); | ||
476 | zfcp_erp_adapter_reopen(adapter, | ||
477 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | | ||
478 | ZFCP_STATUS_COMMON_ERP_FAILED, 99, req); | ||
582 | break; | 479 | break; |
583 | default: | 480 | default: |
584 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 481 | dev_err(&adapter->ccw_device->dev, |
585 | "(warning: unknown reason code %d)\n", | 482 | "Transfer protocol status information" |
586 | zfcp_get_busid_by_adapter(adapter), | 483 | "provided by the adapter (0x%x) " |
587 | link_down->error_code); | 484 | "is not compatible with the device driver.\n", |
588 | } | 485 | qtcb->prefix.prot_status); |
589 | 486 | zfcp_erp_adapter_shutdown(adapter, 0, 119, req); | |
590 | if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) | 487 | } |
591 | ZFCP_LOG_DEBUG("Debug information to link down: " | 488 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
592 | "primary_status=0x%02x " | ||
593 | "ioerr_code=0x%02x " | ||
594 | "action_code=0x%02x " | ||
595 | "reason_code=0x%02x " | ||
596 | "explanation_code=0x%02x " | ||
597 | "vendor_specific_code=0x%02x\n", | ||
598 | link_down->primary_status, | ||
599 | link_down->ioerr_code, | ||
600 | link_down->action_code, | ||
601 | link_down->reason_code, | ||
602 | link_down->explanation_code, | ||
603 | link_down->vendor_specific_code); | ||
604 | |||
605 | out: | ||
606 | zfcp_erp_adapter_failed(adapter, id, fsf_req); | ||
607 | } | 489 | } |
608 | 490 | ||
609 | /* | 491 | /** |
610 | * function: zfcp_fsf_req_dispatch | 492 | * zfcp_fsf_req_complete - process completion of a FSF request |
611 | * | 493 | * @fsf_req: The FSF request that has been completed. |
612 | * purpose: calls the appropriate command specific handler | ||
613 | * | 494 | * |
614 | * returns: | 495 | * When a request has been completed either from the FCP adapter, |
496 | * or it has been dismissed due to a queue shutdown, this function | ||
497 | * is called to process the completion status and trigger further | ||
498 | * events related to the FSF request. | ||
615 | */ | 499 | */ |
616 | static int | 500 | void zfcp_fsf_req_complete(struct zfcp_fsf_req *req) |
617 | zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) | ||
618 | { | 501 | { |
619 | struct zfcp_erp_action *erp_action = fsf_req->erp_action; | 502 | if (unlikely(req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { |
620 | struct zfcp_adapter *adapter = fsf_req->adapter; | 503 | zfcp_fsf_status_read_handler(req); |
621 | int retval = 0; | 504 | return; |
505 | } | ||
622 | 506 | ||
507 | del_timer(&req->timer); | ||
508 | zfcp_fsf_protstatus_eval(req); | ||
509 | zfcp_fsf_fsfstatus_eval(req); | ||
510 | req->handler(req); | ||
623 | 511 | ||
624 | switch (fsf_req->fsf_command) { | 512 | if (req->erp_action) |
513 | zfcp_erp_notify(req->erp_action, 0); | ||
514 | req->status |= ZFCP_STATUS_FSFREQ_COMPLETED; | ||
625 | 515 | ||
626 | case FSF_QTCB_FCP_CMND: | 516 | if (likely(req->status & ZFCP_STATUS_FSFREQ_CLEANUP)) |
627 | zfcp_fsf_send_fcp_command_handler(fsf_req); | 517 | zfcp_fsf_req_free(req); |
628 | break; | 518 | else |
519 | /* notify initiator waiting for the requests completion */ | ||
520 | /* | ||
521 | * FIXME: Race! We must not access fsf_req here as it might have been | ||
522 | * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED | ||
523 | * flag. It's an improbable case. But, we have the same paranoia for | ||
524 | * the cleanup flag already. | ||
525 | * Might better be handled using complete()? | ||
526 | * (setting the flag and doing wakeup ought to be atomic | ||
527 | * with regard to checking the flag as long as waitqueue is | ||
528 | * part of the to be released structure) | ||
529 | */ | ||
530 | wake_up(&req->completion_wq); | ||
531 | } | ||
629 | 532 | ||
630 | case FSF_QTCB_ABORT_FCP_CMND: | 533 | static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) |
631 | zfcp_fsf_abort_fcp_command_handler(fsf_req); | 534 | { |
632 | break; | 535 | struct fsf_qtcb_bottom_config *bottom; |
536 | struct zfcp_adapter *adapter = req->adapter; | ||
537 | struct Scsi_Host *shost = adapter->scsi_host; | ||
633 | 538 | ||
634 | case FSF_QTCB_SEND_GENERIC: | 539 | bottom = &req->qtcb->bottom.config; |
635 | zfcp_fsf_send_ct_handler(fsf_req); | ||
636 | break; | ||
637 | 540 | ||
638 | case FSF_QTCB_OPEN_PORT_WITH_DID: | 541 | if (req->data) |
639 | zfcp_fsf_open_port_handler(fsf_req); | 542 | memcpy(req->data, bottom, sizeof(*bottom)); |
640 | break; | ||
641 | 543 | ||
642 | case FSF_QTCB_OPEN_LUN: | 544 | fc_host_node_name(shost) = bottom->nport_serv_param.wwnn; |
643 | zfcp_fsf_open_unit_handler(fsf_req); | 545 | fc_host_port_name(shost) = bottom->nport_serv_param.wwpn; |
644 | break; | 546 | fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK; |
547 | fc_host_speed(shost) = bottom->fc_link_speed; | ||
548 | fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; | ||
645 | 549 | ||
646 | case FSF_QTCB_CLOSE_LUN: | 550 | adapter->hydra_version = bottom->adapter_type; |
647 | zfcp_fsf_close_unit_handler(fsf_req); | 551 | adapter->timer_ticks = bottom->timer_interval; |
648 | break; | ||
649 | 552 | ||
650 | case FSF_QTCB_CLOSE_PORT: | 553 | if (fc_host_permanent_port_name(shost) == -1) |
651 | zfcp_fsf_close_port_handler(fsf_req); | 554 | fc_host_permanent_port_name(shost) = fc_host_port_name(shost); |
652 | break; | ||
653 | 555 | ||
654 | case FSF_QTCB_CLOSE_PHYSICAL_PORT: | 556 | switch (bottom->fc_topology) { |
655 | zfcp_fsf_close_physical_port_handler(fsf_req); | 557 | case FSF_TOPO_P2P: |
656 | break; | 558 | adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK; |
559 | adapter->peer_wwpn = bottom->plogi_payload.wwpn; | ||
560 | adapter->peer_wwnn = bottom->plogi_payload.wwnn; | ||
561 | fc_host_port_type(shost) = FC_PORTTYPE_PTP; | ||
562 | if (req->erp_action) | ||
563 | dev_info(&adapter->ccw_device->dev, | ||
564 | "Point-to-Point fibrechannel " | ||
565 | "configuration detected.\n"); | ||
566 | break; | ||
567 | case FSF_TOPO_FABRIC: | ||
568 | fc_host_port_type(shost) = FC_PORTTYPE_NPORT; | ||
569 | if (req->erp_action) | ||
570 | dev_info(&adapter->ccw_device->dev, | ||
571 | "Switched fabric fibrechannel " | ||
572 | "network detected.\n"); | ||
573 | break; | ||
574 | case FSF_TOPO_AL: | ||
575 | fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; | ||
576 | dev_err(&adapter->ccw_device->dev, | ||
577 | "Unsupported arbitrated loop fibrechannel " | ||
578 | "topology detected, shutting down " | ||
579 | "adapter.\n"); | ||
580 | zfcp_erp_adapter_shutdown(adapter, 0, 127, req); | ||
581 | return -EIO; | ||
582 | default: | ||
583 | fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; | ||
584 | dev_err(&adapter->ccw_device->dev, | ||
585 | "The fibrechannel topology reported by the" | ||
586 | " adapter is not known by the zfcp driver," | ||
587 | " shutting down adapter.\n"); | ||
588 | zfcp_erp_adapter_shutdown(adapter, 0, 128, req); | ||
589 | return -EIO; | ||
590 | } | ||
657 | 591 | ||
658 | case FSF_QTCB_EXCHANGE_CONFIG_DATA: | 592 | return 0; |
659 | zfcp_fsf_exchange_config_data_handler(fsf_req); | 593 | } |
660 | break; | ||
661 | 594 | ||
662 | case FSF_QTCB_EXCHANGE_PORT_DATA: | 595 | static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) |
663 | zfcp_fsf_exchange_port_data_handler(fsf_req); | 596 | { |
664 | break; | 597 | struct zfcp_adapter *adapter = req->adapter; |
598 | struct fsf_qtcb *qtcb = req->qtcb; | ||
599 | struct fsf_qtcb_bottom_config *bottom = &qtcb->bottom.config; | ||
600 | struct Scsi_Host *shost = adapter->scsi_host; | ||
665 | 601 | ||
666 | case FSF_QTCB_SEND_ELS: | 602 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
667 | zfcp_fsf_send_els_handler(fsf_req); | 603 | return; |
668 | break; | ||
669 | 604 | ||
670 | case FSF_QTCB_DOWNLOAD_CONTROL_FILE: | 605 | adapter->fsf_lic_version = bottom->lic_version; |
671 | zfcp_fsf_control_file_handler(fsf_req); | 606 | adapter->adapter_features = bottom->adapter_features; |
672 | break; | 607 | adapter->connection_features = bottom->connection_features; |
608 | adapter->peer_wwpn = 0; | ||
609 | adapter->peer_wwnn = 0; | ||
610 | adapter->peer_d_id = 0; | ||
673 | 611 | ||
674 | case FSF_QTCB_UPLOAD_CONTROL_FILE: | 612 | switch (qtcb->header.fsf_status) { |
675 | zfcp_fsf_control_file_handler(fsf_req); | 613 | case FSF_GOOD: |
614 | if (zfcp_fsf_exchange_config_evaluate(req)) | ||
615 | return; | ||
616 | |||
617 | if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) { | ||
618 | dev_err(&adapter->ccw_device->dev, | ||
619 | "Maximum QTCB size (%d bytes) allowed by " | ||
620 | "the adapter is lower than the minimum " | ||
621 | "required by the driver (%ld bytes).\n", | ||
622 | bottom->max_qtcb_size, | ||
623 | sizeof(struct fsf_qtcb)); | ||
624 | zfcp_erp_adapter_shutdown(adapter, 0, 129, req); | ||
625 | return; | ||
626 | } | ||
627 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | ||
628 | &adapter->status); | ||
676 | break; | 629 | break; |
630 | case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: | ||
631 | fc_host_node_name(shost) = 0; | ||
632 | fc_host_port_name(shost) = 0; | ||
633 | fc_host_port_id(shost) = 0; | ||
634 | fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; | ||
635 | fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; | ||
636 | adapter->hydra_version = 0; | ||
677 | 637 | ||
638 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | ||
639 | &adapter->status); | ||
640 | |||
641 | zfcp_fsf_link_down_info_eval(req, 42, | ||
642 | &qtcb->header.fsf_status_qual.link_down_info); | ||
643 | break; | ||
678 | default: | 644 | default: |
679 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 645 | zfcp_erp_adapter_shutdown(adapter, 0, 130, req); |
680 | ZFCP_LOG_NORMAL("bug: Command issued by the device driver is " | 646 | return; |
681 | "not supported by the adapter %s\n", | ||
682 | zfcp_get_busid_by_adapter(adapter)); | ||
683 | if (fsf_req->fsf_command != fsf_req->qtcb->header.fsf_command) | ||
684 | ZFCP_LOG_NORMAL | ||
685 | ("bug: Command issued by the device driver differs " | ||
686 | "from the command returned by the adapter %s " | ||
687 | "(debug info 0x%x, 0x%x).\n", | ||
688 | zfcp_get_busid_by_adapter(adapter), | ||
689 | fsf_req->fsf_command, | ||
690 | fsf_req->qtcb->header.fsf_command); | ||
691 | } | 647 | } |
692 | 648 | ||
693 | if (!erp_action) | 649 | if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) { |
694 | return retval; | 650 | adapter->hardware_version = bottom->hardware_version; |
695 | 651 | memcpy(fc_host_serial_number(shost), bottom->serial_number, | |
696 | zfcp_erp_async_handler(erp_action, 0); | 652 | min(FC_SERIAL_NUMBER_SIZE, 17)); |
653 | EBCASC(fc_host_serial_number(shost), | ||
654 | min(FC_SERIAL_NUMBER_SIZE, 17)); | ||
655 | } | ||
697 | 656 | ||
698 | return retval; | 657 | if (FSF_QTCB_CURRENT_VERSION < bottom->low_qtcb_version) { |
658 | dev_err(&adapter->ccw_device->dev, | ||
659 | "The adapter only supports newer control block " | ||
660 | "versions, try updated device driver.\n"); | ||
661 | zfcp_erp_adapter_shutdown(adapter, 0, 125, req); | ||
662 | return; | ||
663 | } | ||
664 | if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) { | ||
665 | dev_err(&adapter->ccw_device->dev, | ||
666 | "The adapter only supports older control block " | ||
667 | "versions, consider a microcode upgrade.\n"); | ||
668 | zfcp_erp_adapter_shutdown(adapter, 0, 126, req); | ||
669 | } | ||
699 | } | 670 | } |
700 | 671 | ||
701 | /* | 672 | static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req) |
702 | * function: zfcp_fsf_status_read | ||
703 | * | ||
704 | * purpose: initiates a Status Read command at the specified adapter | ||
705 | * | ||
706 | * returns: | ||
707 | */ | ||
708 | int | ||
709 | zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) | ||
710 | { | 673 | { |
711 | struct zfcp_fsf_req *fsf_req; | 674 | struct zfcp_adapter *adapter = req->adapter; |
712 | struct fsf_status_read_buffer *status_buffer; | 675 | struct fsf_qtcb_bottom_port *bottom = &req->qtcb->bottom.port; |
713 | unsigned long lock_flags; | 676 | struct Scsi_Host *shost = adapter->scsi_host; |
714 | volatile struct qdio_buffer_element *sbale; | ||
715 | int retval = 0; | ||
716 | |||
717 | /* setup new FSF request */ | ||
718 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS, | ||
719 | req_flags | ZFCP_REQ_NO_QTCB, | ||
720 | adapter->pool.fsf_req_status_read, | ||
721 | &lock_flags, &fsf_req); | ||
722 | if (retval < 0) { | ||
723 | ZFCP_LOG_INFO("error: Could not create unsolicited status " | ||
724 | "buffer for adapter %s.\n", | ||
725 | zfcp_get_busid_by_adapter(adapter)); | ||
726 | goto failed_req_create; | ||
727 | } | ||
728 | |||
729 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | ||
730 | sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS; | ||
731 | sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
732 | fsf_req->sbale_curr = 2; | ||
733 | 677 | ||
734 | status_buffer = | 678 | if (req->data) |
735 | mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC); | 679 | memcpy(req->data, bottom, sizeof(*bottom)); |
736 | if (!status_buffer) { | ||
737 | ZFCP_LOG_NORMAL("bug: could not get some buffer\n"); | ||
738 | goto failed_buf; | ||
739 | } | ||
740 | memset(status_buffer, 0, sizeof (struct fsf_status_read_buffer)); | ||
741 | fsf_req->data = (unsigned long) status_buffer; | ||
742 | 680 | ||
743 | /* insert pointer to respective buffer */ | 681 | if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) |
744 | sbale = zfcp_qdio_sbale_curr(fsf_req); | 682 | fc_host_permanent_port_name(shost) = bottom->wwpn; |
745 | sbale->addr = (void *) status_buffer; | 683 | else |
746 | sbale->length = sizeof(struct fsf_status_read_buffer); | 684 | fc_host_permanent_port_name(shost) = fc_host_port_name(shost); |
685 | fc_host_maxframe_size(shost) = bottom->maximum_frame_size; | ||
686 | fc_host_supported_speeds(shost) = bottom->supported_speed; | ||
687 | } | ||
747 | 688 | ||
748 | retval = zfcp_fsf_req_send(fsf_req); | 689 | static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) |
749 | if (retval) { | 690 | { |
750 | ZFCP_LOG_DEBUG("error: Could not set-up unsolicited status " | 691 | struct zfcp_adapter *adapter = req->adapter; |
751 | "environment.\n"); | 692 | struct fsf_qtcb *qtcb = req->qtcb; |
752 | goto failed_req_send; | ||
753 | } | ||
754 | 693 | ||
755 | ZFCP_LOG_TRACE("Status Read request initiated (adapter%s)\n", | 694 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
756 | zfcp_get_busid_by_adapter(adapter)); | 695 | return; |
757 | goto out; | ||
758 | 696 | ||
759 | failed_req_send: | 697 | switch (qtcb->header.fsf_status) { |
760 | mempool_free(status_buffer, adapter->pool.data_status_read); | 698 | case FSF_GOOD: |
699 | zfcp_fsf_exchange_port_evaluate(req); | ||
700 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); | ||
701 | break; | ||
702 | case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: | ||
703 | zfcp_fsf_exchange_port_evaluate(req); | ||
704 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); | ||
705 | zfcp_fsf_link_down_info_eval(req, 43, | ||
706 | &qtcb->header.fsf_status_qual.link_down_info); | ||
707 | break; | ||
708 | } | ||
709 | } | ||
761 | 710 | ||
762 | failed_buf: | 711 | static int zfcp_fsf_sbal_check(struct zfcp_qdio_queue *queue) |
763 | zfcp_fsf_req_free(fsf_req); | 712 | { |
764 | failed_req_create: | 713 | spin_lock(&queue->lock); |
765 | zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL); | 714 | if (atomic_read(&queue->count)) |
766 | out: | 715 | return 1; |
767 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 716 | spin_unlock(&queue->lock); |
768 | return retval; | 717 | return 0; |
769 | } | 718 | } |
770 | 719 | ||
771 | static int | 720 | static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter) |
772 | zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req) | ||
773 | { | 721 | { |
774 | struct fsf_status_read_buffer *status_buffer; | 722 | long ret; |
775 | struct zfcp_adapter *adapter; | 723 | struct zfcp_qdio_queue *req_q = &adapter->req_q; |
776 | struct zfcp_port *port; | ||
777 | unsigned long flags; | ||
778 | 724 | ||
779 | status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; | 725 | spin_unlock(&req_q->lock); |
780 | adapter = fsf_req->adapter; | 726 | ret = wait_event_interruptible_timeout(adapter->request_wq, |
727 | zfcp_fsf_sbal_check(req_q), 5 * HZ); | ||
728 | if (ret > 0) | ||
729 | return 0; | ||
781 | 730 | ||
782 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 731 | spin_lock(&req_q->lock); |
783 | list_for_each_entry(port, &adapter->port_list_head, list) | 732 | return -EIO; |
784 | if (port->d_id == (status_buffer->d_id & ZFCP_DID_MASK)) | 733 | } |
785 | break; | ||
786 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
787 | 734 | ||
788 | if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) { | 735 | static struct zfcp_fsf_req *zfcp_fsf_alloc_noqtcb(mempool_t *pool) |
789 | ZFCP_LOG_NORMAL("bug: Reopen port indication received for " | 736 | { |
790 | "nonexisting port with d_id 0x%06x on " | 737 | struct zfcp_fsf_req *req; |
791 | "adapter %s. Ignored.\n", | 738 | req = mempool_alloc(pool, GFP_ATOMIC); |
792 | status_buffer->d_id & ZFCP_DID_MASK, | 739 | if (!req) |
793 | zfcp_get_busid_by_adapter(adapter)); | 740 | return NULL; |
794 | goto out; | 741 | memset(req, 0, sizeof(*req)); |
795 | } | 742 | return req; |
743 | } | ||
796 | 744 | ||
797 | switch (status_buffer->status_subtype) { | 745 | static struct zfcp_fsf_req *zfcp_fsf_alloc_qtcb(mempool_t *pool) |
746 | { | ||
747 | struct zfcp_fsf_req_qtcb *qtcb; | ||
798 | 748 | ||
799 | case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT: | 749 | if (likely(pool)) |
800 | zfcp_erp_port_reopen(port, 0, 101, fsf_req); | 750 | qtcb = mempool_alloc(pool, GFP_ATOMIC); |
801 | break; | 751 | else |
752 | qtcb = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache, | ||
753 | GFP_ATOMIC); | ||
754 | if (unlikely(!qtcb)) | ||
755 | return NULL; | ||
802 | 756 | ||
803 | case FSF_STATUS_READ_SUB_ERROR_PORT: | 757 | memset(qtcb, 0, sizeof(*qtcb)); |
804 | zfcp_erp_port_shutdown(port, 0, 122, fsf_req); | 758 | qtcb->fsf_req.qtcb = &qtcb->qtcb; |
805 | break; | 759 | qtcb->fsf_req.pool = pool; |
806 | 760 | ||
807 | default: | 761 | return &qtcb->fsf_req; |
808 | ZFCP_LOG_NORMAL("bug: Undefined status subtype received " | ||
809 | "for a reopen indication on port with " | ||
810 | "d_id 0x%06x on the adapter %s. " | ||
811 | "Ignored. (debug info 0x%x)\n", | ||
812 | status_buffer->d_id, | ||
813 | zfcp_get_busid_by_adapter(adapter), | ||
814 | status_buffer->status_subtype); | ||
815 | } | ||
816 | out: | ||
817 | return 0; | ||
818 | } | 762 | } |
819 | 763 | ||
820 | /* | 764 | static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, |
821 | * function: zfcp_fsf_status_read_handler | 765 | u32 fsf_cmd, int req_flags, |
822 | * | 766 | mempool_t *pool) |
823 | * purpose: is called for finished Open Port command | ||
824 | * | ||
825 | * returns: | ||
826 | */ | ||
827 | static int | ||
828 | zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) | ||
829 | { | 767 | { |
830 | int retval = 0; | 768 | volatile struct qdio_buffer_element *sbale; |
831 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
832 | struct fsf_status_read_buffer *status_buffer = | ||
833 | (struct fsf_status_read_buffer *) fsf_req->data; | ||
834 | struct fsf_bit_error_payload *fsf_bit_error; | ||
835 | |||
836 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { | ||
837 | zfcp_hba_dbf_event_fsf_unsol("dism", adapter, status_buffer); | ||
838 | mempool_free(status_buffer, adapter->pool.data_status_read); | ||
839 | zfcp_fsf_req_free(fsf_req); | ||
840 | goto out; | ||
841 | } | ||
842 | 769 | ||
843 | zfcp_hba_dbf_event_fsf_unsol("read", adapter, status_buffer); | 770 | struct zfcp_fsf_req *req; |
771 | struct zfcp_qdio_queue *req_q = &adapter->req_q; | ||
844 | 772 | ||
845 | switch (status_buffer->status_type) { | 773 | if (req_flags & ZFCP_REQ_NO_QTCB) |
774 | req = zfcp_fsf_alloc_noqtcb(pool); | ||
775 | else | ||
776 | req = zfcp_fsf_alloc_qtcb(pool); | ||
846 | 777 | ||
847 | case FSF_STATUS_READ_PORT_CLOSED: | 778 | if (unlikely(!req)) |
848 | zfcp_fsf_status_read_port_closed(fsf_req); | 779 | return ERR_PTR(-EIO); |
849 | break; | ||
850 | 780 | ||
851 | case FSF_STATUS_READ_INCOMING_ELS: | 781 | if (adapter->req_no == 0) |
852 | zfcp_fsf_incoming_els(fsf_req); | 782 | adapter->req_no++; |
853 | break; | ||
854 | 783 | ||
855 | case FSF_STATUS_READ_SENSE_DATA_AVAIL: | 784 | INIT_LIST_HEAD(&req->list); |
856 | ZFCP_LOG_INFO("unsolicited sense data received (adapter %s)\n", | 785 | init_timer(&req->timer); |
857 | zfcp_get_busid_by_adapter(adapter)); | 786 | init_waitqueue_head(&req->completion_wq); |
858 | break; | ||
859 | 787 | ||
860 | case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: | 788 | req->adapter = adapter; |
861 | fsf_bit_error = (struct fsf_bit_error_payload *) | 789 | req->fsf_command = fsf_cmd; |
862 | status_buffer->payload; | 790 | req->req_id = adapter->req_no++; |
863 | ZFCP_LOG_NORMAL("Warning: bit error threshold data " | 791 | req->sbal_number = 1; |
864 | "received (adapter %s, " | 792 | req->sbal_first = req_q->first; |
865 | "link failures = %i, loss of sync errors = %i, " | 793 | req->sbal_last = req_q->first; |
866 | "loss of signal errors = %i, " | 794 | req->sbale_curr = 1; |
867 | "primitive sequence errors = %i, " | ||
868 | "invalid transmission word errors = %i, " | ||
869 | "CRC errors = %i)\n", | ||
870 | zfcp_get_busid_by_adapter(adapter), | ||
871 | fsf_bit_error->link_failure_error_count, | ||
872 | fsf_bit_error->loss_of_sync_error_count, | ||
873 | fsf_bit_error->loss_of_signal_error_count, | ||
874 | fsf_bit_error->primitive_sequence_error_count, | ||
875 | fsf_bit_error->invalid_transmission_word_error_count, | ||
876 | fsf_bit_error->crc_error_count); | ||
877 | ZFCP_LOG_INFO("Additional bit error threshold data " | ||
878 | "(adapter %s, " | ||
879 | "primitive sequence event time-outs = %i, " | ||
880 | "elastic buffer overrun errors = %i, " | ||
881 | "advertised receive buffer-to-buffer credit = %i, " | ||
882 | "current receice buffer-to-buffer credit = %i, " | ||
883 | "advertised transmit buffer-to-buffer credit = %i, " | ||
884 | "current transmit buffer-to-buffer credit = %i)\n", | ||
885 | zfcp_get_busid_by_adapter(adapter), | ||
886 | fsf_bit_error->primitive_sequence_event_timeout_count, | ||
887 | fsf_bit_error->elastic_buffer_overrun_error_count, | ||
888 | fsf_bit_error->advertised_receive_b2b_credit, | ||
889 | fsf_bit_error->current_receive_b2b_credit, | ||
890 | fsf_bit_error->advertised_transmit_b2b_credit, | ||
891 | fsf_bit_error->current_transmit_b2b_credit); | ||
892 | break; | ||
893 | 795 | ||
894 | case FSF_STATUS_READ_LINK_DOWN: | 796 | sbale = zfcp_qdio_sbale_req(req); |
895 | switch (status_buffer->status_subtype) { | 797 | sbale[0].addr = (void *) req->req_id; |
896 | case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: | 798 | sbale[0].flags |= SBAL_FLAGS0_COMMAND; |
897 | ZFCP_LOG_INFO("Physical link to adapter %s is down\n", | ||
898 | zfcp_get_busid_by_adapter(adapter)); | ||
899 | zfcp_fsf_link_down_info_eval(fsf_req, 38, | ||
900 | (struct fsf_link_down_info *) | ||
901 | &status_buffer->payload); | ||
902 | break; | ||
903 | case FSF_STATUS_READ_SUB_FDISC_FAILED: | ||
904 | ZFCP_LOG_INFO("Local link to adapter %s is down " | ||
905 | "due to failed FDISC login\n", | ||
906 | zfcp_get_busid_by_adapter(adapter)); | ||
907 | zfcp_fsf_link_down_info_eval(fsf_req, 39, | ||
908 | (struct fsf_link_down_info *) | ||
909 | &status_buffer->payload); | ||
910 | break; | ||
911 | case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: | ||
912 | ZFCP_LOG_INFO("Local link to adapter %s is down " | ||
913 | "due to firmware update on adapter\n", | ||
914 | zfcp_get_busid_by_adapter(adapter)); | ||
915 | zfcp_fsf_link_down_info_eval(fsf_req, 40, NULL); | ||
916 | break; | ||
917 | default: | ||
918 | ZFCP_LOG_INFO("Local link to adapter %s is down " | ||
919 | "due to unknown reason\n", | ||
920 | zfcp_get_busid_by_adapter(adapter)); | ||
921 | zfcp_fsf_link_down_info_eval(fsf_req, 41, NULL); | ||
922 | }; | ||
923 | break; | ||
924 | 799 | ||
925 | case FSF_STATUS_READ_LINK_UP: | 800 | if (likely(req->qtcb)) { |
926 | ZFCP_LOG_NORMAL("Local link to adapter %s was replugged. " | 801 | req->qtcb->prefix.req_seq_no = req->adapter->fsf_req_seq_no; |
927 | "Restarting operations on this adapter\n", | 802 | req->qtcb->prefix.req_id = req->req_id; |
928 | zfcp_get_busid_by_adapter(adapter)); | 803 | req->qtcb->prefix.ulp_info = 26; |
929 | /* All ports should be marked as ready to run again */ | 804 | req->qtcb->prefix.qtcb_type = fsf_qtcb_type[req->fsf_command]; |
930 | zfcp_erp_modify_adapter_status(adapter, 30, NULL, | 805 | req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION; |
931 | ZFCP_STATUS_COMMON_RUNNING, | 806 | req->qtcb->header.req_handle = req->req_id; |
932 | ZFCP_SET); | 807 | req->qtcb->header.fsf_command = req->fsf_command; |
933 | zfcp_erp_adapter_reopen(adapter, | 808 | req->seq_no = adapter->fsf_req_seq_no; |
934 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | 809 | req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; |
935 | | ZFCP_STATUS_COMMON_ERP_FAILED, | 810 | sbale[1].addr = (void *) req->qtcb; |
936 | 102, fsf_req); | 811 | sbale[1].length = sizeof(struct fsf_qtcb); |
937 | break; | 812 | } |
938 | 813 | ||
939 | case FSF_STATUS_READ_NOTIFICATION_LOST: | 814 | if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) { |
940 | ZFCP_LOG_NORMAL("Unsolicited status notification(s) lost: " | 815 | zfcp_fsf_req_free(req); |
941 | "adapter %s%s%s%s%s%s%s%s%s\n", | 816 | return ERR_PTR(-EIO); |
942 | zfcp_get_busid_by_adapter(adapter), | 817 | } |
943 | (status_buffer->status_subtype & | ||
944 | FSF_STATUS_READ_SUB_INCOMING_ELS) ? | ||
945 | ", incoming ELS" : "", | ||
946 | (status_buffer->status_subtype & | ||
947 | FSF_STATUS_READ_SUB_SENSE_DATA) ? | ||
948 | ", sense data" : "", | ||
949 | (status_buffer->status_subtype & | ||
950 | FSF_STATUS_READ_SUB_LINK_STATUS) ? | ||
951 | ", link status change" : "", | ||
952 | (status_buffer->status_subtype & | ||
953 | FSF_STATUS_READ_SUB_PORT_CLOSED) ? | ||
954 | ", port close" : "", | ||
955 | (status_buffer->status_subtype & | ||
956 | FSF_STATUS_READ_SUB_BIT_ERROR_THRESHOLD) ? | ||
957 | ", bit error exception" : "", | ||
958 | (status_buffer->status_subtype & | ||
959 | FSF_STATUS_READ_SUB_ACT_UPDATED) ? | ||
960 | ", ACT update" : "", | ||
961 | (status_buffer->status_subtype & | ||
962 | FSF_STATUS_READ_SUB_ACT_HARDENED) ? | ||
963 | ", ACT hardening" : "", | ||
964 | (status_buffer->status_subtype & | ||
965 | FSF_STATUS_READ_SUB_FEATURE_UPDATE_ALERT) ? | ||
966 | ", adapter feature change" : ""); | ||
967 | |||
968 | if (status_buffer->status_subtype & | ||
969 | FSF_STATUS_READ_SUB_ACT_UPDATED) | ||
970 | zfcp_erp_adapter_access_changed(adapter, 135, fsf_req); | ||
971 | break; | ||
972 | 818 | ||
973 | case FSF_STATUS_READ_CFDC_UPDATED: | 819 | if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) |
974 | ZFCP_LOG_NORMAL("CFDC has been updated on the adapter %s\n", | 820 | req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; |
975 | zfcp_get_busid_by_adapter(adapter)); | ||
976 | zfcp_erp_adapter_access_changed(adapter, 136, fsf_req); | ||
977 | break; | ||
978 | 821 | ||
979 | case FSF_STATUS_READ_CFDC_HARDENED: | 822 | return req; |
980 | switch (status_buffer->status_subtype) { | 823 | } |
981 | case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE: | ||
982 | ZFCP_LOG_NORMAL("CFDC of adapter %s saved on SE\n", | ||
983 | zfcp_get_busid_by_adapter(adapter)); | ||
984 | break; | ||
985 | case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2: | ||
986 | ZFCP_LOG_NORMAL("CFDC of adapter %s has been copied " | ||
987 | "to the secondary SE\n", | ||
988 | zfcp_get_busid_by_adapter(adapter)); | ||
989 | break; | ||
990 | default: | ||
991 | ZFCP_LOG_NORMAL("CFDC of adapter %s has been hardened\n", | ||
992 | zfcp_get_busid_by_adapter(adapter)); | ||
993 | } | ||
994 | break; | ||
995 | 824 | ||
996 | case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: | 825 | static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) |
997 | ZFCP_LOG_INFO("List of supported features on adapter %s has " | 826 | { |
998 | "been changed from 0x%08X to 0x%08X\n", | 827 | struct zfcp_adapter *adapter = req->adapter; |
999 | zfcp_get_busid_by_adapter(adapter), | 828 | struct zfcp_qdio_queue *req_q = &adapter->req_q; |
1000 | *(u32*) (status_buffer->payload + 4), | 829 | int idx; |
1001 | *(u32*) (status_buffer->payload)); | ||
1002 | adapter->adapter_features = *(u32*) status_buffer->payload; | ||
1003 | break; | ||
1004 | 830 | ||
1005 | default: | 831 | /* put allocated FSF request into hash table */ |
1006 | ZFCP_LOG_NORMAL("warning: An unsolicited status packet of unknown " | 832 | spin_lock(&adapter->req_list_lock); |
1007 | "type was received (debug info 0x%x)\n", | 833 | idx = zfcp_reqlist_hash(req->req_id); |
1008 | status_buffer->status_type); | 834 | list_add_tail(&req->list, &adapter->req_list[idx]); |
1009 | ZFCP_LOG_DEBUG("Dump of status_read_buffer %p:\n", | 835 | spin_unlock(&adapter->req_list_lock); |
1010 | status_buffer); | 836 | |
1011 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 837 | req->issued = get_clock(); |
1012 | (char *) status_buffer, | 838 | if (zfcp_qdio_send(req)) { |
1013 | sizeof (struct fsf_status_read_buffer)); | 839 | /* Queues are down..... */ |
1014 | break; | 840 | del_timer(&req->timer); |
1015 | } | 841 | spin_lock(&adapter->req_list_lock); |
1016 | mempool_free(status_buffer, adapter->pool.data_status_read); | 842 | zfcp_reqlist_remove(adapter, req); |
1017 | zfcp_fsf_req_free(fsf_req); | 843 | spin_unlock(&adapter->req_list_lock); |
1018 | /* | 844 | /* undo changes in request queue made for this request */ |
1019 | * recycle buffer and start new request repeat until outbound | 845 | atomic_add(req->sbal_number, &req_q->count); |
1020 | * queue is empty or adapter shutdown is requested | 846 | req_q->first -= req->sbal_number; |
1021 | */ | 847 | req_q->first += QDIO_MAX_BUFFERS_PER_Q; |
1022 | /* | 848 | req_q->first %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */ |
1023 | * FIXME(qdio): | 849 | zfcp_erp_adapter_reopen(adapter, 0, 116, req); |
1024 | * we may wait in the req_create for 5s during shutdown, so | 850 | return -EIO; |
1025 | * qdio_cleanup will have to wait at least that long before returning | ||
1026 | * with failure to allow us a proper cleanup under all circumstances | ||
1027 | */ | ||
1028 | /* | ||
1029 | * FIXME: | ||
1030 | * allocation failure possible? (Is this code needed?) | ||
1031 | */ | ||
1032 | retval = zfcp_fsf_status_read(adapter, 0); | ||
1033 | if (retval < 0) { | ||
1034 | ZFCP_LOG_INFO("Failed to create unsolicited status read " | ||
1035 | "request for the adapter %s.\n", | ||
1036 | zfcp_get_busid_by_adapter(adapter)); | ||
1037 | /* temporary fix to avoid status read buffer shortage */ | ||
1038 | adapter->status_read_failed++; | ||
1039 | if ((ZFCP_STATUS_READS_RECOM - adapter->status_read_failed) | ||
1040 | < ZFCP_STATUS_READ_FAILED_THRESHOLD) { | ||
1041 | ZFCP_LOG_INFO("restart adapter %s due to status read " | ||
1042 | "buffer shortage\n", | ||
1043 | zfcp_get_busid_by_adapter(adapter)); | ||
1044 | zfcp_erp_adapter_reopen(adapter, 0, 103, fsf_req); | ||
1045 | } | ||
1046 | } | 851 | } |
1047 | out: | 852 | |
1048 | return retval; | 853 | /* Don't increase for unsolicited status */ |
854 | if (req->qtcb) | ||
855 | adapter->fsf_req_seq_no++; | ||
856 | |||
857 | return 0; | ||
1049 | } | 858 | } |
1050 | 859 | ||
1051 | /* | 860 | /** |
1052 | * function: zfcp_fsf_abort_fcp_command | 861 | * zfcp_fsf_status_read - send status read request |
1053 | * | 862 | * @adapter: pointer to struct zfcp_adapter |
1054 | * purpose: tells FSF to abort a running SCSI command | 863 | * @req_flags: request flags |
1055 | * | 864 | * Returns: 0 on success, ERROR otherwise |
1056 | * returns: address of initiated FSF request | ||
1057 | * NULL - request could not be initiated | ||
1058 | * | ||
1059 | * FIXME(design): should be watched by a timeout !!! | ||
1060 | * FIXME(design) shouldn't this be modified to return an int | ||
1061 | * also...don't know how though | ||
1062 | */ | 865 | */ |
1063 | struct zfcp_fsf_req * | 866 | int zfcp_fsf_status_read(struct zfcp_adapter *adapter) |
1064 | zfcp_fsf_abort_fcp_command(unsigned long old_req_id, | ||
1065 | struct zfcp_adapter *adapter, | ||
1066 | struct zfcp_unit *unit, int req_flags) | ||
1067 | { | 867 | { |
868 | struct zfcp_fsf_req *req; | ||
869 | struct fsf_status_read_buffer *sr_buf; | ||
1068 | volatile struct qdio_buffer_element *sbale; | 870 | volatile struct qdio_buffer_element *sbale; |
1069 | struct zfcp_fsf_req *fsf_req = NULL; | 871 | int retval = -EIO; |
1070 | unsigned long lock_flags; | ||
1071 | int retval = 0; | ||
1072 | |||
1073 | /* setup new FSF request */ | ||
1074 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, | ||
1075 | req_flags, adapter->pool.fsf_req_abort, | ||
1076 | &lock_flags, &fsf_req); | ||
1077 | if (retval < 0) { | ||
1078 | ZFCP_LOG_INFO("error: Failed to create an abort command " | ||
1079 | "request for lun 0x%016Lx on port 0x%016Lx " | ||
1080 | "on adapter %s.\n", | ||
1081 | unit->fcp_lun, | ||
1082 | unit->port->wwpn, | ||
1083 | zfcp_get_busid_by_adapter(adapter)); | ||
1084 | goto out; | ||
1085 | } | ||
1086 | |||
1087 | if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
1088 | &unit->status))) | ||
1089 | goto unit_blocked; | ||
1090 | 872 | ||
1091 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 873 | spin_lock(&adapter->req_q.lock); |
1092 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 874 | if (zfcp_fsf_req_sbal_get(adapter)) |
1093 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 875 | goto out; |
1094 | 876 | ||
1095 | fsf_req->data = (unsigned long) unit; | 877 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS, |
878 | ZFCP_REQ_NO_QTCB, | ||
879 | adapter->pool.fsf_req_status_read); | ||
880 | if (unlikely(IS_ERR(req))) { | ||
881 | retval = PTR_ERR(req); | ||
882 | goto out; | ||
883 | } | ||
1096 | 884 | ||
1097 | /* set handles of unit and its parent port in QTCB */ | 885 | sbale = zfcp_qdio_sbale_req(req); |
1098 | fsf_req->qtcb->header.lun_handle = unit->handle; | 886 | sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS; |
1099 | fsf_req->qtcb->header.port_handle = unit->port->handle; | 887 | sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; |
888 | req->sbale_curr = 2; | ||
1100 | 889 | ||
1101 | /* set handle of request which should be aborted */ | 890 | sr_buf = mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC); |
1102 | fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id; | 891 | if (!sr_buf) { |
892 | retval = -ENOMEM; | ||
893 | goto failed_buf; | ||
894 | } | ||
895 | memset(sr_buf, 0, sizeof(*sr_buf)); | ||
896 | req->data = sr_buf; | ||
897 | sbale = zfcp_qdio_sbale_curr(req); | ||
898 | sbale->addr = (void *) sr_buf; | ||
899 | sbale->length = sizeof(*sr_buf); | ||
1103 | 900 | ||
1104 | zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT); | 901 | retval = zfcp_fsf_req_send(req); |
1105 | retval = zfcp_fsf_req_send(fsf_req); | 902 | if (retval) |
1106 | if (!retval) | 903 | goto failed_req_send; |
1107 | goto out; | ||
1108 | 904 | ||
1109 | unit_blocked: | 905 | goto out; |
1110 | zfcp_fsf_req_free(fsf_req); | ||
1111 | fsf_req = NULL; | ||
1112 | 906 | ||
1113 | out: | 907 | failed_req_send: |
1114 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 908 | mempool_free(sr_buf, adapter->pool.data_status_read); |
1115 | return fsf_req; | 909 | failed_buf: |
910 | zfcp_fsf_req_free(req); | ||
911 | zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL); | ||
912 | out: | ||
913 | spin_unlock(&adapter->req_q.lock); | ||
914 | return retval; | ||
1116 | } | 915 | } |
1117 | 916 | ||
1118 | /* | 917 | static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) |
1119 | * function: zfcp_fsf_abort_fcp_command_handler | ||
1120 | * | ||
1121 | * purpose: is called for finished Abort FCP Command request | ||
1122 | * | ||
1123 | * returns: | ||
1124 | */ | ||
1125 | static int | ||
1126 | zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) | ||
1127 | { | 918 | { |
1128 | int retval = -EINVAL; | 919 | struct zfcp_unit *unit = req->data; |
1129 | struct zfcp_unit *unit; | 920 | union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual; |
1130 | union fsf_status_qual *fsf_stat_qual = | ||
1131 | &new_fsf_req->qtcb->header.fsf_status_qual; | ||
1132 | |||
1133 | if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
1134 | /* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */ | ||
1135 | goto skip_fsfstatus; | ||
1136 | } | ||
1137 | |||
1138 | unit = (struct zfcp_unit *) new_fsf_req->data; | ||
1139 | 921 | ||
1140 | /* evaluate FSF status in QTCB */ | 922 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
1141 | switch (new_fsf_req->qtcb->header.fsf_status) { | 923 | return; |
1142 | 924 | ||
925 | switch (req->qtcb->header.fsf_status) { | ||
1143 | case FSF_PORT_HANDLE_NOT_VALID: | 926 | case FSF_PORT_HANDLE_NOT_VALID: |
1144 | if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) { | 927 | if (fsq->word[0] == fsq->word[1]) { |
1145 | /* | ||
1146 | * In this case a command that was sent prior to a port | ||
1147 | * reopen was aborted (handles are different). This is | ||
1148 | * fine. | ||
1149 | */ | ||
1150 | } else { | ||
1151 | ZFCP_LOG_INFO("Temporary port identifier 0x%x for " | ||
1152 | "port 0x%016Lx on adapter %s invalid. " | ||
1153 | "This may happen occasionally.\n", | ||
1154 | unit->port->handle, | ||
1155 | unit->port->wwpn, | ||
1156 | zfcp_get_busid_by_unit(unit)); | ||
1157 | ZFCP_LOG_INFO("status qualifier:\n"); | ||
1158 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, | ||
1159 | (char *) &new_fsf_req->qtcb->header. | ||
1160 | fsf_status_qual, | ||
1161 | sizeof (union fsf_status_qual)); | ||
1162 | /* Let's hope this sorts out the mess */ | ||
1163 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 104, | 928 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 104, |
1164 | new_fsf_req); | 929 | req); |
1165 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 930 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1166 | } | 931 | } |
1167 | break; | 932 | break; |
1168 | |||
1169 | case FSF_LUN_HANDLE_NOT_VALID: | 933 | case FSF_LUN_HANDLE_NOT_VALID: |
1170 | if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) { | 934 | if (fsq->word[0] == fsq->word[1]) { |
1171 | /* | 935 | zfcp_erp_port_reopen(unit->port, 0, 105, req); |
1172 | * In this case a command that was sent prior to a unit | 936 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1173 | * reopen was aborted (handles are different). | ||
1174 | * This is fine. | ||
1175 | */ | ||
1176 | } else { | ||
1177 | ZFCP_LOG_INFO | ||
1178 | ("Warning: Temporary LUN identifier 0x%x of LUN " | ||
1179 | "0x%016Lx on port 0x%016Lx on adapter %s is " | ||
1180 | "invalid. This may happen in rare cases. " | ||
1181 | "Trying to re-establish link.\n", | ||
1182 | unit->handle, | ||
1183 | unit->fcp_lun, | ||
1184 | unit->port->wwpn, | ||
1185 | zfcp_get_busid_by_unit(unit)); | ||
1186 | ZFCP_LOG_DEBUG("Status qualifier data:\n"); | ||
1187 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
1188 | (char *) &new_fsf_req->qtcb->header. | ||
1189 | fsf_status_qual, | ||
1190 | sizeof (union fsf_status_qual)); | ||
1191 | /* Let's hope this sorts out the mess */ | ||
1192 | zfcp_erp_port_reopen(unit->port, 0, 105, new_fsf_req); | ||
1193 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1194 | } | 937 | } |
1195 | break; | 938 | break; |
1196 | |||
1197 | case FSF_FCP_COMMAND_DOES_NOT_EXIST: | 939 | case FSF_FCP_COMMAND_DOES_NOT_EXIST: |
1198 | retval = 0; | 940 | req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED; |
1199 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED; | ||
1200 | break; | 941 | break; |
1201 | |||
1202 | case FSF_PORT_BOXED: | 942 | case FSF_PORT_BOXED: |
1203 | ZFCP_LOG_INFO("Remote port 0x%016Lx on adapter %s needs to " | 943 | zfcp_erp_port_boxed(unit->port, 47, req); |
1204 | "be reopened\n", unit->port->wwpn, | 944 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
1205 | zfcp_get_busid_by_unit(unit)); | 945 | ZFCP_STATUS_FSFREQ_RETRY; |
1206 | zfcp_erp_port_boxed(unit->port, 47, new_fsf_req); | ||
1207 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ||
1208 | | ZFCP_STATUS_FSFREQ_RETRY; | ||
1209 | break; | 946 | break; |
1210 | |||
1211 | case FSF_LUN_BOXED: | 947 | case FSF_LUN_BOXED: |
1212 | ZFCP_LOG_INFO( | 948 | zfcp_erp_unit_boxed(unit, 48, req); |
1213 | "unit 0x%016Lx on port 0x%016Lx on adapter %s needs " | 949 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
1214 | "to be reopened\n", | 950 | ZFCP_STATUS_FSFREQ_RETRY; |
1215 | unit->fcp_lun, unit->port->wwpn, | ||
1216 | zfcp_get_busid_by_unit(unit)); | ||
1217 | zfcp_erp_unit_boxed(unit, 48, new_fsf_req); | ||
1218 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ||
1219 | | ZFCP_STATUS_FSFREQ_RETRY; | ||
1220 | break; | 951 | break; |
1221 | |||
1222 | case FSF_ADAPTER_STATUS_AVAILABLE: | 952 | case FSF_ADAPTER_STATUS_AVAILABLE: |
1223 | switch (new_fsf_req->qtcb->header.fsf_status_qual.word[0]) { | 953 | switch (fsq->word[0]) { |
1224 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 954 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
1225 | zfcp_test_link(unit->port); | 955 | zfcp_test_link(unit->port); |
1226 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1227 | break; | ||
1228 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 956 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
1229 | /* SCSI stack will escalate */ | 957 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1230 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1231 | break; | ||
1232 | default: | ||
1233 | ZFCP_LOG_NORMAL | ||
1234 | ("bug: Wrong status qualifier 0x%x arrived.\n", | ||
1235 | new_fsf_req->qtcb->header.fsf_status_qual.word[0]); | ||
1236 | break; | 958 | break; |
1237 | } | 959 | } |
1238 | break; | 960 | break; |
1239 | |||
1240 | case FSF_GOOD: | 961 | case FSF_GOOD: |
1241 | retval = 0; | 962 | req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED; |
1242 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED; | ||
1243 | break; | ||
1244 | |||
1245 | default: | ||
1246 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
1247 | "(debug info 0x%x)\n", | ||
1248 | new_fsf_req->qtcb->header.fsf_status); | ||
1249 | break; | 963 | break; |
1250 | } | 964 | } |
1251 | skip_fsfstatus: | ||
1252 | return retval; | ||
1253 | } | 965 | } |
1254 | 966 | ||
1255 | /** | 967 | /** |
1256 | * zfcp_use_one_sbal - checks whether req buffer and resp bother each fit into | 968 | * zfcp_fsf_abort_fcp_command - abort running SCSI command |
1257 | * one SBALE | 969 | * @old_req_id: unsigned long |
1258 | * Two scatter-gather lists are passed, one for the reqeust and one for the | 970 | * @adapter: pointer to struct zfcp_adapter |
1259 | * response. | 971 | * @unit: pointer to struct zfcp_unit |
972 | * @req_flags: integer specifying the request flags | ||
973 | * Returns: pointer to struct zfcp_fsf_req | ||
974 | * | ||
975 | * FIXME(design): should be watched by a timeout !!! | ||
1260 | */ | 976 | */ |
1261 | static inline int | ||
1262 | zfcp_use_one_sbal(struct scatterlist *req, int req_count, | ||
1263 | struct scatterlist *resp, int resp_count) | ||
1264 | { | ||
1265 | return ((req_count == 1) && | ||
1266 | (resp_count == 1) && | ||
1267 | (((unsigned long) zfcp_sg_to_address(&req[0]) & | ||
1268 | PAGE_MASK) == | ||
1269 | ((unsigned long) (zfcp_sg_to_address(&req[0]) + | ||
1270 | req[0].length - 1) & PAGE_MASK)) && | ||
1271 | (((unsigned long) zfcp_sg_to_address(&resp[0]) & | ||
1272 | PAGE_MASK) == | ||
1273 | ((unsigned long) (zfcp_sg_to_address(&resp[0]) + | ||
1274 | resp[0].length - 1) & PAGE_MASK))); | ||
1275 | } | ||
1276 | 977 | ||
1277 | /** | 978 | struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, |
1278 | * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS) | 979 | struct zfcp_adapter *adapter, |
1279 | * @ct: pointer to struct zfcp_send_ct which conatins all needed data for | 980 | struct zfcp_unit *unit, |
1280 | * the request | 981 | int req_flags) |
1281 | * @pool: pointer to memory pool, if non-null this pool is used to allocate | ||
1282 | * a struct zfcp_fsf_req | ||
1283 | * @erp_action: pointer to erp_action, if non-null the Generic Service request | ||
1284 | * is sent within error recovery | ||
1285 | */ | ||
1286 | int | ||
1287 | zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, | ||
1288 | struct zfcp_erp_action *erp_action) | ||
1289 | { | 982 | { |
1290 | volatile struct qdio_buffer_element *sbale; | 983 | volatile struct qdio_buffer_element *sbale; |
1291 | struct zfcp_port *port; | 984 | struct zfcp_fsf_req *req = NULL; |
1292 | struct zfcp_adapter *adapter; | ||
1293 | struct zfcp_fsf_req *fsf_req; | ||
1294 | unsigned long lock_flags; | ||
1295 | int bytes; | ||
1296 | int ret = 0; | ||
1297 | |||
1298 | port = ct->port; | ||
1299 | adapter = port->adapter; | ||
1300 | |||
1301 | ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC, | ||
1302 | ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | ||
1303 | pool, &lock_flags, &fsf_req); | ||
1304 | if (ret < 0) { | ||
1305 | ZFCP_LOG_INFO("error: Could not create CT request (FC-GS) for " | ||
1306 | "adapter: %s\n", | ||
1307 | zfcp_get_busid_by_adapter(adapter)); | ||
1308 | goto failed_req; | ||
1309 | } | ||
1310 | 985 | ||
1311 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 986 | spin_lock(&adapter->req_q.lock); |
1312 | if (zfcp_use_one_sbal(ct->req, ct->req_count, | 987 | if (!atomic_read(&adapter->req_q.count)) |
1313 | ct->resp, ct->resp_count)){ | 988 | goto out; |
1314 | /* both request buffer and response buffer | 989 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, |
1315 | fit into one sbale each */ | 990 | req_flags, adapter->pool.fsf_req_abort); |
1316 | sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; | 991 | if (unlikely(IS_ERR(req))) |
1317 | sbale[2].addr = zfcp_sg_to_address(&ct->req[0]); | 992 | goto out; |
1318 | sbale[2].length = ct->req[0].length; | ||
1319 | sbale[3].addr = zfcp_sg_to_address(&ct->resp[0]); | ||
1320 | sbale[3].length = ct->resp[0].length; | ||
1321 | sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
1322 | } else if (adapter->adapter_features & | ||
1323 | FSF_FEATURE_ELS_CT_CHAINED_SBALS) { | ||
1324 | /* try to use chained SBALs */ | ||
1325 | bytes = zfcp_qdio_sbals_from_sg(fsf_req, | ||
1326 | SBAL_FLAGS0_TYPE_WRITE_READ, | ||
1327 | ct->req, ct->req_count, | ||
1328 | ZFCP_MAX_SBALS_PER_CT_REQ); | ||
1329 | if (bytes <= 0) { | ||
1330 | ZFCP_LOG_INFO("error: creation of CT request failed " | ||
1331 | "on adapter %s\n", | ||
1332 | zfcp_get_busid_by_adapter(adapter)); | ||
1333 | if (bytes == 0) | ||
1334 | ret = -ENOMEM; | ||
1335 | else | ||
1336 | ret = bytes; | ||
1337 | |||
1338 | goto failed_send; | ||
1339 | } | ||
1340 | fsf_req->qtcb->bottom.support.req_buf_length = bytes; | ||
1341 | fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; | ||
1342 | bytes = zfcp_qdio_sbals_from_sg(fsf_req, | ||
1343 | SBAL_FLAGS0_TYPE_WRITE_READ, | ||
1344 | ct->resp, ct->resp_count, | ||
1345 | ZFCP_MAX_SBALS_PER_CT_REQ); | ||
1346 | if (bytes <= 0) { | ||
1347 | ZFCP_LOG_INFO("error: creation of CT request failed " | ||
1348 | "on adapter %s\n", | ||
1349 | zfcp_get_busid_by_adapter(adapter)); | ||
1350 | if (bytes == 0) | ||
1351 | ret = -ENOMEM; | ||
1352 | else | ||
1353 | ret = bytes; | ||
1354 | |||
1355 | goto failed_send; | ||
1356 | } | ||
1357 | fsf_req->qtcb->bottom.support.resp_buf_length = bytes; | ||
1358 | } else { | ||
1359 | /* reject send generic request */ | ||
1360 | ZFCP_LOG_INFO( | ||
1361 | "error: microcode does not support chained SBALs," | ||
1362 | "CT request too big (adapter %s)\n", | ||
1363 | zfcp_get_busid_by_adapter(adapter)); | ||
1364 | ret = -EOPNOTSUPP; | ||
1365 | goto failed_send; | ||
1366 | } | ||
1367 | |||
1368 | /* settings in QTCB */ | ||
1369 | fsf_req->qtcb->header.port_handle = port->handle; | ||
1370 | fsf_req->qtcb->bottom.support.service_class = | ||
1371 | ZFCP_FC_SERVICE_CLASS_DEFAULT; | ||
1372 | fsf_req->qtcb->bottom.support.timeout = ct->timeout; | ||
1373 | fsf_req->data = (unsigned long) ct; | ||
1374 | |||
1375 | zfcp_san_dbf_event_ct_request(fsf_req); | ||
1376 | 993 | ||
1377 | if (erp_action) { | 994 | if (unlikely(!(atomic_read(&unit->status) & |
1378 | erp_action->fsf_req = fsf_req; | 995 | ZFCP_STATUS_COMMON_UNBLOCKED))) |
1379 | fsf_req->erp_action = erp_action; | 996 | goto out_error_free; |
1380 | zfcp_erp_start_timer(fsf_req); | ||
1381 | } else | ||
1382 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | ||
1383 | 997 | ||
1384 | ret = zfcp_fsf_req_send(fsf_req); | 998 | sbale = zfcp_qdio_sbale_req(req); |
1385 | if (ret) { | 999 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
1386 | ZFCP_LOG_DEBUG("error: initiation of CT request failed " | 1000 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
1387 | "(adapter %s, port 0x%016Lx)\n", | ||
1388 | zfcp_get_busid_by_adapter(adapter), port->wwpn); | ||
1389 | goto failed_send; | ||
1390 | } | ||
1391 | 1001 | ||
1392 | ZFCP_LOG_DEBUG("CT request initiated (adapter %s, port 0x%016Lx)\n", | 1002 | req->data = unit; |
1393 | zfcp_get_busid_by_adapter(adapter), port->wwpn); | 1003 | req->handler = zfcp_fsf_abort_fcp_command_handler; |
1394 | goto out; | 1004 | req->qtcb->header.lun_handle = unit->handle; |
1005 | req->qtcb->header.port_handle = unit->port->handle; | ||
1006 | req->qtcb->bottom.support.req_handle = (u64) old_req_id; | ||
1395 | 1007 | ||
1396 | failed_send: | 1008 | zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); |
1397 | zfcp_fsf_req_free(fsf_req); | 1009 | if (!zfcp_fsf_req_send(req)) |
1398 | if (erp_action != NULL) { | 1010 | goto out; |
1399 | erp_action->fsf_req = NULL; | 1011 | |
1400 | } | 1012 | out_error_free: |
1401 | failed_req: | 1013 | zfcp_fsf_req_free(req); |
1402 | out: | 1014 | req = NULL; |
1403 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 1015 | out: |
1404 | lock_flags); | 1016 | spin_unlock(&adapter->req_q.lock); |
1405 | return ret; | 1017 | return req; |
1406 | } | 1018 | } |
1407 | 1019 | ||
1408 | /** | 1020 | static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) |
1409 | * zfcp_fsf_send_ct_handler - handler for Generic Service requests | ||
1410 | * @fsf_req: pointer to struct zfcp_fsf_req | ||
1411 | * | ||
1412 | * Data specific for the Generic Service request is passed using | ||
1413 | * fsf_req->data. There we find the pointer to struct zfcp_send_ct. | ||
1414 | * Usually a specific handler for the CT request is called which is | ||
1415 | * found in this structure. | ||
1416 | */ | ||
1417 | static int | ||
1418 | zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) | ||
1419 | { | 1021 | { |
1420 | struct zfcp_port *port; | 1022 | struct zfcp_adapter *adapter = req->adapter; |
1421 | struct zfcp_adapter *adapter; | 1023 | struct zfcp_send_ct *send_ct = req->data; |
1422 | struct zfcp_send_ct *send_ct; | 1024 | struct zfcp_port *port = send_ct->port; |
1423 | struct fsf_qtcb_header *header; | 1025 | struct fsf_qtcb_header *header = &req->qtcb->header; |
1424 | struct fsf_qtcb_bottom_support *bottom; | ||
1425 | int retval = -EINVAL; | ||
1426 | u16 subtable, rule, counter; | ||
1427 | 1026 | ||
1428 | adapter = fsf_req->adapter; | 1027 | send_ct->status = -EINVAL; |
1429 | send_ct = (struct zfcp_send_ct *) fsf_req->data; | ||
1430 | port = send_ct->port; | ||
1431 | header = &fsf_req->qtcb->header; | ||
1432 | bottom = &fsf_req->qtcb->bottom.support; | ||
1433 | 1028 | ||
1434 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) | 1029 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
1435 | goto skip_fsfstatus; | 1030 | goto skip_fsfstatus; |
1436 | 1031 | ||
1437 | /* evaluate FSF status in QTCB */ | ||
1438 | switch (header->fsf_status) { | 1032 | switch (header->fsf_status) { |
1439 | |||
1440 | case FSF_GOOD: | 1033 | case FSF_GOOD: |
1441 | zfcp_san_dbf_event_ct_response(fsf_req); | 1034 | zfcp_san_dbf_event_ct_response(req); |
1442 | retval = 0; | 1035 | send_ct->status = 0; |
1443 | break; | 1036 | break; |
1444 | |||
1445 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: | 1037 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: |
1446 | ZFCP_LOG_INFO("error: adapter %s does not support fc " | 1038 | zfcp_fsf_class_not_supp(req); |
1447 | "class %d.\n", | ||
1448 | zfcp_get_busid_by_port(port), | ||
1449 | ZFCP_FC_SERVICE_CLASS_DEFAULT); | ||
1450 | /* stop operation for this adapter */ | ||
1451 | zfcp_erp_adapter_shutdown(adapter, 0, 123, fsf_req); | ||
1452 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1453 | break; | 1039 | break; |
1454 | |||
1455 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1040 | case FSF_ADAPTER_STATUS_AVAILABLE: |
1456 | switch (header->fsf_status_qual.word[0]){ | 1041 | switch (header->fsf_status_qual.word[0]){ |
1457 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 1042 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
1458 | /* reopening link to port */ | ||
1459 | zfcp_test_link(port); | 1043 | zfcp_test_link(port); |
1460 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1461 | break; | ||
1462 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 1044 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
1463 | /* ERP strategy will escalate */ | 1045 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1464 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1465 | break; | ||
1466 | default: | ||
1467 | ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x " | ||
1468 | "arrived.\n", | ||
1469 | header->fsf_status_qual.word[0]); | ||
1470 | break; | 1046 | break; |
1471 | } | 1047 | } |
1472 | break; | 1048 | break; |
1473 | |||
1474 | case FSF_ACCESS_DENIED: | 1049 | case FSF_ACCESS_DENIED: |
1475 | ZFCP_LOG_NORMAL("access denied, cannot send generic service " | 1050 | zfcp_fsf_access_denied_port(req, port); |
1476 | "command (adapter %s, port d_id=0x%06x)\n", | ||
1477 | zfcp_get_busid_by_port(port), port->d_id); | ||
1478 | for (counter = 0; counter < 2; counter++) { | ||
1479 | subtable = header->fsf_status_qual.halfword[counter * 2]; | ||
1480 | rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | ||
1481 | switch (subtable) { | ||
1482 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
1483 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
1484 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
1485 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
1486 | ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | ||
1487 | zfcp_act_subtable_type[subtable], rule); | ||
1488 | break; | ||
1489 | } | ||
1490 | } | ||
1491 | zfcp_erp_port_access_denied(port, 55, fsf_req); | ||
1492 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1493 | break; | ||
1494 | |||
1495 | case FSF_GENERIC_COMMAND_REJECTED: | ||
1496 | ZFCP_LOG_INFO("generic service command rejected " | ||
1497 | "(adapter %s, port d_id=0x%06x)\n", | ||
1498 | zfcp_get_busid_by_port(port), port->d_id); | ||
1499 | ZFCP_LOG_INFO("status qualifier:\n"); | ||
1500 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, | ||
1501 | (char *) &header->fsf_status_qual, | ||
1502 | sizeof (union fsf_status_qual)); | ||
1503 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1504 | break; | ||
1505 | |||
1506 | case FSF_PORT_HANDLE_NOT_VALID: | ||
1507 | ZFCP_LOG_DEBUG("Temporary port identifier 0x%x for port " | ||
1508 | "0x%016Lx on adapter %s invalid. This may " | ||
1509 | "happen occasionally.\n", port->handle, | ||
1510 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
1511 | ZFCP_LOG_INFO("status qualifier:\n"); | ||
1512 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, | ||
1513 | (char *) &header->fsf_status_qual, | ||
1514 | sizeof (union fsf_status_qual)); | ||
1515 | zfcp_erp_adapter_reopen(adapter, 0, 106, fsf_req); | ||
1516 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1517 | break; | 1051 | break; |
1518 | |||
1519 | case FSF_PORT_BOXED: | 1052 | case FSF_PORT_BOXED: |
1520 | ZFCP_LOG_INFO("port needs to be reopened " | 1053 | zfcp_erp_port_boxed(port, 49, req); |
1521 | "(adapter %s, port d_id=0x%06x)\n", | 1054 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
1522 | zfcp_get_busid_by_port(port), port->d_id); | 1055 | ZFCP_STATUS_FSFREQ_RETRY; |
1523 | zfcp_erp_port_boxed(port, 49, fsf_req); | ||
1524 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ||
1525 | | ZFCP_STATUS_FSFREQ_RETRY; | ||
1526 | break; | 1056 | break; |
1527 | 1057 | case FSF_PORT_HANDLE_NOT_VALID: | |
1528 | /* following states should never occure, all cases avoided | 1058 | zfcp_erp_adapter_reopen(adapter, 0, 106, req); |
1529 | in zfcp_fsf_send_ct - but who knows ... */ | 1059 | case FSF_GENERIC_COMMAND_REJECTED: |
1530 | case FSF_PAYLOAD_SIZE_MISMATCH: | 1060 | case FSF_PAYLOAD_SIZE_MISMATCH: |
1531 | ZFCP_LOG_INFO("payload size mismatch (adapter: %s, " | ||
1532 | "req_buf_length=%d, resp_buf_length=%d)\n", | ||
1533 | zfcp_get_busid_by_adapter(adapter), | ||
1534 | bottom->req_buf_length, bottom->resp_buf_length); | ||
1535 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1536 | break; | ||
1537 | case FSF_REQUEST_SIZE_TOO_LARGE: | 1061 | case FSF_REQUEST_SIZE_TOO_LARGE: |
1538 | ZFCP_LOG_INFO("request size too large (adapter: %s, " | ||
1539 | "req_buf_length=%d)\n", | ||
1540 | zfcp_get_busid_by_adapter(adapter), | ||
1541 | bottom->req_buf_length); | ||
1542 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1543 | break; | ||
1544 | case FSF_RESPONSE_SIZE_TOO_LARGE: | 1062 | case FSF_RESPONSE_SIZE_TOO_LARGE: |
1545 | ZFCP_LOG_INFO("response size too large (adapter: %s, " | ||
1546 | "resp_buf_length=%d)\n", | ||
1547 | zfcp_get_busid_by_adapter(adapter), | ||
1548 | bottom->resp_buf_length); | ||
1549 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1550 | break; | ||
1551 | case FSF_SBAL_MISMATCH: | 1063 | case FSF_SBAL_MISMATCH: |
1552 | ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, " | 1064 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1553 | "resp_buf_length=%d)\n", | ||
1554 | zfcp_get_busid_by_adapter(adapter), | ||
1555 | bottom->req_buf_length, bottom->resp_buf_length); | ||
1556 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1557 | break; | ||
1558 | |||
1559 | default: | ||
1560 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
1561 | "(debug info 0x%x)\n", header->fsf_status); | ||
1562 | break; | 1065 | break; |
1563 | } | 1066 | } |
1564 | 1067 | ||
1565 | skip_fsfstatus: | 1068 | skip_fsfstatus: |
1566 | send_ct->status = retval; | 1069 | if (send_ct->handler) |
1567 | |||
1568 | if (send_ct->handler != NULL) | ||
1569 | send_ct->handler(send_ct->handler_data); | 1070 | send_ct->handler(send_ct->handler_data); |
1071 | } | ||
1570 | 1072 | ||
1571 | return retval; | 1073 | static int zfcp_fsf_setup_sbals(struct zfcp_fsf_req *req, |
1074 | struct scatterlist *sg_req, | ||
1075 | struct scatterlist *sg_resp, int max_sbals) | ||
1076 | { | ||
1077 | int bytes; | ||
1078 | |||
1079 | bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ, | ||
1080 | sg_req, max_sbals); | ||
1081 | if (bytes <= 0) | ||
1082 | return -ENOMEM; | ||
1083 | req->qtcb->bottom.support.req_buf_length = bytes; | ||
1084 | req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; | ||
1085 | |||
1086 | bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ, | ||
1087 | sg_resp, max_sbals); | ||
1088 | if (bytes <= 0) | ||
1089 | return -ENOMEM; | ||
1090 | req->qtcb->bottom.support.resp_buf_length = bytes; | ||
1091 | |||
1092 | return 0; | ||
1572 | } | 1093 | } |
1573 | 1094 | ||
1574 | /** | 1095 | /** |
1575 | * zfcp_fsf_send_els - initiate an ELS command (FC-FS) | 1096 | * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS) |
1576 | * @els: pointer to struct zfcp_send_els which contains all needed data for | 1097 | * @ct: pointer to struct zfcp_send_ct with data for request |
1577 | * the command. | 1098 | * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req |
1099 | * @erp_action: if non-null the Generic Service request sent within ERP | ||
1578 | */ | 1100 | */ |
1579 | int | 1101 | int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, |
1580 | zfcp_fsf_send_els(struct zfcp_send_els *els) | 1102 | struct zfcp_erp_action *erp_action) |
1581 | { | 1103 | { |
1582 | volatile struct qdio_buffer_element *sbale; | 1104 | struct zfcp_port *port = ct->port; |
1583 | struct zfcp_fsf_req *fsf_req; | 1105 | struct zfcp_adapter *adapter = port->adapter; |
1584 | u32 d_id; | 1106 | struct zfcp_fsf_req *req; |
1585 | struct zfcp_adapter *adapter; | 1107 | int ret = -EIO; |
1586 | unsigned long lock_flags; | ||
1587 | int bytes; | ||
1588 | int ret = 0; | ||
1589 | |||
1590 | d_id = els->d_id; | ||
1591 | adapter = els->adapter; | ||
1592 | 1108 | ||
1593 | ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, | 1109 | spin_lock(&adapter->req_q.lock); |
1594 | ZFCP_REQ_AUTO_CLEANUP, | 1110 | if (zfcp_fsf_req_sbal_get(adapter)) |
1595 | NULL, &lock_flags, &fsf_req); | 1111 | goto out; |
1596 | if (ret < 0) { | ||
1597 | ZFCP_LOG_INFO("error: creation of ELS request failed " | ||
1598 | "(adapter %s, port d_id: 0x%06x)\n", | ||
1599 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1600 | goto failed_req; | ||
1601 | } | ||
1602 | 1112 | ||
1603 | if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | 1113 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC, |
1604 | &els->port->status))) { | 1114 | ZFCP_REQ_AUTO_CLEANUP, pool); |
1605 | ret = -EBUSY; | 1115 | if (unlikely(IS_ERR(req))) { |
1606 | goto port_blocked; | 1116 | ret = PTR_ERR(req); |
1117 | goto out; | ||
1607 | } | 1118 | } |
1608 | 1119 | ||
1609 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1120 | ret = zfcp_fsf_setup_sbals(req, ct->req, ct->resp, |
1610 | if (zfcp_use_one_sbal(els->req, els->req_count, | 1121 | FSF_MAX_SBALS_PER_REQ); |
1611 | els->resp, els->resp_count)){ | 1122 | if (ret) |
1612 | /* both request buffer and response buffer | ||
1613 | fit into one sbale each */ | ||
1614 | sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; | ||
1615 | sbale[2].addr = zfcp_sg_to_address(&els->req[0]); | ||
1616 | sbale[2].length = els->req[0].length; | ||
1617 | sbale[3].addr = zfcp_sg_to_address(&els->resp[0]); | ||
1618 | sbale[3].length = els->resp[0].length; | ||
1619 | sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
1620 | } else if (adapter->adapter_features & | ||
1621 | FSF_FEATURE_ELS_CT_CHAINED_SBALS) { | ||
1622 | /* try to use chained SBALs */ | ||
1623 | bytes = zfcp_qdio_sbals_from_sg(fsf_req, | ||
1624 | SBAL_FLAGS0_TYPE_WRITE_READ, | ||
1625 | els->req, els->req_count, | ||
1626 | ZFCP_MAX_SBALS_PER_ELS_REQ); | ||
1627 | if (bytes <= 0) { | ||
1628 | ZFCP_LOG_INFO("error: creation of ELS request failed " | ||
1629 | "(adapter %s, port d_id: 0x%06x)\n", | ||
1630 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1631 | if (bytes == 0) { | ||
1632 | ret = -ENOMEM; | ||
1633 | } else { | ||
1634 | ret = bytes; | ||
1635 | } | ||
1636 | goto failed_send; | ||
1637 | } | ||
1638 | fsf_req->qtcb->bottom.support.req_buf_length = bytes; | ||
1639 | fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; | ||
1640 | bytes = zfcp_qdio_sbals_from_sg(fsf_req, | ||
1641 | SBAL_FLAGS0_TYPE_WRITE_READ, | ||
1642 | els->resp, els->resp_count, | ||
1643 | ZFCP_MAX_SBALS_PER_ELS_REQ); | ||
1644 | if (bytes <= 0) { | ||
1645 | ZFCP_LOG_INFO("error: creation of ELS request failed " | ||
1646 | "(adapter %s, port d_id: 0x%06x)\n", | ||
1647 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1648 | if (bytes == 0) { | ||
1649 | ret = -ENOMEM; | ||
1650 | } else { | ||
1651 | ret = bytes; | ||
1652 | } | ||
1653 | goto failed_send; | ||
1654 | } | ||
1655 | fsf_req->qtcb->bottom.support.resp_buf_length = bytes; | ||
1656 | } else { | ||
1657 | /* reject request */ | ||
1658 | ZFCP_LOG_INFO("error: microcode does not support chained SBALs" | ||
1659 | ", ELS request too big (adapter %s, " | ||
1660 | "port d_id: 0x%06x)\n", | ||
1661 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1662 | ret = -EOPNOTSUPP; | ||
1663 | goto failed_send; | ||
1664 | } | ||
1665 | |||
1666 | /* settings in QTCB */ | ||
1667 | fsf_req->qtcb->bottom.support.d_id = d_id; | ||
1668 | fsf_req->qtcb->bottom.support.service_class = | ||
1669 | ZFCP_FC_SERVICE_CLASS_DEFAULT; | ||
1670 | fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT; | ||
1671 | fsf_req->data = (unsigned long) els; | ||
1672 | |||
1673 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | ||
1674 | |||
1675 | zfcp_san_dbf_event_els_request(fsf_req); | ||
1676 | |||
1677 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | ||
1678 | ret = zfcp_fsf_req_send(fsf_req); | ||
1679 | if (ret) { | ||
1680 | ZFCP_LOG_DEBUG("error: initiation of ELS request failed " | ||
1681 | "(adapter %s, port d_id: 0x%06x)\n", | ||
1682 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1683 | goto failed_send; | 1123 | goto failed_send; |
1684 | } | ||
1685 | 1124 | ||
1686 | ZFCP_LOG_DEBUG("ELS request initiated (adapter %s, port d_id: " | 1125 | req->handler = zfcp_fsf_send_ct_handler; |
1687 | "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); | 1126 | req->qtcb->header.port_handle = port->handle; |
1688 | goto out; | 1127 | req->qtcb->bottom.support.service_class = FSF_CLASS_3; |
1128 | req->qtcb->bottom.support.timeout = ct->timeout; | ||
1129 | req->data = ct; | ||
1689 | 1130 | ||
1690 | port_blocked: | 1131 | zfcp_san_dbf_event_ct_request(req); |
1691 | failed_send: | ||
1692 | zfcp_fsf_req_free(fsf_req); | ||
1693 | 1132 | ||
1694 | failed_req: | 1133 | if (erp_action) { |
1695 | out: | 1134 | erp_action->fsf_req = req; |
1696 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 1135 | req->erp_action = erp_action; |
1697 | lock_flags); | 1136 | zfcp_fsf_start_erp_timer(req); |
1137 | } else | ||
1138 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); | ||
1139 | |||
1140 | ret = zfcp_fsf_req_send(req); | ||
1141 | if (ret) | ||
1142 | goto failed_send; | ||
1143 | |||
1144 | goto out; | ||
1698 | 1145 | ||
1699 | return ret; | 1146 | failed_send: |
1147 | zfcp_fsf_req_free(req); | ||
1148 | if (erp_action) | ||
1149 | erp_action->fsf_req = NULL; | ||
1150 | out: | ||
1151 | spin_unlock(&adapter->req_q.lock); | ||
1152 | return ret; | ||
1700 | } | 1153 | } |
1701 | 1154 | ||
1702 | /** | 1155 | static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) |
1703 | * zfcp_fsf_send_els_handler - handler for ELS commands | ||
1704 | * @fsf_req: pointer to struct zfcp_fsf_req | ||
1705 | * | ||
1706 | * Data specific for the ELS command is passed using | ||
1707 | * fsf_req->data. There we find the pointer to struct zfcp_send_els. | ||
1708 | * Usually a specific handler for the ELS command is called which is | ||
1709 | * found in this structure. | ||
1710 | */ | ||
1711 | static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) | ||
1712 | { | 1156 | { |
1713 | struct zfcp_adapter *adapter; | 1157 | struct zfcp_send_els *send_els = req->data; |
1714 | struct zfcp_port *port; | 1158 | struct zfcp_port *port = send_els->port; |
1715 | u32 d_id; | 1159 | struct fsf_qtcb_header *header = &req->qtcb->header; |
1716 | struct fsf_qtcb_header *header; | 1160 | |
1717 | struct fsf_qtcb_bottom_support *bottom; | 1161 | send_els->status = -EINVAL; |
1718 | struct zfcp_send_els *send_els; | 1162 | |
1719 | int retval = -EINVAL; | 1163 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
1720 | u16 subtable, rule, counter; | ||
1721 | |||
1722 | send_els = (struct zfcp_send_els *) fsf_req->data; | ||
1723 | adapter = send_els->adapter; | ||
1724 | port = send_els->port; | ||
1725 | d_id = send_els->d_id; | ||
1726 | header = &fsf_req->qtcb->header; | ||
1727 | bottom = &fsf_req->qtcb->bottom.support; | ||
1728 | |||
1729 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) | ||
1730 | goto skip_fsfstatus; | 1164 | goto skip_fsfstatus; |
1731 | 1165 | ||
1732 | switch (header->fsf_status) { | 1166 | switch (header->fsf_status) { |
1733 | |||
1734 | case FSF_GOOD: | 1167 | case FSF_GOOD: |
1735 | zfcp_san_dbf_event_els_response(fsf_req); | 1168 | zfcp_san_dbf_event_els_response(req); |
1736 | retval = 0; | 1169 | send_els->status = 0; |
1737 | break; | 1170 | break; |
1738 | |||
1739 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: | 1171 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: |
1740 | ZFCP_LOG_INFO("error: adapter %s does not support fc " | 1172 | zfcp_fsf_class_not_supp(req); |
1741 | "class %d.\n", | ||
1742 | zfcp_get_busid_by_adapter(adapter), | ||
1743 | ZFCP_FC_SERVICE_CLASS_DEFAULT); | ||
1744 | /* stop operation for this adapter */ | ||
1745 | zfcp_erp_adapter_shutdown(adapter, 0, 124, fsf_req); | ||
1746 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1747 | break; | 1173 | break; |
1748 | |||
1749 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1174 | case FSF_ADAPTER_STATUS_AVAILABLE: |
1750 | switch (header->fsf_status_qual.word[0]){ | 1175 | switch (header->fsf_status_qual.word[0]){ |
1751 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 1176 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
1752 | if (port && (send_els->ls_code != ZFCP_LS_ADISC)) | 1177 | if (port && (send_els->ls_code != ZFCP_LS_ADISC)) |
1753 | zfcp_test_link(port); | 1178 | zfcp_test_link(port); |
1754 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1179 | /*fall through */ |
1755 | break; | ||
1756 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 1180 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
1757 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1758 | retval = | ||
1759 | zfcp_handle_els_rjt(header->fsf_status_qual.word[1], | ||
1760 | (struct zfcp_ls_rjt_par *) | ||
1761 | &header->fsf_status_qual.word[2]); | ||
1762 | break; | ||
1763 | case FSF_SQ_RETRY_IF_POSSIBLE: | 1181 | case FSF_SQ_RETRY_IF_POSSIBLE: |
1764 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1182 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1765 | break; | 1183 | break; |
1766 | default: | ||
1767 | ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x\n", | ||
1768 | header->fsf_status_qual.word[0]); | ||
1769 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, | ||
1770 | (char*)header->fsf_status_qual.word, 16); | ||
1771 | } | 1184 | } |
1772 | break; | 1185 | break; |
1773 | |||
1774 | case FSF_ELS_COMMAND_REJECTED: | 1186 | case FSF_ELS_COMMAND_REJECTED: |
1775 | ZFCP_LOG_INFO("ELS has been rejected because command filter " | ||
1776 | "prohibited sending " | ||
1777 | "(adapter: %s, port d_id: 0x%06x)\n", | ||
1778 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1779 | |||
1780 | break; | ||
1781 | |||
1782 | case FSF_PAYLOAD_SIZE_MISMATCH: | 1187 | case FSF_PAYLOAD_SIZE_MISMATCH: |
1783 | ZFCP_LOG_INFO( | ||
1784 | "ELS request size and ELS response size must be either " | ||
1785 | "both 0, or both greater than 0 " | ||
1786 | "(adapter: %s, req_buf_length=%d resp_buf_length=%d)\n", | ||
1787 | zfcp_get_busid_by_adapter(adapter), | ||
1788 | bottom->req_buf_length, | ||
1789 | bottom->resp_buf_length); | ||
1790 | break; | ||
1791 | |||
1792 | case FSF_REQUEST_SIZE_TOO_LARGE: | 1188 | case FSF_REQUEST_SIZE_TOO_LARGE: |
1793 | ZFCP_LOG_INFO( | ||
1794 | "Length of the ELS request buffer, " | ||
1795 | "specified in QTCB bottom, " | ||
1796 | "exceeds the size of the buffers " | ||
1797 | "that have been allocated for ELS request data " | ||
1798 | "(adapter: %s, req_buf_length=%d)\n", | ||
1799 | zfcp_get_busid_by_adapter(adapter), | ||
1800 | bottom->req_buf_length); | ||
1801 | break; | ||
1802 | |||
1803 | case FSF_RESPONSE_SIZE_TOO_LARGE: | 1189 | case FSF_RESPONSE_SIZE_TOO_LARGE: |
1804 | ZFCP_LOG_INFO( | ||
1805 | "Length of the ELS response buffer, " | ||
1806 | "specified in QTCB bottom, " | ||
1807 | "exceeds the size of the buffers " | ||
1808 | "that have been allocated for ELS response data " | ||
1809 | "(adapter: %s, resp_buf_length=%d)\n", | ||
1810 | zfcp_get_busid_by_adapter(adapter), | ||
1811 | bottom->resp_buf_length); | ||
1812 | break; | ||
1813 | |||
1814 | case FSF_SBAL_MISMATCH: | ||
1815 | /* should never occure, avoided in zfcp_fsf_send_els */ | ||
1816 | ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, " | ||
1817 | "resp_buf_length=%d)\n", | ||
1818 | zfcp_get_busid_by_adapter(adapter), | ||
1819 | bottom->req_buf_length, bottom->resp_buf_length); | ||
1820 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1821 | break; | 1190 | break; |
1822 | |||
1823 | case FSF_ACCESS_DENIED: | 1191 | case FSF_ACCESS_DENIED: |
1824 | ZFCP_LOG_NORMAL("access denied, cannot send ELS command " | 1192 | zfcp_fsf_access_denied_port(req, port); |
1825 | "(adapter %s, port d_id=0x%06x)\n", | ||
1826 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1827 | for (counter = 0; counter < 2; counter++) { | ||
1828 | subtable = header->fsf_status_qual.halfword[counter * 2]; | ||
1829 | rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | ||
1830 | switch (subtable) { | ||
1831 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
1832 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
1833 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
1834 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
1835 | ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | ||
1836 | zfcp_act_subtable_type[subtable], rule); | ||
1837 | break; | ||
1838 | } | ||
1839 | } | ||
1840 | if (port != NULL) | ||
1841 | zfcp_erp_port_access_denied(port, 56, fsf_req); | ||
1842 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1843 | break; | 1193 | break; |
1844 | 1194 | case FSF_SBAL_MISMATCH: | |
1195 | /* should never occure, avoided in zfcp_fsf_send_els */ | ||
1196 | /* fall through */ | ||
1845 | default: | 1197 | default: |
1846 | ZFCP_LOG_NORMAL( | 1198 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1847 | "bug: An unknown FSF Status was presented " | ||
1848 | "(adapter: %s, fsf_status=0x%08x)\n", | ||
1849 | zfcp_get_busid_by_adapter(adapter), | ||
1850 | header->fsf_status); | ||
1851 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1852 | break; | 1199 | break; |
1853 | } | 1200 | } |
1854 | |||
1855 | skip_fsfstatus: | 1201 | skip_fsfstatus: |
1856 | send_els->status = retval; | ||
1857 | |||
1858 | if (send_els->handler) | 1202 | if (send_els->handler) |
1859 | send_els->handler(send_els->handler_data); | 1203 | send_els->handler(send_els->handler_data); |
1204 | } | ||
1860 | 1205 | ||
1861 | return retval; | 1206 | /** |
1207 | * zfcp_fsf_send_els - initiate an ELS command (FC-FS) | ||
1208 | * @els: pointer to struct zfcp_send_els with data for the command | ||
1209 | */ | ||
1210 | int zfcp_fsf_send_els(struct zfcp_send_els *els) | ||
1211 | { | ||
1212 | struct zfcp_fsf_req *req; | ||
1213 | struct zfcp_adapter *adapter = els->adapter; | ||
1214 | struct fsf_qtcb_bottom_support *bottom; | ||
1215 | int ret = -EIO; | ||
1216 | |||
1217 | if (unlikely(!(atomic_read(&els->port->status) & | ||
1218 | ZFCP_STATUS_COMMON_UNBLOCKED))) | ||
1219 | return -EBUSY; | ||
1220 | |||
1221 | spin_lock(&adapter->req_q.lock); | ||
1222 | if (!atomic_read(&adapter->req_q.count)) | ||
1223 | goto out; | ||
1224 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, | ||
1225 | ZFCP_REQ_AUTO_CLEANUP, NULL); | ||
1226 | if (unlikely(IS_ERR(req))) { | ||
1227 | ret = PTR_ERR(req); | ||
1228 | goto out; | ||
1229 | } | ||
1230 | |||
1231 | ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, | ||
1232 | FSF_MAX_SBALS_PER_ELS_REQ); | ||
1233 | if (ret) | ||
1234 | goto failed_send; | ||
1235 | |||
1236 | bottom = &req->qtcb->bottom.support; | ||
1237 | req->handler = zfcp_fsf_send_els_handler; | ||
1238 | bottom->d_id = els->d_id; | ||
1239 | bottom->service_class = FSF_CLASS_3; | ||
1240 | bottom->timeout = 2 * R_A_TOV; | ||
1241 | req->data = els; | ||
1242 | |||
1243 | zfcp_san_dbf_event_els_request(req); | ||
1244 | |||
1245 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); | ||
1246 | ret = zfcp_fsf_req_send(req); | ||
1247 | if (ret) | ||
1248 | goto failed_send; | ||
1249 | |||
1250 | goto out; | ||
1251 | |||
1252 | failed_send: | ||
1253 | zfcp_fsf_req_free(req); | ||
1254 | out: | ||
1255 | spin_unlock(&adapter->req_q.lock); | ||
1256 | return ret; | ||
1862 | } | 1257 | } |
1863 | 1258 | ||
1864 | int | 1259 | int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) |
1865 | zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) | ||
1866 | { | 1260 | { |
1867 | volatile struct qdio_buffer_element *sbale; | 1261 | volatile struct qdio_buffer_element *sbale; |
1868 | struct zfcp_fsf_req *fsf_req; | 1262 | struct zfcp_fsf_req *req; |
1869 | struct zfcp_adapter *adapter = erp_action->adapter; | 1263 | struct zfcp_adapter *adapter = erp_action->adapter; |
1870 | unsigned long lock_flags; | 1264 | int retval = -EIO; |
1871 | int retval; | 1265 | |
1872 | 1266 | spin_lock(&adapter->req_q.lock); | |
1873 | /* setup new FSF request */ | 1267 | if (!atomic_read(&adapter->req_q.count)) |
1874 | retval = zfcp_fsf_req_create(adapter, | 1268 | goto out; |
1875 | FSF_QTCB_EXCHANGE_CONFIG_DATA, | 1269 | req = zfcp_fsf_req_create(adapter, |
1876 | ZFCP_REQ_AUTO_CLEANUP, | 1270 | FSF_QTCB_EXCHANGE_CONFIG_DATA, |
1877 | adapter->pool.fsf_req_erp, | 1271 | ZFCP_REQ_AUTO_CLEANUP, |
1878 | &lock_flags, &fsf_req); | 1272 | adapter->pool.fsf_req_erp); |
1879 | if (retval) { | 1273 | if (unlikely(IS_ERR(req))) { |
1880 | ZFCP_LOG_INFO("error: Could not create exchange configuration " | 1274 | retval = PTR_ERR(req); |
1881 | "data request for adapter %s.\n", | 1275 | goto out; |
1882 | zfcp_get_busid_by_adapter(adapter)); | ||
1883 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | ||
1884 | lock_flags); | ||
1885 | return retval; | ||
1886 | } | 1276 | } |
1887 | 1277 | ||
1888 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1278 | sbale = zfcp_qdio_sbale_req(req); |
1889 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1279 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
1890 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1280 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
1891 | 1281 | ||
1892 | fsf_req->qtcb->bottom.config.feature_selection = | 1282 | req->qtcb->bottom.config.feature_selection = |
1893 | FSF_FEATURE_CFDC | | 1283 | FSF_FEATURE_CFDC | |
1894 | FSF_FEATURE_LUN_SHARING | | 1284 | FSF_FEATURE_LUN_SHARING | |
1895 | FSF_FEATURE_NOTIFICATION_LOST | | 1285 | FSF_FEATURE_NOTIFICATION_LOST | |
1896 | FSF_FEATURE_UPDATE_ALERT; | 1286 | FSF_FEATURE_UPDATE_ALERT; |
1897 | fsf_req->erp_action = erp_action; | 1287 | req->erp_action = erp_action; |
1898 | erp_action->fsf_req = fsf_req; | 1288 | req->handler = zfcp_fsf_exchange_config_data_handler; |
1289 | erp_action->fsf_req = req; | ||
1899 | 1290 | ||
1900 | zfcp_erp_start_timer(fsf_req); | 1291 | zfcp_fsf_start_erp_timer(req); |
1901 | retval = zfcp_fsf_req_send(fsf_req); | 1292 | retval = zfcp_fsf_req_send(req); |
1902 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | ||
1903 | lock_flags); | ||
1904 | if (retval) { | 1293 | if (retval) { |
1905 | ZFCP_LOG_INFO("error: Could not send exchange configuration " | 1294 | zfcp_fsf_req_free(req); |
1906 | "data command on the adapter %s\n", | ||
1907 | zfcp_get_busid_by_adapter(adapter)); | ||
1908 | zfcp_fsf_req_free(fsf_req); | ||
1909 | erp_action->fsf_req = NULL; | 1295 | erp_action->fsf_req = NULL; |
1910 | } | 1296 | } |
1911 | else | 1297 | out: |
1912 | ZFCP_LOG_DEBUG("exchange configuration data request initiated " | 1298 | spin_unlock(&adapter->req_q.lock); |
1913 | "(adapter %s)\n", | ||
1914 | zfcp_get_busid_by_adapter(adapter)); | ||
1915 | |||
1916 | return retval; | 1299 | return retval; |
1917 | } | 1300 | } |
1918 | 1301 | ||
1919 | int | 1302 | int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, |
1920 | zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, | 1303 | struct fsf_qtcb_bottom_config *data) |
1921 | struct fsf_qtcb_bottom_config *data) | ||
1922 | { | 1304 | { |
1923 | volatile struct qdio_buffer_element *sbale; | 1305 | volatile struct qdio_buffer_element *sbale; |
1924 | struct zfcp_fsf_req *fsf_req; | 1306 | struct zfcp_fsf_req *req = NULL; |
1925 | unsigned long lock_flags; | 1307 | int retval = -EIO; |
1926 | int retval; | 1308 | |
1927 | 1309 | spin_lock(&adapter->req_q.lock); | |
1928 | /* setup new FSF request */ | 1310 | if (zfcp_fsf_req_sbal_get(adapter)) |
1929 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, | 1311 | goto out; |
1930 | ZFCP_WAIT_FOR_SBAL, NULL, &lock_flags, | 1312 | |
1931 | &fsf_req); | 1313 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, |
1932 | if (retval) { | 1314 | 0, NULL); |
1933 | ZFCP_LOG_INFO("error: Could not create exchange configuration " | 1315 | if (unlikely(IS_ERR(req))) { |
1934 | "data request for adapter %s.\n", | 1316 | retval = PTR_ERR(req); |
1935 | zfcp_get_busid_by_adapter(adapter)); | 1317 | goto out; |
1936 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | ||
1937 | lock_flags); | ||
1938 | return retval; | ||
1939 | } | 1318 | } |
1940 | 1319 | ||
1941 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1320 | sbale = zfcp_qdio_sbale_req(req); |
1942 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1321 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
1943 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1322 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
1323 | req->handler = zfcp_fsf_exchange_config_data_handler; | ||
1944 | 1324 | ||
1945 | fsf_req->qtcb->bottom.config.feature_selection = | 1325 | req->qtcb->bottom.config.feature_selection = |
1946 | FSF_FEATURE_CFDC | | 1326 | FSF_FEATURE_CFDC | |
1947 | FSF_FEATURE_LUN_SHARING | | 1327 | FSF_FEATURE_LUN_SHARING | |
1948 | FSF_FEATURE_NOTIFICATION_LOST | | 1328 | FSF_FEATURE_NOTIFICATION_LOST | |
1949 | FSF_FEATURE_UPDATE_ALERT; | 1329 | FSF_FEATURE_UPDATE_ALERT; |
1950 | 1330 | ||
1951 | if (data) | 1331 | if (data) |
1952 | fsf_req->data = (unsigned long) data; | 1332 | req->data = data; |
1953 | 1333 | ||
1954 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | 1334 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); |
1955 | retval = zfcp_fsf_req_send(fsf_req); | 1335 | retval = zfcp_fsf_req_send(req); |
1956 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 1336 | out: |
1957 | lock_flags); | 1337 | spin_unlock(&adapter->req_q.lock); |
1958 | if (retval) | 1338 | if (!retval) |
1959 | ZFCP_LOG_INFO("error: Could not send exchange configuration " | 1339 | wait_event(req->completion_wq, |
1960 | "data command on the adapter %s\n", | 1340 | req->status & ZFCP_STATUS_FSFREQ_COMPLETED); |
1961 | zfcp_get_busid_by_adapter(adapter)); | ||
1962 | else | ||
1963 | wait_event(fsf_req->completion_wq, | ||
1964 | fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | ||
1965 | 1341 | ||
1966 | zfcp_fsf_req_free(fsf_req); | 1342 | zfcp_fsf_req_free(req); |
1967 | 1343 | ||
1968 | return retval; | 1344 | return retval; |
1969 | } | 1345 | } |
1970 | 1346 | ||
1971 | /** | 1347 | /** |
1972 | * zfcp_fsf_exchange_config_evaluate | ||
1973 | * @fsf_req: fsf_req which belongs to xchg config data request | ||
1974 | * @xchg_ok: specifies if xchg config data was incomplete or complete (0/1) | ||
1975 | * | ||
1976 | * returns: -EIO on error, 0 otherwise | ||
1977 | */ | ||
1978 | static int | ||
1979 | zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) | ||
1980 | { | ||
1981 | struct fsf_qtcb_bottom_config *bottom; | ||
1982 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
1983 | struct Scsi_Host *shost = adapter->scsi_host; | ||
1984 | |||
1985 | bottom = &fsf_req->qtcb->bottom.config; | ||
1986 | ZFCP_LOG_DEBUG("low/high QTCB version 0x%x/0x%x of FSF\n", | ||
1987 | bottom->low_qtcb_version, bottom->high_qtcb_version); | ||
1988 | adapter->fsf_lic_version = bottom->lic_version; | ||
1989 | adapter->adapter_features = bottom->adapter_features; | ||
1990 | adapter->connection_features = bottom->connection_features; | ||
1991 | adapter->peer_wwpn = 0; | ||
1992 | adapter->peer_wwnn = 0; | ||
1993 | adapter->peer_d_id = 0; | ||
1994 | |||
1995 | if (xchg_ok) { | ||
1996 | |||
1997 | if (fsf_req->data) | ||
1998 | memcpy((struct fsf_qtcb_bottom_config *) fsf_req->data, | ||
1999 | bottom, sizeof (struct fsf_qtcb_bottom_config)); | ||
2000 | |||
2001 | fc_host_node_name(shost) = bottom->nport_serv_param.wwnn; | ||
2002 | fc_host_port_name(shost) = bottom->nport_serv_param.wwpn; | ||
2003 | fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK; | ||
2004 | fc_host_speed(shost) = bottom->fc_link_speed; | ||
2005 | fc_host_supported_classes(shost) = | ||
2006 | FC_COS_CLASS2 | FC_COS_CLASS3; | ||
2007 | adapter->hydra_version = bottom->adapter_type; | ||
2008 | if (fc_host_permanent_port_name(shost) == -1) | ||
2009 | fc_host_permanent_port_name(shost) = | ||
2010 | fc_host_port_name(shost); | ||
2011 | if (bottom->fc_topology == FSF_TOPO_P2P) { | ||
2012 | adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK; | ||
2013 | adapter->peer_wwpn = bottom->plogi_payload.wwpn; | ||
2014 | adapter->peer_wwnn = bottom->plogi_payload.wwnn; | ||
2015 | fc_host_port_type(shost) = FC_PORTTYPE_PTP; | ||
2016 | } else if (bottom->fc_topology == FSF_TOPO_FABRIC) | ||
2017 | fc_host_port_type(shost) = FC_PORTTYPE_NPORT; | ||
2018 | else if (bottom->fc_topology == FSF_TOPO_AL) | ||
2019 | fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; | ||
2020 | else | ||
2021 | fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; | ||
2022 | } else { | ||
2023 | fc_host_node_name(shost) = 0; | ||
2024 | fc_host_port_name(shost) = 0; | ||
2025 | fc_host_port_id(shost) = 0; | ||
2026 | fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; | ||
2027 | fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; | ||
2028 | adapter->hydra_version = 0; | ||
2029 | } | ||
2030 | |||
2031 | if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) { | ||
2032 | adapter->hardware_version = bottom->hardware_version; | ||
2033 | memcpy(fc_host_serial_number(shost), bottom->serial_number, | ||
2034 | min(FC_SERIAL_NUMBER_SIZE, 17)); | ||
2035 | EBCASC(fc_host_serial_number(shost), | ||
2036 | min(FC_SERIAL_NUMBER_SIZE, 17)); | ||
2037 | } | ||
2038 | |||
2039 | if (fsf_req->erp_action) | ||
2040 | ZFCP_LOG_NORMAL("The adapter %s reported the following " | ||
2041 | "characteristics:\n" | ||
2042 | "WWNN 0x%016Lx, WWPN 0x%016Lx, " | ||
2043 | "S_ID 0x%06x,\n" | ||
2044 | "adapter version 0x%x, " | ||
2045 | "LIC version 0x%x, " | ||
2046 | "FC link speed %d Gb/s\n", | ||
2047 | zfcp_get_busid_by_adapter(adapter), | ||
2048 | (wwn_t) fc_host_node_name(shost), | ||
2049 | (wwn_t) fc_host_port_name(shost), | ||
2050 | fc_host_port_id(shost), | ||
2051 | adapter->hydra_version, | ||
2052 | adapter->fsf_lic_version, | ||
2053 | fc_host_speed(shost)); | ||
2054 | if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) { | ||
2055 | ZFCP_LOG_NORMAL("error: the adapter %s " | ||
2056 | "only supports newer control block " | ||
2057 | "versions in comparison to this device " | ||
2058 | "driver (try updated device driver)\n", | ||
2059 | zfcp_get_busid_by_adapter(adapter)); | ||
2060 | zfcp_erp_adapter_shutdown(adapter, 0, 125, fsf_req); | ||
2061 | return -EIO; | ||
2062 | } | ||
2063 | if (ZFCP_QTCB_VERSION > bottom->high_qtcb_version) { | ||
2064 | ZFCP_LOG_NORMAL("error: the adapter %s " | ||
2065 | "only supports older control block " | ||
2066 | "versions than this device driver uses" | ||
2067 | "(consider a microcode upgrade)\n", | ||
2068 | zfcp_get_busid_by_adapter(adapter)); | ||
2069 | zfcp_erp_adapter_shutdown(adapter, 0, 126, fsf_req); | ||
2070 | return -EIO; | ||
2071 | } | ||
2072 | return 0; | ||
2073 | } | ||
2074 | |||
2075 | /** | ||
2076 | * function: zfcp_fsf_exchange_config_data_handler | ||
2077 | * | ||
2078 | * purpose: is called for finished Exchange Configuration Data command | ||
2079 | * | ||
2080 | * returns: | ||
2081 | */ | ||
2082 | static int | ||
2083 | zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) | ||
2084 | { | ||
2085 | struct fsf_qtcb_bottom_config *bottom; | ||
2086 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
2087 | struct fsf_qtcb *qtcb = fsf_req->qtcb; | ||
2088 | |||
2089 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) | ||
2090 | return -EIO; | ||
2091 | |||
2092 | switch (qtcb->header.fsf_status) { | ||
2093 | |||
2094 | case FSF_GOOD: | ||
2095 | if (zfcp_fsf_exchange_config_evaluate(fsf_req, 1)) | ||
2096 | return -EIO; | ||
2097 | |||
2098 | switch (fc_host_port_type(adapter->scsi_host)) { | ||
2099 | case FC_PORTTYPE_PTP: | ||
2100 | ZFCP_LOG_NORMAL("Point-to-Point fibrechannel " | ||
2101 | "configuration detected at adapter %s\n" | ||
2102 | "Peer WWNN 0x%016llx, " | ||
2103 | "peer WWPN 0x%016llx, " | ||
2104 | "peer d_id 0x%06x\n", | ||
2105 | zfcp_get_busid_by_adapter(adapter), | ||
2106 | adapter->peer_wwnn, | ||
2107 | adapter->peer_wwpn, | ||
2108 | adapter->peer_d_id); | ||
2109 | break; | ||
2110 | case FC_PORTTYPE_NLPORT: | ||
2111 | ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel " | ||
2112 | "topology detected at adapter %s " | ||
2113 | "unsupported, shutting down adapter\n", | ||
2114 | zfcp_get_busid_by_adapter(adapter)); | ||
2115 | zfcp_erp_adapter_shutdown(adapter, 0, 127, fsf_req); | ||
2116 | return -EIO; | ||
2117 | case FC_PORTTYPE_NPORT: | ||
2118 | if (fsf_req->erp_action) | ||
2119 | ZFCP_LOG_NORMAL("Switched fabric fibrechannel " | ||
2120 | "network detected at adapter " | ||
2121 | "%s.\n", | ||
2122 | zfcp_get_busid_by_adapter(adapter)); | ||
2123 | break; | ||
2124 | default: | ||
2125 | ZFCP_LOG_NORMAL("bug: The fibrechannel topology " | ||
2126 | "reported by the exchange " | ||
2127 | "configuration command for " | ||
2128 | "the adapter %s is not " | ||
2129 | "of a type known to the zfcp " | ||
2130 | "driver, shutting down adapter\n", | ||
2131 | zfcp_get_busid_by_adapter(adapter)); | ||
2132 | zfcp_erp_adapter_shutdown(adapter, 0, 128, fsf_req); | ||
2133 | return -EIO; | ||
2134 | } | ||
2135 | bottom = &qtcb->bottom.config; | ||
2136 | if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) { | ||
2137 | ZFCP_LOG_NORMAL("bug: Maximum QTCB size (%d bytes) " | ||
2138 | "allowed by the adapter %s " | ||
2139 | "is lower than the minimum " | ||
2140 | "required by the driver (%ld bytes).\n", | ||
2141 | bottom->max_qtcb_size, | ||
2142 | zfcp_get_busid_by_adapter(adapter), | ||
2143 | sizeof(struct fsf_qtcb)); | ||
2144 | zfcp_erp_adapter_shutdown(adapter, 0, 129, fsf_req); | ||
2145 | return -EIO; | ||
2146 | } | ||
2147 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | ||
2148 | &adapter->status); | ||
2149 | break; | ||
2150 | case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: | ||
2151 | if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0)) | ||
2152 | return -EIO; | ||
2153 | |||
2154 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | ||
2155 | &adapter->status); | ||
2156 | |||
2157 | zfcp_fsf_link_down_info_eval(fsf_req, 42, | ||
2158 | &qtcb->header.fsf_status_qual.link_down_info); | ||
2159 | break; | ||
2160 | default: | ||
2161 | zfcp_erp_adapter_shutdown(adapter, 0, 130, fsf_req); | ||
2162 | return -EIO; | ||
2163 | } | ||
2164 | return 0; | ||
2165 | } | ||
2166 | |||
2167 | /** | ||
2168 | * zfcp_fsf_exchange_port_data - request information about local port | 1348 | * zfcp_fsf_exchange_port_data - request information about local port |
2169 | * @erp_action: ERP action for the adapter for which port data is requested | 1349 | * @erp_action: ERP action for the adapter for which port data is requested |
1350 | * Returns: 0 on success, error otherwise | ||
2170 | */ | 1351 | */ |
2171 | int | 1352 | int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) |
2172 | zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) | ||
2173 | { | 1353 | { |
2174 | volatile struct qdio_buffer_element *sbale; | 1354 | volatile struct qdio_buffer_element *sbale; |
2175 | struct zfcp_fsf_req *fsf_req; | 1355 | struct zfcp_fsf_req *req; |
2176 | struct zfcp_adapter *adapter = erp_action->adapter; | 1356 | struct zfcp_adapter *adapter = erp_action->adapter; |
2177 | unsigned long lock_flags; | 1357 | int retval = -EIO; |
2178 | int retval; | ||
2179 | 1358 | ||
2180 | if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) { | 1359 | if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) |
2181 | ZFCP_LOG_INFO("error: exchange port data " | ||
2182 | "command not supported by adapter %s\n", | ||
2183 | zfcp_get_busid_by_adapter(adapter)); | ||
2184 | return -EOPNOTSUPP; | 1360 | return -EOPNOTSUPP; |
2185 | } | ||
2186 | 1361 | ||
2187 | /* setup new FSF request */ | 1362 | spin_lock(&adapter->req_q.lock); |
2188 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, | 1363 | if (!atomic_read(&adapter->req_q.count)) |
2189 | ZFCP_REQ_AUTO_CLEANUP, | 1364 | goto out; |
2190 | adapter->pool.fsf_req_erp, | 1365 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, |
2191 | &lock_flags, &fsf_req); | 1366 | ZFCP_REQ_AUTO_CLEANUP, |
2192 | if (retval) { | 1367 | adapter->pool.fsf_req_erp); |
2193 | ZFCP_LOG_INFO("error: Out of resources. Could not create an " | 1368 | if (unlikely(IS_ERR(req))) { |
2194 | "exchange port data request for " | 1369 | retval = PTR_ERR(req); |
2195 | "the adapter %s.\n", | 1370 | goto out; |
2196 | zfcp_get_busid_by_adapter(adapter)); | ||
2197 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | ||
2198 | lock_flags); | ||
2199 | return retval; | ||
2200 | } | 1371 | } |
2201 | 1372 | ||
2202 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1373 | sbale = zfcp_qdio_sbale_req(req); |
2203 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1374 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
2204 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1375 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
2205 | 1376 | ||
2206 | erp_action->fsf_req = fsf_req; | 1377 | req->handler = zfcp_fsf_exchange_port_data_handler; |
2207 | fsf_req->erp_action = erp_action; | 1378 | req->erp_action = erp_action; |
2208 | zfcp_erp_start_timer(fsf_req); | 1379 | erp_action->fsf_req = req; |
2209 | |||
2210 | retval = zfcp_fsf_req_send(fsf_req); | ||
2211 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | ||
2212 | 1380 | ||
1381 | zfcp_fsf_start_erp_timer(req); | ||
1382 | retval = zfcp_fsf_req_send(req); | ||
2213 | if (retval) { | 1383 | if (retval) { |
2214 | ZFCP_LOG_INFO("error: Could not send an exchange port data " | 1384 | zfcp_fsf_req_free(req); |
2215 | "command on the adapter %s\n", | ||
2216 | zfcp_get_busid_by_adapter(adapter)); | ||
2217 | zfcp_fsf_req_free(fsf_req); | ||
2218 | erp_action->fsf_req = NULL; | 1385 | erp_action->fsf_req = NULL; |
2219 | } | 1386 | } |
2220 | else | 1387 | out: |
2221 | ZFCP_LOG_DEBUG("exchange port data request initiated " | 1388 | spin_unlock(&adapter->req_q.lock); |
2222 | "(adapter %s)\n", | ||
2223 | zfcp_get_busid_by_adapter(adapter)); | ||
2224 | return retval; | 1389 | return retval; |
2225 | } | 1390 | } |
2226 | 1391 | ||
2227 | |||
2228 | /** | 1392 | /** |
2229 | * zfcp_fsf_exchange_port_data_sync - request information about local port | 1393 | * zfcp_fsf_exchange_port_data_sync - request information about local port |
2230 | * and wait until information is ready | 1394 | * @adapter: pointer to struct zfcp_adapter |
1395 | * @data: pointer to struct fsf_qtcb_bottom_port | ||
1396 | * Returns: 0 on success, error otherwise | ||
2231 | */ | 1397 | */ |
2232 | int | 1398 | int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, |
2233 | zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, | 1399 | struct fsf_qtcb_bottom_port *data) |
2234 | struct fsf_qtcb_bottom_port *data) | ||
2235 | { | 1400 | { |
2236 | volatile struct qdio_buffer_element *sbale; | 1401 | volatile struct qdio_buffer_element *sbale; |
2237 | struct zfcp_fsf_req *fsf_req; | 1402 | struct zfcp_fsf_req *req = NULL; |
2238 | unsigned long lock_flags; | 1403 | int retval = -EIO; |
2239 | int retval; | 1404 | |
2240 | 1405 | if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) | |
2241 | if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) { | ||
2242 | ZFCP_LOG_INFO("error: exchange port data " | ||
2243 | "command not supported by adapter %s\n", | ||
2244 | zfcp_get_busid_by_adapter(adapter)); | ||
2245 | return -EOPNOTSUPP; | 1406 | return -EOPNOTSUPP; |
2246 | } | ||
2247 | 1407 | ||
2248 | /* setup new FSF request */ | 1408 | spin_lock(&adapter->req_q.lock); |
2249 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, | 1409 | if (!atomic_read(&adapter->req_q.count)) |
2250 | 0, NULL, &lock_flags, &fsf_req); | 1410 | goto out; |
2251 | if (retval) { | 1411 | |
2252 | ZFCP_LOG_INFO("error: Out of resources. Could not create an " | 1412 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0, |
2253 | "exchange port data request for " | 1413 | NULL); |
2254 | "the adapter %s.\n", | 1414 | if (unlikely(IS_ERR(req))) { |
2255 | zfcp_get_busid_by_adapter(adapter)); | 1415 | retval = PTR_ERR(req); |
2256 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 1416 | goto out; |
2257 | lock_flags); | ||
2258 | return retval; | ||
2259 | } | 1417 | } |
2260 | 1418 | ||
2261 | if (data) | 1419 | if (data) |
2262 | fsf_req->data = (unsigned long) data; | 1420 | req->data = data; |
2263 | 1421 | ||
2264 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1422 | sbale = zfcp_qdio_sbale_req(req); |
2265 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1423 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
2266 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1424 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
2267 | 1425 | ||
2268 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | 1426 | req->handler = zfcp_fsf_exchange_port_data_handler; |
2269 | retval = zfcp_fsf_req_send(fsf_req); | 1427 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); |
2270 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 1428 | retval = zfcp_fsf_req_send(req); |
2271 | 1429 | out: | |
2272 | if (retval) | 1430 | spin_unlock(&adapter->req_q.lock); |
2273 | ZFCP_LOG_INFO("error: Could not send an exchange port data " | 1431 | if (!retval) |
2274 | "command on the adapter %s\n", | 1432 | wait_event(req->completion_wq, |
2275 | zfcp_get_busid_by_adapter(adapter)); | 1433 | req->status & ZFCP_STATUS_FSFREQ_COMPLETED); |
2276 | else | 1434 | zfcp_fsf_req_free(req); |
2277 | wait_event(fsf_req->completion_wq, | ||
2278 | fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | ||
2279 | |||
2280 | zfcp_fsf_req_free(fsf_req); | ||
2281 | |||
2282 | return retval; | ||
2283 | } | ||
2284 | |||
2285 | /** | ||
2286 | * zfcp_fsf_exchange_port_evaluate | ||
2287 | * @fsf_req: fsf_req which belongs to xchg port data request | ||
2288 | * @xchg_ok: specifies if xchg port data was incomplete or complete (0/1) | ||
2289 | */ | ||
2290 | static void | ||
2291 | zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) | ||
2292 | { | ||
2293 | struct zfcp_adapter *adapter; | ||
2294 | struct fsf_qtcb_bottom_port *bottom; | ||
2295 | struct Scsi_Host *shost; | ||
2296 | |||
2297 | adapter = fsf_req->adapter; | ||
2298 | bottom = &fsf_req->qtcb->bottom.port; | ||
2299 | shost = adapter->scsi_host; | ||
2300 | |||
2301 | if (fsf_req->data) | ||
2302 | memcpy((struct fsf_qtcb_bottom_port*) fsf_req->data, bottom, | ||
2303 | sizeof(struct fsf_qtcb_bottom_port)); | ||
2304 | |||
2305 | if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) | ||
2306 | fc_host_permanent_port_name(shost) = bottom->wwpn; | ||
2307 | else | ||
2308 | fc_host_permanent_port_name(shost) = fc_host_port_name(shost); | ||
2309 | fc_host_maxframe_size(shost) = bottom->maximum_frame_size; | ||
2310 | fc_host_supported_speeds(shost) = bottom->supported_speed; | ||
2311 | } | ||
2312 | |||
2313 | /** | ||
2314 | * zfcp_fsf_exchange_port_data_handler - handler for exchange_port_data request | ||
2315 | * @fsf_req: pointer to struct zfcp_fsf_req | ||
2316 | */ | ||
2317 | static void | ||
2318 | zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req) | ||
2319 | { | ||
2320 | struct zfcp_adapter *adapter; | ||
2321 | struct fsf_qtcb *qtcb; | ||
2322 | |||
2323 | adapter = fsf_req->adapter; | ||
2324 | qtcb = fsf_req->qtcb; | ||
2325 | |||
2326 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) | ||
2327 | return; | ||
2328 | |||
2329 | switch (qtcb->header.fsf_status) { | ||
2330 | case FSF_GOOD: | ||
2331 | zfcp_fsf_exchange_port_evaluate(fsf_req, 1); | ||
2332 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); | ||
2333 | break; | ||
2334 | case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: | ||
2335 | zfcp_fsf_exchange_port_evaluate(fsf_req, 0); | ||
2336 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); | ||
2337 | zfcp_fsf_link_down_info_eval(fsf_req, 43, | ||
2338 | &qtcb->header.fsf_status_qual.link_down_info); | ||
2339 | break; | ||
2340 | } | ||
2341 | } | ||
2342 | |||
2343 | |||
2344 | /* | ||
2345 | * function: zfcp_fsf_open_port | ||
2346 | * | ||
2347 | * purpose: | ||
2348 | * | ||
2349 | * returns: address of initiated FSF request | ||
2350 | * NULL - request could not be initiated | ||
2351 | */ | ||
2352 | int | ||
2353 | zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) | ||
2354 | { | ||
2355 | volatile struct qdio_buffer_element *sbale; | ||
2356 | struct zfcp_fsf_req *fsf_req; | ||
2357 | unsigned long lock_flags; | ||
2358 | int retval = 0; | ||
2359 | |||
2360 | /* setup new FSF request */ | ||
2361 | retval = zfcp_fsf_req_create(erp_action->adapter, | ||
2362 | FSF_QTCB_OPEN_PORT_WITH_DID, | ||
2363 | ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | ||
2364 | erp_action->adapter->pool.fsf_req_erp, | ||
2365 | &lock_flags, &fsf_req); | ||
2366 | if (retval < 0) { | ||
2367 | ZFCP_LOG_INFO("error: Could not create open port request " | ||
2368 | "for port 0x%016Lx on adapter %s.\n", | ||
2369 | erp_action->port->wwpn, | ||
2370 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
2371 | goto out; | ||
2372 | } | ||
2373 | |||
2374 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | ||
2375 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | ||
2376 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
2377 | |||
2378 | fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id; | ||
2379 | atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status); | ||
2380 | fsf_req->data = (unsigned long) erp_action->port; | ||
2381 | fsf_req->erp_action = erp_action; | ||
2382 | erp_action->fsf_req = fsf_req; | ||
2383 | |||
2384 | zfcp_erp_start_timer(fsf_req); | ||
2385 | retval = zfcp_fsf_req_send(fsf_req); | ||
2386 | if (retval) { | ||
2387 | ZFCP_LOG_INFO("error: Could not send open port request for " | ||
2388 | "port 0x%016Lx on adapter %s.\n", | ||
2389 | erp_action->port->wwpn, | ||
2390 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
2391 | zfcp_fsf_req_free(fsf_req); | ||
2392 | erp_action->fsf_req = NULL; | ||
2393 | goto out; | ||
2394 | } | ||
2395 | 1435 | ||
2396 | ZFCP_LOG_DEBUG("open port request initiated " | ||
2397 | "(adapter %s, port 0x%016Lx)\n", | ||
2398 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2399 | erp_action->port->wwpn); | ||
2400 | out: | ||
2401 | write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | ||
2402 | lock_flags); | ||
2403 | return retval; | 1436 | return retval; |
2404 | } | 1437 | } |
2405 | 1438 | ||
2406 | /* | 1439 | static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) |
2407 | * function: zfcp_fsf_open_port_handler | ||
2408 | * | ||
2409 | * purpose: is called for finished Open Port command | ||
2410 | * | ||
2411 | * returns: | ||
2412 | */ | ||
2413 | static int | ||
2414 | zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) | ||
2415 | { | 1440 | { |
2416 | int retval = -EINVAL; | 1441 | struct zfcp_port *port = req->data; |
2417 | struct zfcp_port *port; | 1442 | struct fsf_qtcb_header *header = &req->qtcb->header; |
2418 | struct fsf_plogi *plogi; | 1443 | struct fsf_plogi *plogi; |
2419 | struct fsf_qtcb_header *header; | ||
2420 | u16 subtable, rule, counter; | ||
2421 | 1444 | ||
2422 | port = (struct zfcp_port *) fsf_req->data; | 1445 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
2423 | header = &fsf_req->qtcb->header; | ||
2424 | |||
2425 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
2426 | /* don't change port status in our bookkeeping */ | ||
2427 | goto skip_fsfstatus; | 1446 | goto skip_fsfstatus; |
2428 | } | ||
2429 | 1447 | ||
2430 | /* evaluate FSF status in QTCB */ | ||
2431 | switch (header->fsf_status) { | 1448 | switch (header->fsf_status) { |
2432 | |||
2433 | case FSF_PORT_ALREADY_OPEN: | 1449 | case FSF_PORT_ALREADY_OPEN: |
2434 | ZFCP_LOG_NORMAL("bug: remote port 0x%016Lx on adapter %s " | ||
2435 | "is already open.\n", | ||
2436 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
2437 | /* | ||
2438 | * This is a bug, however operation should continue normally | ||
2439 | * if it is simply ignored | ||
2440 | */ | ||
2441 | break; | 1450 | break; |
2442 | |||
2443 | case FSF_ACCESS_DENIED: | 1451 | case FSF_ACCESS_DENIED: |
2444 | ZFCP_LOG_NORMAL("Access denied, cannot open port 0x%016Lx " | 1452 | zfcp_fsf_access_denied_port(req, port); |
2445 | "on adapter %s\n", | ||
2446 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
2447 | for (counter = 0; counter < 2; counter++) { | ||
2448 | subtable = header->fsf_status_qual.halfword[counter * 2]; | ||
2449 | rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | ||
2450 | switch (subtable) { | ||
2451 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
2452 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
2453 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
2454 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
2455 | ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | ||
2456 | zfcp_act_subtable_type[subtable], rule); | ||
2457 | break; | ||
2458 | } | ||
2459 | } | ||
2460 | zfcp_erp_port_access_denied(port, 57, fsf_req); | ||
2461 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2462 | break; | 1453 | break; |
2463 | |||
2464 | case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: | 1454 | case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: |
2465 | ZFCP_LOG_INFO("error: The FSF adapter is out of resources. " | 1455 | dev_warn(&req->adapter->ccw_device->dev, |
2466 | "The remote port 0x%016Lx on adapter %s " | 1456 | "The adapter is out of resources. The remote port " |
2467 | "could not be opened. Disabling it.\n", | 1457 | "0x%016Lx could not be opened, disabling it.\n", |
2468 | port->wwpn, zfcp_get_busid_by_port(port)); | 1458 | port->wwpn); |
2469 | zfcp_erp_port_failed(port, 31, fsf_req); | 1459 | zfcp_erp_port_failed(port, 31, req); |
2470 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1460 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2471 | break; | 1461 | break; |
2472 | |||
2473 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1462 | case FSF_ADAPTER_STATUS_AVAILABLE: |
2474 | switch (header->fsf_status_qual.word[0]) { | 1463 | switch (header->fsf_status_qual.word[0]) { |
2475 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 1464 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
2476 | /* ERP strategy will escalate */ | ||
2477 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2478 | break; | ||
2479 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 1465 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
2480 | /* ERP strategy will escalate */ | 1466 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2481 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2482 | break; | 1467 | break; |
2483 | case FSF_SQ_NO_RETRY_POSSIBLE: | 1468 | case FSF_SQ_NO_RETRY_POSSIBLE: |
2484 | ZFCP_LOG_NORMAL("The remote port 0x%016Lx on " | 1469 | dev_warn(&req->adapter->ccw_device->dev, |
2485 | "adapter %s could not be opened. " | 1470 | "The remote port 0x%016Lx could not be " |
2486 | "Disabling it.\n", | 1471 | "opened. Disabling it.\n", port->wwpn); |
2487 | port->wwpn, | 1472 | zfcp_erp_port_failed(port, 32, req); |
2488 | zfcp_get_busid_by_port(port)); | 1473 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2489 | zfcp_erp_port_failed(port, 32, fsf_req); | ||
2490 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2491 | break; | ||
2492 | default: | ||
2493 | ZFCP_LOG_NORMAL | ||
2494 | ("bug: Wrong status qualifier 0x%x arrived.\n", | ||
2495 | header->fsf_status_qual.word[0]); | ||
2496 | break; | 1474 | break; |
2497 | } | 1475 | } |
2498 | break; | 1476 | break; |
2499 | |||
2500 | case FSF_GOOD: | 1477 | case FSF_GOOD: |
2501 | /* save port handle assigned by FSF */ | ||
2502 | port->handle = header->port_handle; | 1478 | port->handle = header->port_handle; |
2503 | ZFCP_LOG_INFO("The remote port 0x%016Lx via adapter %s " | ||
2504 | "was opened, it's port handle is 0x%x\n", | ||
2505 | port->wwpn, zfcp_get_busid_by_port(port), | ||
2506 | port->handle); | ||
2507 | /* mark port as open */ | ||
2508 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN | | 1479 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN | |
2509 | ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); | 1480 | ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); |
2510 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | | 1481 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | |
2511 | ZFCP_STATUS_COMMON_ACCESS_BOXED, | 1482 | ZFCP_STATUS_COMMON_ACCESS_BOXED, |
2512 | &port->status); | 1483 | &port->status); |
2513 | retval = 0; | ||
2514 | /* check whether D_ID has changed during open */ | 1484 | /* check whether D_ID has changed during open */ |
2515 | /* | 1485 | /* |
2516 | * FIXME: This check is not airtight, as the FCP channel does | 1486 | * FIXME: This check is not airtight, as the FCP channel does |
@@ -2526,320 +1496,168 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) | |||
2526 | * another GID_PN straight after a port has been opened. | 1496 | * another GID_PN straight after a port has been opened. |
2527 | * Alternately, an ADISC/PDISC ELS should suffice, as well. | 1497 | * Alternately, an ADISC/PDISC ELS should suffice, as well. |
2528 | */ | 1498 | */ |
2529 | plogi = (struct fsf_plogi *) fsf_req->qtcb->bottom.support.els; | 1499 | if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN) |
2530 | if (!atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, &port->status)) | 1500 | break; |
2531 | { | 1501 | |
2532 | if (fsf_req->qtcb->bottom.support.els1_length < | 1502 | plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els; |
2533 | sizeof (struct fsf_plogi)) { | 1503 | if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) { |
2534 | ZFCP_LOG_INFO( | 1504 | if (plogi->serv_param.wwpn != port->wwpn) |
2535 | "warning: insufficient length of " | 1505 | atomic_clear_mask(ZFCP_STATUS_PORT_DID_DID, |
2536 | "PLOGI payload (%i)\n", | 1506 | &port->status); |
2537 | fsf_req->qtcb->bottom.support.els1_length); | 1507 | else { |
2538 | /* skip sanity check and assume wwpn is ok */ | 1508 | port->wwnn = plogi->serv_param.wwnn; |
2539 | } else { | 1509 | zfcp_fc_plogi_evaluate(port, plogi); |
2540 | if (plogi->serv_param.wwpn != port->wwpn) { | ||
2541 | ZFCP_LOG_INFO("warning: d_id of port " | ||
2542 | "0x%016Lx changed during " | ||
2543 | "open\n", port->wwpn); | ||
2544 | atomic_clear_mask( | ||
2545 | ZFCP_STATUS_PORT_DID_DID, | ||
2546 | &port->status); | ||
2547 | } else { | ||
2548 | port->wwnn = plogi->serv_param.wwnn; | ||
2549 | zfcp_plogi_evaluate(port, plogi); | ||
2550 | } | ||
2551 | } | 1510 | } |
2552 | } | 1511 | } |
2553 | break; | 1512 | break; |
2554 | |||
2555 | case FSF_UNKNOWN_OP_SUBTYPE: | 1513 | case FSF_UNKNOWN_OP_SUBTYPE: |
2556 | /* should never occure, subtype not set in zfcp_fsf_open_port */ | 1514 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2557 | ZFCP_LOG_INFO("unknown operation subtype (adapter: %s, " | ||
2558 | "op_subtype=0x%x)\n", | ||
2559 | zfcp_get_busid_by_port(port), | ||
2560 | fsf_req->qtcb->bottom.support.operation_subtype); | ||
2561 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2562 | break; | ||
2563 | |||
2564 | default: | ||
2565 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
2566 | "(debug info 0x%x)\n", | ||
2567 | header->fsf_status); | ||
2568 | break; | 1515 | break; |
2569 | } | 1516 | } |
2570 | 1517 | ||
2571 | skip_fsfstatus: | 1518 | skip_fsfstatus: |
2572 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status); | 1519 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status); |
2573 | return retval; | ||
2574 | } | 1520 | } |
2575 | 1521 | ||
2576 | /* | 1522 | /** |
2577 | * function: zfcp_fsf_close_port | 1523 | * zfcp_fsf_open_port - create and send open port request |
2578 | * | 1524 | * @erp_action: pointer to struct zfcp_erp_action |
2579 | * purpose: submit FSF command "close port" | 1525 | * Returns: 0 on success, error otherwise |
2580 | * | ||
2581 | * returns: address of initiated FSF request | ||
2582 | * NULL - request could not be initiated | ||
2583 | */ | 1526 | */ |
2584 | int | 1527 | int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) |
2585 | zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) | ||
2586 | { | 1528 | { |
2587 | volatile struct qdio_buffer_element *sbale; | 1529 | volatile struct qdio_buffer_element *sbale; |
2588 | struct zfcp_fsf_req *fsf_req; | 1530 | struct zfcp_adapter *adapter = erp_action->adapter; |
2589 | unsigned long lock_flags; | 1531 | struct zfcp_fsf_req *req; |
2590 | int retval = 0; | 1532 | int retval = -EIO; |
2591 | 1533 | ||
2592 | /* setup new FSF request */ | 1534 | spin_lock(&adapter->req_q.lock); |
2593 | retval = zfcp_fsf_req_create(erp_action->adapter, | 1535 | if (zfcp_fsf_req_sbal_get(adapter)) |
2594 | FSF_QTCB_CLOSE_PORT, | 1536 | goto out; |
2595 | ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | 1537 | |
2596 | erp_action->adapter->pool.fsf_req_erp, | 1538 | req = zfcp_fsf_req_create(adapter, |
2597 | &lock_flags, &fsf_req); | 1539 | FSF_QTCB_OPEN_PORT_WITH_DID, |
2598 | if (retval < 0) { | 1540 | ZFCP_REQ_AUTO_CLEANUP, |
2599 | ZFCP_LOG_INFO("error: Could not create a close port request " | 1541 | adapter->pool.fsf_req_erp); |
2600 | "for port 0x%016Lx on adapter %s.\n", | 1542 | if (unlikely(IS_ERR(req))) { |
2601 | erp_action->port->wwpn, | 1543 | retval = PTR_ERR(req); |
2602 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
2603 | goto out; | 1544 | goto out; |
2604 | } | 1545 | } |
2605 | 1546 | ||
2606 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1547 | sbale = zfcp_qdio_sbale_req(req); |
2607 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1548 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
2608 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1549 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
2609 | 1550 | ||
2610 | atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status); | 1551 | req->handler = zfcp_fsf_open_port_handler; |
2611 | fsf_req->data = (unsigned long) erp_action->port; | 1552 | req->qtcb->bottom.support.d_id = erp_action->port->d_id; |
2612 | fsf_req->erp_action = erp_action; | 1553 | req->data = erp_action->port; |
2613 | fsf_req->qtcb->header.port_handle = erp_action->port->handle; | 1554 | req->erp_action = erp_action; |
2614 | fsf_req->erp_action = erp_action; | 1555 | erp_action->fsf_req = req; |
2615 | erp_action->fsf_req = fsf_req; | 1556 | atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status); |
2616 | 1557 | ||
2617 | zfcp_erp_start_timer(fsf_req); | 1558 | zfcp_fsf_start_erp_timer(req); |
2618 | retval = zfcp_fsf_req_send(fsf_req); | 1559 | retval = zfcp_fsf_req_send(req); |
2619 | if (retval) { | 1560 | if (retval) { |
2620 | ZFCP_LOG_INFO("error: Could not send a close port request for " | 1561 | zfcp_fsf_req_free(req); |
2621 | "port 0x%016Lx on adapter %s.\n", | ||
2622 | erp_action->port->wwpn, | ||
2623 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
2624 | zfcp_fsf_req_free(fsf_req); | ||
2625 | erp_action->fsf_req = NULL; | 1562 | erp_action->fsf_req = NULL; |
2626 | goto out; | ||
2627 | } | 1563 | } |
2628 | 1564 | out: | |
2629 | ZFCP_LOG_TRACE("close port request initiated " | 1565 | spin_unlock(&adapter->req_q.lock); |
2630 | "(adapter %s, port 0x%016Lx)\n", | ||
2631 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2632 | erp_action->port->wwpn); | ||
2633 | out: | ||
2634 | write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | ||
2635 | lock_flags); | ||
2636 | return retval; | 1566 | return retval; |
2637 | } | 1567 | } |
2638 | 1568 | ||
2639 | /* | 1569 | static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req) |
2640 | * function: zfcp_fsf_close_port_handler | ||
2641 | * | ||
2642 | * purpose: is called for finished Close Port FSF command | ||
2643 | * | ||
2644 | * returns: | ||
2645 | */ | ||
2646 | static int | ||
2647 | zfcp_fsf_close_port_handler(struct zfcp_fsf_req *fsf_req) | ||
2648 | { | 1570 | { |
2649 | int retval = -EINVAL; | 1571 | struct zfcp_port *port = req->data; |
2650 | struct zfcp_port *port; | ||
2651 | 1572 | ||
2652 | port = (struct zfcp_port *) fsf_req->data; | 1573 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
2653 | |||
2654 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
2655 | /* don't change port status in our bookkeeping */ | ||
2656 | goto skip_fsfstatus; | 1574 | goto skip_fsfstatus; |
2657 | } | ||
2658 | |||
2659 | /* evaluate FSF status in QTCB */ | ||
2660 | switch (fsf_req->qtcb->header.fsf_status) { | ||
2661 | 1575 | ||
1576 | switch (req->qtcb->header.fsf_status) { | ||
2662 | case FSF_PORT_HANDLE_NOT_VALID: | 1577 | case FSF_PORT_HANDLE_NOT_VALID: |
2663 | ZFCP_LOG_INFO("Temporary port identifier 0x%x for port " | 1578 | zfcp_erp_adapter_reopen(port->adapter, 0, 107, req); |
2664 | "0x%016Lx on adapter %s invalid. This may happen " | 1579 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2665 | "occasionally.\n", port->handle, | ||
2666 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
2667 | ZFCP_LOG_DEBUG("status qualifier:\n"); | ||
2668 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
2669 | (char *) &fsf_req->qtcb->header.fsf_status_qual, | ||
2670 | sizeof (union fsf_status_qual)); | ||
2671 | zfcp_erp_adapter_reopen(port->adapter, 0, 107, fsf_req); | ||
2672 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2673 | break; | 1580 | break; |
2674 | |||
2675 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1581 | case FSF_ADAPTER_STATUS_AVAILABLE: |
2676 | /* Note: FSF has actually closed the port in this case. | ||
2677 | * The status code is just daft. Fingers crossed for a change | ||
2678 | */ | ||
2679 | retval = 0; | ||
2680 | break; | 1582 | break; |
2681 | |||
2682 | case FSF_GOOD: | 1583 | case FSF_GOOD: |
2683 | ZFCP_LOG_TRACE("remote port 0x016%Lx on adapter %s closed, " | 1584 | zfcp_erp_modify_port_status(port, 33, req, |
2684 | "port handle 0x%x\n", port->wwpn, | ||
2685 | zfcp_get_busid_by_port(port), port->handle); | ||
2686 | zfcp_erp_modify_port_status(port, 33, fsf_req, | ||
2687 | ZFCP_STATUS_COMMON_OPEN, | 1585 | ZFCP_STATUS_COMMON_OPEN, |
2688 | ZFCP_CLEAR); | 1586 | ZFCP_CLEAR); |
2689 | retval = 0; | ||
2690 | break; | ||
2691 | |||
2692 | default: | ||
2693 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
2694 | "(debug info 0x%x)\n", | ||
2695 | fsf_req->qtcb->header.fsf_status); | ||
2696 | break; | 1587 | break; |
2697 | } | 1588 | } |
2698 | 1589 | ||
2699 | skip_fsfstatus: | 1590 | skip_fsfstatus: |
2700 | atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status); | 1591 | atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status); |
2701 | return retval; | ||
2702 | } | 1592 | } |
2703 | 1593 | ||
2704 | /* | 1594 | /** |
2705 | * function: zfcp_fsf_close_physical_port | 1595 | * zfcp_fsf_close_port - create and send close port request |
2706 | * | 1596 | * @erp_action: pointer to struct zfcp_erp_action |
2707 | * purpose: submit FSF command "close physical port" | 1597 | * Returns: 0 on success, error otherwise |
2708 | * | ||
2709 | * returns: address of initiated FSF request | ||
2710 | * NULL - request could not be initiated | ||
2711 | */ | 1598 | */ |
2712 | int | 1599 | int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) |
2713 | zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) | ||
2714 | { | 1600 | { |
2715 | volatile struct qdio_buffer_element *sbale; | 1601 | volatile struct qdio_buffer_element *sbale; |
2716 | struct zfcp_fsf_req *fsf_req; | 1602 | struct zfcp_adapter *adapter = erp_action->adapter; |
2717 | unsigned long lock_flags; | 1603 | struct zfcp_fsf_req *req; |
2718 | int retval = 0; | 1604 | int retval = -EIO; |
2719 | |||
2720 | /* setup new FSF request */ | ||
2721 | retval = zfcp_fsf_req_create(erp_action->adapter, | ||
2722 | FSF_QTCB_CLOSE_PHYSICAL_PORT, | ||
2723 | ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | ||
2724 | erp_action->adapter->pool.fsf_req_erp, | ||
2725 | &lock_flags, &fsf_req); | ||
2726 | if (retval < 0) { | ||
2727 | ZFCP_LOG_INFO("error: Could not create close physical port " | ||
2728 | "request (adapter %s, port 0x%016Lx)\n", | ||
2729 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2730 | erp_action->port->wwpn); | ||
2731 | 1605 | ||
1606 | spin_lock(&adapter->req_q.lock); | ||
1607 | if (zfcp_fsf_req_sbal_get(adapter)) | ||
1608 | goto out; | ||
1609 | |||
1610 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT, | ||
1611 | ZFCP_REQ_AUTO_CLEANUP, | ||
1612 | adapter->pool.fsf_req_erp); | ||
1613 | if (unlikely(IS_ERR(req))) { | ||
1614 | retval = PTR_ERR(req); | ||
2732 | goto out; | 1615 | goto out; |
2733 | } | 1616 | } |
2734 | 1617 | ||
2735 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1618 | sbale = zfcp_qdio_sbale_req(req); |
2736 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1619 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
2737 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1620 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
2738 | 1621 | ||
2739 | /* mark port as being closed */ | 1622 | req->handler = zfcp_fsf_close_port_handler; |
2740 | atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, | 1623 | req->data = erp_action->port; |
2741 | &erp_action->port->status); | 1624 | req->erp_action = erp_action; |
2742 | /* save a pointer to this port */ | 1625 | req->qtcb->header.port_handle = erp_action->port->handle; |
2743 | fsf_req->data = (unsigned long) erp_action->port; | 1626 | erp_action->fsf_req = req; |
2744 | fsf_req->qtcb->header.port_handle = erp_action->port->handle; | 1627 | atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status); |
2745 | fsf_req->erp_action = erp_action; | 1628 | |
2746 | erp_action->fsf_req = fsf_req; | 1629 | zfcp_fsf_start_erp_timer(req); |
2747 | 1630 | retval = zfcp_fsf_req_send(req); | |
2748 | zfcp_erp_start_timer(fsf_req); | ||
2749 | retval = zfcp_fsf_req_send(fsf_req); | ||
2750 | if (retval) { | 1631 | if (retval) { |
2751 | ZFCP_LOG_INFO("error: Could not send close physical port " | 1632 | zfcp_fsf_req_free(req); |
2752 | "request (adapter %s, port 0x%016Lx)\n", | ||
2753 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2754 | erp_action->port->wwpn); | ||
2755 | zfcp_fsf_req_free(fsf_req); | ||
2756 | erp_action->fsf_req = NULL; | 1633 | erp_action->fsf_req = NULL; |
2757 | goto out; | ||
2758 | } | 1634 | } |
2759 | 1635 | out: | |
2760 | ZFCP_LOG_TRACE("close physical port request initiated " | 1636 | spin_unlock(&adapter->req_q.lock); |
2761 | "(adapter %s, port 0x%016Lx)\n", | ||
2762 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2763 | erp_action->port->wwpn); | ||
2764 | out: | ||
2765 | write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | ||
2766 | lock_flags); | ||
2767 | return retval; | 1637 | return retval; |
2768 | } | 1638 | } |
2769 | 1639 | ||
2770 | /* | 1640 | static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) |
2771 | * function: zfcp_fsf_close_physical_port_handler | ||
2772 | * | ||
2773 | * purpose: is called for finished Close Physical Port FSF command | ||
2774 | * | ||
2775 | * returns: | ||
2776 | */ | ||
2777 | static int | ||
2778 | zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) | ||
2779 | { | 1641 | { |
2780 | int retval = -EINVAL; | 1642 | struct zfcp_port *port = req->data; |
2781 | struct zfcp_port *port; | 1643 | struct fsf_qtcb_header *header = &req->qtcb->header; |
2782 | struct zfcp_unit *unit; | 1644 | struct zfcp_unit *unit; |
2783 | struct fsf_qtcb_header *header; | ||
2784 | u16 subtable, rule, counter; | ||
2785 | 1645 | ||
2786 | port = (struct zfcp_port *) fsf_req->data; | 1646 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
2787 | header = &fsf_req->qtcb->header; | ||
2788 | |||
2789 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
2790 | /* don't change port status in our bookkeeping */ | ||
2791 | goto skip_fsfstatus; | 1647 | goto skip_fsfstatus; |
2792 | } | ||
2793 | 1648 | ||
2794 | /* evaluate FSF status in QTCB */ | ||
2795 | switch (header->fsf_status) { | 1649 | switch (header->fsf_status) { |
2796 | |||
2797 | case FSF_PORT_HANDLE_NOT_VALID: | 1650 | case FSF_PORT_HANDLE_NOT_VALID: |
2798 | ZFCP_LOG_INFO("Temporary port identifier 0x%x invalid" | 1651 | zfcp_erp_adapter_reopen(port->adapter, 0, 108, req); |
2799 | "(adapter %s, port 0x%016Lx). " | 1652 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2800 | "This may happen occasionally.\n", | ||
2801 | port->handle, | ||
2802 | zfcp_get_busid_by_port(port), | ||
2803 | port->wwpn); | ||
2804 | ZFCP_LOG_DEBUG("status qualifier:\n"); | ||
2805 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
2806 | (char *) &header->fsf_status_qual, | ||
2807 | sizeof (union fsf_status_qual)); | ||
2808 | zfcp_erp_adapter_reopen(port->adapter, 0, 108, fsf_req); | ||
2809 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2810 | break; | 1653 | break; |
2811 | |||
2812 | case FSF_ACCESS_DENIED: | 1654 | case FSF_ACCESS_DENIED: |
2813 | ZFCP_LOG_NORMAL("Access denied, cannot close " | 1655 | zfcp_fsf_access_denied_port(req, port); |
2814 | "physical port 0x%016Lx on adapter %s\n", | ||
2815 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
2816 | for (counter = 0; counter < 2; counter++) { | ||
2817 | subtable = header->fsf_status_qual.halfword[counter * 2]; | ||
2818 | rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | ||
2819 | switch (subtable) { | ||
2820 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
2821 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
2822 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
2823 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
2824 | ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | ||
2825 | zfcp_act_subtable_type[subtable], rule); | ||
2826 | break; | ||
2827 | } | ||
2828 | } | ||
2829 | zfcp_erp_port_access_denied(port, 58, fsf_req); | ||
2830 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2831 | break; | 1656 | break; |
2832 | |||
2833 | case FSF_PORT_BOXED: | 1657 | case FSF_PORT_BOXED: |
2834 | ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter " | 1658 | zfcp_erp_port_boxed(port, 50, req); |
2835 | "%s needs to be reopened but it was attempted " | 1659 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
2836 | "to close it physically.\n", | 1660 | ZFCP_STATUS_FSFREQ_RETRY; |
2837 | port->wwpn, | ||
2838 | zfcp_get_busid_by_port(port)); | ||
2839 | zfcp_erp_port_boxed(port, 50, fsf_req); | ||
2840 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | ||
2841 | ZFCP_STATUS_FSFREQ_RETRY; | ||
2842 | |||
2843 | /* can't use generic zfcp_erp_modify_port_status because | 1661 | /* can't use generic zfcp_erp_modify_port_status because |
2844 | * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ | 1662 | * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ |
2845 | atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); | 1663 | atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); |
@@ -2847,154 +1665,88 @@ zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) | |||
2847 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, | 1665 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, |
2848 | &unit->status); | 1666 | &unit->status); |
2849 | break; | 1667 | break; |
2850 | |||
2851 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1668 | case FSF_ADAPTER_STATUS_AVAILABLE: |
2852 | switch (header->fsf_status_qual.word[0]) { | 1669 | switch (header->fsf_status_qual.word[0]) { |
2853 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 1670 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
2854 | /* This will now be escalated by ERP */ | 1671 | /* fall through */ |
2855 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2856 | break; | ||
2857 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 1672 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
2858 | /* ERP strategy will escalate */ | 1673 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2859 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2860 | break; | ||
2861 | default: | ||
2862 | ZFCP_LOG_NORMAL | ||
2863 | ("bug: Wrong status qualifier 0x%x arrived.\n", | ||
2864 | header->fsf_status_qual.word[0]); | ||
2865 | break; | 1674 | break; |
2866 | } | 1675 | } |
2867 | break; | 1676 | break; |
2868 | |||
2869 | case FSF_GOOD: | 1677 | case FSF_GOOD: |
2870 | ZFCP_LOG_DEBUG("Remote port 0x%016Lx via adapter %s " | ||
2871 | "physically closed, port handle 0x%x\n", | ||
2872 | port->wwpn, | ||
2873 | zfcp_get_busid_by_port(port), port->handle); | ||
2874 | /* can't use generic zfcp_erp_modify_port_status because | 1678 | /* can't use generic zfcp_erp_modify_port_status because |
2875 | * ZFCP_STATUS_COMMON_OPEN must not be reset for the port | 1679 | * ZFCP_STATUS_COMMON_OPEN must not be reset for the port |
2876 | */ | 1680 | */ |
2877 | atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); | 1681 | atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); |
2878 | list_for_each_entry(unit, &port->unit_list_head, list) | 1682 | list_for_each_entry(unit, &port->unit_list_head, list) |
2879 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); | 1683 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, |
2880 | retval = 0; | 1684 | &unit->status); |
2881 | break; | ||
2882 | |||
2883 | default: | ||
2884 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
2885 | "(debug info 0x%x)\n", | ||
2886 | header->fsf_status); | ||
2887 | break; | 1685 | break; |
2888 | } | 1686 | } |
2889 | 1687 | skip_fsfstatus: | |
2890 | skip_fsfstatus: | ||
2891 | atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status); | 1688 | atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status); |
2892 | return retval; | ||
2893 | } | 1689 | } |
2894 | 1690 | ||
2895 | /* | 1691 | /** |
2896 | * function: zfcp_fsf_open_unit | 1692 | * zfcp_fsf_close_physical_port - close physical port |
2897 | * | 1693 | * @erp_action: pointer to struct zfcp_erp_action |
2898 | * purpose: | 1694 | * Returns: 0 on success |
2899 | * | ||
2900 | * returns: | ||
2901 | * | ||
2902 | * assumptions: This routine does not check whether the associated | ||
2903 | * remote port has already been opened. This should be | ||
2904 | * done by calling routines. Otherwise some status | ||
2905 | * may be presented by FSF | ||
2906 | */ | 1695 | */ |
2907 | int | 1696 | int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) |
2908 | zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) | ||
2909 | { | 1697 | { |
2910 | volatile struct qdio_buffer_element *sbale; | 1698 | volatile struct qdio_buffer_element *sbale; |
2911 | struct zfcp_fsf_req *fsf_req; | 1699 | struct zfcp_adapter *adapter = erp_action->adapter; |
2912 | unsigned long lock_flags; | 1700 | struct zfcp_fsf_req *req; |
2913 | int retval = 0; | 1701 | int retval = -EIO; |
2914 | 1702 | ||
2915 | /* setup new FSF request */ | 1703 | spin_lock(&adapter->req_q.lock); |
2916 | retval = zfcp_fsf_req_create(erp_action->adapter, | 1704 | if (zfcp_fsf_req_sbal_get(adapter)) |
2917 | FSF_QTCB_OPEN_LUN, | 1705 | goto out; |
2918 | ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | 1706 | |
2919 | erp_action->adapter->pool.fsf_req_erp, | 1707 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PHYSICAL_PORT, |
2920 | &lock_flags, &fsf_req); | 1708 | ZFCP_REQ_AUTO_CLEANUP, |
2921 | if (retval < 0) { | 1709 | adapter->pool.fsf_req_erp); |
2922 | ZFCP_LOG_INFO("error: Could not create open unit request for " | 1710 | if (unlikely(IS_ERR(req))) { |
2923 | "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n", | 1711 | retval = PTR_ERR(req); |
2924 | erp_action->unit->fcp_lun, | ||
2925 | erp_action->unit->port->wwpn, | ||
2926 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
2927 | goto out; | 1712 | goto out; |
2928 | } | 1713 | } |
2929 | 1714 | ||
2930 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1715 | sbale = zfcp_qdio_sbale_req(req); |
2931 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1716 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
2932 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1717 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
2933 | 1718 | ||
2934 | fsf_req->qtcb->header.port_handle = erp_action->port->handle; | 1719 | req->data = erp_action->port; |
2935 | fsf_req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun; | 1720 | req->qtcb->header.port_handle = erp_action->port->handle; |
2936 | if (!(erp_action->adapter->connection_features & FSF_FEATURE_NPIV_MODE)) | 1721 | req->erp_action = erp_action; |
2937 | fsf_req->qtcb->bottom.support.option = | 1722 | req->handler = zfcp_fsf_close_physical_port_handler; |
2938 | FSF_OPEN_LUN_SUPPRESS_BOXING; | 1723 | erp_action->fsf_req = req; |
2939 | atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status); | 1724 | atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, |
2940 | fsf_req->data = (unsigned long) erp_action->unit; | 1725 | &erp_action->port->status); |
2941 | fsf_req->erp_action = erp_action; | ||
2942 | erp_action->fsf_req = fsf_req; | ||
2943 | 1726 | ||
2944 | zfcp_erp_start_timer(fsf_req); | 1727 | zfcp_fsf_start_erp_timer(req); |
2945 | retval = zfcp_fsf_req_send(erp_action->fsf_req); | 1728 | retval = zfcp_fsf_req_send(req); |
2946 | if (retval) { | 1729 | if (retval) { |
2947 | ZFCP_LOG_INFO("error: Could not send an open unit request " | 1730 | zfcp_fsf_req_free(req); |
2948 | "on the adapter %s, port 0x%016Lx for " | ||
2949 | "unit 0x%016Lx\n", | ||
2950 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2951 | erp_action->port->wwpn, | ||
2952 | erp_action->unit->fcp_lun); | ||
2953 | zfcp_fsf_req_free(fsf_req); | ||
2954 | erp_action->fsf_req = NULL; | 1731 | erp_action->fsf_req = NULL; |
2955 | goto out; | ||
2956 | } | 1732 | } |
2957 | 1733 | out: | |
2958 | ZFCP_LOG_TRACE("Open LUN request initiated (adapter %s, " | 1734 | spin_unlock(&adapter->req_q.lock); |
2959 | "port 0x%016Lx, unit 0x%016Lx)\n", | ||
2960 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2961 | erp_action->port->wwpn, erp_action->unit->fcp_lun); | ||
2962 | out: | ||
2963 | write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | ||
2964 | lock_flags); | ||
2965 | return retval; | 1735 | return retval; |
2966 | } | 1736 | } |
2967 | 1737 | ||
2968 | /* | 1738 | static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) |
2969 | * function: zfcp_fsf_open_unit_handler | ||
2970 | * | ||
2971 | * purpose: is called for finished Open LUN command | ||
2972 | * | ||
2973 | * returns: | ||
2974 | */ | ||
2975 | static int | ||
2976 | zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) | ||
2977 | { | 1739 | { |
2978 | int retval = -EINVAL; | 1740 | struct zfcp_adapter *adapter = req->adapter; |
2979 | struct zfcp_adapter *adapter; | 1741 | struct zfcp_unit *unit = req->data; |
2980 | struct zfcp_unit *unit; | 1742 | struct fsf_qtcb_header *header = &req->qtcb->header; |
2981 | struct fsf_qtcb_header *header; | 1743 | struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support; |
2982 | struct fsf_qtcb_bottom_support *bottom; | 1744 | struct fsf_queue_designator *queue_designator = |
2983 | struct fsf_queue_designator *queue_designator; | 1745 | &header->fsf_status_qual.fsf_queue_designator; |
2984 | u16 subtable, rule, counter; | ||
2985 | int exclusive, readwrite; | 1746 | int exclusive, readwrite; |
2986 | 1747 | ||
2987 | unit = (struct zfcp_unit *) fsf_req->data; | 1748 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
2988 | |||
2989 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
2990 | /* don't change unit status in our bookkeeping */ | ||
2991 | goto skip_fsfstatus; | 1749 | goto skip_fsfstatus; |
2992 | } | ||
2993 | |||
2994 | adapter = fsf_req->adapter; | ||
2995 | header = &fsf_req->qtcb->header; | ||
2996 | bottom = &fsf_req->qtcb->bottom.support; | ||
2997 | queue_designator = &header->fsf_status_qual.fsf_queue_designator; | ||
2998 | 1750 | ||
2999 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | | 1751 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | |
3000 | ZFCP_STATUS_COMMON_ACCESS_BOXED | | 1752 | ZFCP_STATUS_COMMON_ACCESS_BOXED | |
@@ -3002,155 +1754,65 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) | |||
3002 | ZFCP_STATUS_UNIT_READONLY, | 1754 | ZFCP_STATUS_UNIT_READONLY, |
3003 | &unit->status); | 1755 | &unit->status); |
3004 | 1756 | ||
3005 | /* evaluate FSF status in QTCB */ | ||
3006 | switch (header->fsf_status) { | 1757 | switch (header->fsf_status) { |
3007 | 1758 | ||
3008 | case FSF_PORT_HANDLE_NOT_VALID: | 1759 | case FSF_PORT_HANDLE_NOT_VALID: |
3009 | ZFCP_LOG_INFO("Temporary port identifier 0x%x " | 1760 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 109, req); |
3010 | "for port 0x%016Lx on adapter %s invalid " | 1761 | /* fall through */ |
3011 | "This may happen occasionally\n", | ||
3012 | unit->port->handle, | ||
3013 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | ||
3014 | ZFCP_LOG_DEBUG("status qualifier:\n"); | ||
3015 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3016 | (char *) &header->fsf_status_qual, | ||
3017 | sizeof (union fsf_status_qual)); | ||
3018 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 109, fsf_req); | ||
3019 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3020 | break; | ||
3021 | |||
3022 | case FSF_LUN_ALREADY_OPEN: | 1762 | case FSF_LUN_ALREADY_OPEN: |
3023 | ZFCP_LOG_NORMAL("bug: Attempted to open unit 0x%016Lx on " | ||
3024 | "remote port 0x%016Lx on adapter %s twice.\n", | ||
3025 | unit->fcp_lun, | ||
3026 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | ||
3027 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3028 | break; | 1763 | break; |
3029 | |||
3030 | case FSF_ACCESS_DENIED: | 1764 | case FSF_ACCESS_DENIED: |
3031 | ZFCP_LOG_NORMAL("Access denied, cannot open unit 0x%016Lx on " | 1765 | zfcp_fsf_access_denied_unit(req, unit); |
3032 | "remote port 0x%016Lx on adapter %s\n", | ||
3033 | unit->fcp_lun, unit->port->wwpn, | ||
3034 | zfcp_get_busid_by_unit(unit)); | ||
3035 | for (counter = 0; counter < 2; counter++) { | ||
3036 | subtable = header->fsf_status_qual.halfword[counter * 2]; | ||
3037 | rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | ||
3038 | switch (subtable) { | ||
3039 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
3040 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
3041 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
3042 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
3043 | ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | ||
3044 | zfcp_act_subtable_type[subtable], rule); | ||
3045 | break; | ||
3046 | } | ||
3047 | } | ||
3048 | zfcp_erp_unit_access_denied(unit, 59, fsf_req); | ||
3049 | atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); | 1766 | atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); |
3050 | atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); | 1767 | atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); |
3051 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3052 | break; | 1768 | break; |
3053 | |||
3054 | case FSF_PORT_BOXED: | 1769 | case FSF_PORT_BOXED: |
3055 | ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s " | 1770 | zfcp_erp_port_boxed(unit->port, 51, req); |
3056 | "needs to be reopened\n", | 1771 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
3057 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | 1772 | ZFCP_STATUS_FSFREQ_RETRY; |
3058 | zfcp_erp_port_boxed(unit->port, 51, fsf_req); | ||
3059 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | ||
3060 | ZFCP_STATUS_FSFREQ_RETRY; | ||
3061 | break; | 1773 | break; |
3062 | |||
3063 | case FSF_LUN_SHARING_VIOLATION: | 1774 | case FSF_LUN_SHARING_VIOLATION: |
3064 | if (header->fsf_status_qual.word[0] != 0) { | 1775 | if (header->fsf_status_qual.word[0]) |
3065 | ZFCP_LOG_NORMAL("FCP-LUN 0x%Lx at the remote port " | 1776 | dev_warn(&adapter->ccw_device->dev, |
3066 | "with WWPN 0x%Lx " | 1777 | "FCP-LUN 0x%Lx at the remote port " |
3067 | "connected to the adapter %s " | 1778 | "with WWPN 0x%Lx " |
3068 | "is already in use in LPAR%d, CSS%d\n", | 1779 | "connected to the adapter " |
3069 | unit->fcp_lun, | 1780 | "is already in use in LPAR%d, CSS%d.\n", |
3070 | unit->port->wwpn, | 1781 | unit->fcp_lun, |
3071 | zfcp_get_busid_by_unit(unit), | 1782 | unit->port->wwpn, |
3072 | queue_designator->hla, | 1783 | queue_designator->hla, |
3073 | queue_designator->cssid); | 1784 | queue_designator->cssid); |
3074 | } else { | 1785 | else |
3075 | subtable = header->fsf_status_qual.halfword[4]; | 1786 | zfcp_act_eval_err(adapter, |
3076 | rule = header->fsf_status_qual.halfword[5]; | 1787 | header->fsf_status_qual.word[2]); |
3077 | switch (subtable) { | 1788 | zfcp_erp_unit_access_denied(unit, 60, req); |
3078 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
3079 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
3080 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
3081 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
3082 | ZFCP_LOG_NORMAL("Access to FCP-LUN 0x%Lx at the " | ||
3083 | "remote port with WWPN 0x%Lx " | ||
3084 | "connected to the adapter %s " | ||
3085 | "is denied (%s rule %d)\n", | ||
3086 | unit->fcp_lun, | ||
3087 | unit->port->wwpn, | ||
3088 | zfcp_get_busid_by_unit(unit), | ||
3089 | zfcp_act_subtable_type[subtable], | ||
3090 | rule); | ||
3091 | break; | ||
3092 | } | ||
3093 | } | ||
3094 | ZFCP_LOG_DEBUG("status qualifier:\n"); | ||
3095 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3096 | (char *) &header->fsf_status_qual, | ||
3097 | sizeof (union fsf_status_qual)); | ||
3098 | zfcp_erp_unit_access_denied(unit, 60, fsf_req); | ||
3099 | atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); | 1789 | atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); |
3100 | atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); | 1790 | atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); |
3101 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1791 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
3102 | break; | 1792 | break; |
3103 | |||
3104 | case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED: | 1793 | case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED: |
3105 | ZFCP_LOG_INFO("error: The adapter ran out of resources. " | 1794 | dev_warn(&adapter->ccw_device->dev, |
3106 | "There is no handle (temporary port identifier) " | 1795 | "The adapter ran out of resources. There is no " |
3107 | "available for unit 0x%016Lx on port 0x%016Lx " | 1796 | "handle available for unit 0x%016Lx on port 0x%016Lx.", |
3108 | "on adapter %s\n", | 1797 | unit->fcp_lun, unit->port->wwpn); |
3109 | unit->fcp_lun, | 1798 | zfcp_erp_unit_failed(unit, 34, req); |
3110 | unit->port->wwpn, | 1799 | /* fall through */ |
3111 | zfcp_get_busid_by_unit(unit)); | 1800 | case FSF_INVALID_COMMAND_OPTION: |
3112 | zfcp_erp_unit_failed(unit, 34, fsf_req); | 1801 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
3113 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3114 | break; | 1802 | break; |
3115 | |||
3116 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1803 | case FSF_ADAPTER_STATUS_AVAILABLE: |
3117 | switch (header->fsf_status_qual.word[0]) { | 1804 | switch (header->fsf_status_qual.word[0]) { |
3118 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 1805 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
3119 | /* Re-establish link to port */ | ||
3120 | zfcp_test_link(unit->port); | 1806 | zfcp_test_link(unit->port); |
3121 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1807 | /* fall through */ |
3122 | break; | ||
3123 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 1808 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
3124 | /* ERP strategy will escalate */ | 1809 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
3125 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3126 | break; | 1810 | break; |
3127 | default: | ||
3128 | ZFCP_LOG_NORMAL | ||
3129 | ("bug: Wrong status qualifier 0x%x arrived.\n", | ||
3130 | header->fsf_status_qual.word[0]); | ||
3131 | } | 1811 | } |
3132 | break; | 1812 | break; |
3133 | 1813 | ||
3134 | case FSF_INVALID_COMMAND_OPTION: | ||
3135 | ZFCP_LOG_NORMAL( | ||
3136 | "Invalid option 0x%x has been specified " | ||
3137 | "in QTCB bottom sent to the adapter %s\n", | ||
3138 | bottom->option, | ||
3139 | zfcp_get_busid_by_adapter(adapter)); | ||
3140 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3141 | retval = -EINVAL; | ||
3142 | break; | ||
3143 | |||
3144 | case FSF_GOOD: | 1814 | case FSF_GOOD: |
3145 | /* save LUN handle assigned by FSF */ | ||
3146 | unit->handle = header->lun_handle; | 1815 | unit->handle = header->lun_handle; |
3147 | ZFCP_LOG_TRACE("unit 0x%016Lx on remote port 0x%016Lx on " | ||
3148 | "adapter %s opened, port handle 0x%x\n", | ||
3149 | unit->fcp_lun, | ||
3150 | unit->port->wwpn, | ||
3151 | zfcp_get_busid_by_unit(unit), | ||
3152 | unit->handle); | ||
3153 | /* mark unit as open */ | ||
3154 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); | 1816 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); |
3155 | 1817 | ||
3156 | if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) && | 1818 | if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) && |
@@ -3168,1528 +1830,629 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) | |||
3168 | if (!readwrite) { | 1830 | if (!readwrite) { |
3169 | atomic_set_mask(ZFCP_STATUS_UNIT_READONLY, | 1831 | atomic_set_mask(ZFCP_STATUS_UNIT_READONLY, |
3170 | &unit->status); | 1832 | &unit->status); |
3171 | ZFCP_LOG_NORMAL("read-only access for unit " | 1833 | dev_info(&adapter->ccw_device->dev, |
3172 | "(adapter %s, wwpn=0x%016Lx, " | 1834 | "Read-only access for unit 0x%016Lx " |
3173 | "fcp_lun=0x%016Lx)\n", | 1835 | "on port 0x%016Lx.\n", |
3174 | zfcp_get_busid_by_unit(unit), | 1836 | unit->fcp_lun, unit->port->wwpn); |
3175 | unit->port->wwpn, | ||
3176 | unit->fcp_lun); | ||
3177 | } | 1837 | } |
3178 | 1838 | ||
3179 | if (exclusive && !readwrite) { | 1839 | if (exclusive && !readwrite) { |
3180 | ZFCP_LOG_NORMAL("exclusive access of read-only " | 1840 | dev_err(&adapter->ccw_device->dev, |
3181 | "unit not supported\n"); | 1841 | "Exclusive access of read-only unit " |
3182 | zfcp_erp_unit_failed(unit, 35, fsf_req); | 1842 | "0x%016Lx on port 0x%016Lx not " |
3183 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1843 | "supported, disabling unit.\n", |
3184 | zfcp_erp_unit_shutdown(unit, 0, 80, fsf_req); | 1844 | unit->fcp_lun, unit->port->wwpn); |
1845 | zfcp_erp_unit_failed(unit, 35, req); | ||
1846 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1847 | zfcp_erp_unit_shutdown(unit, 0, 80, req); | ||
3185 | } else if (!exclusive && readwrite) { | 1848 | } else if (!exclusive && readwrite) { |
3186 | ZFCP_LOG_NORMAL("shared access of read-write " | 1849 | dev_err(&adapter->ccw_device->dev, |
3187 | "unit not supported\n"); | 1850 | "Shared access of read-write unit " |
3188 | zfcp_erp_unit_failed(unit, 36, fsf_req); | 1851 | "0x%016Lx on port 0x%016Lx not " |
3189 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1852 | "supported, disabling unit.\n", |
3190 | zfcp_erp_unit_shutdown(unit, 0, 81, fsf_req); | 1853 | unit->fcp_lun, unit->port->wwpn); |
1854 | zfcp_erp_unit_failed(unit, 36, req); | ||
1855 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1856 | zfcp_erp_unit_shutdown(unit, 0, 81, req); | ||
3191 | } | 1857 | } |
3192 | } | 1858 | } |
3193 | |||
3194 | retval = 0; | ||
3195 | break; | ||
3196 | |||
3197 | default: | ||
3198 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
3199 | "(debug info 0x%x)\n", | ||
3200 | header->fsf_status); | ||
3201 | break; | 1859 | break; |
3202 | } | 1860 | } |
3203 | 1861 | ||
3204 | skip_fsfstatus: | 1862 | skip_fsfstatus: |
3205 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status); | 1863 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status); |
3206 | return retval; | ||
3207 | } | 1864 | } |
3208 | 1865 | ||
3209 | /* | 1866 | /** |
3210 | * function: zfcp_fsf_close_unit | 1867 | * zfcp_fsf_open_unit - open unit |
3211 | * | 1868 | * @erp_action: pointer to struct zfcp_erp_action |
3212 | * purpose: | 1869 | * Returns: 0 on success, error otherwise |
3213 | * | ||
3214 | * returns: address of fsf_req - request successfully initiated | ||
3215 | * NULL - | ||
3216 | * | ||
3217 | * assumptions: This routine does not check whether the associated | ||
3218 | * remote port/lun has already been opened. This should be | ||
3219 | * done by calling routines. Otherwise some status | ||
3220 | * may be presented by FSF | ||
3221 | */ | 1870 | */ |
3222 | int | 1871 | int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) |
3223 | zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) | ||
3224 | { | 1872 | { |
3225 | volatile struct qdio_buffer_element *sbale; | 1873 | volatile struct qdio_buffer_element *sbale; |
3226 | struct zfcp_fsf_req *fsf_req; | 1874 | struct zfcp_adapter *adapter = erp_action->adapter; |
3227 | unsigned long lock_flags; | 1875 | struct zfcp_fsf_req *req; |
3228 | int retval = 0; | 1876 | int retval = -EIO; |
3229 | 1877 | ||
3230 | /* setup new FSF request */ | 1878 | spin_lock(&adapter->req_q.lock); |
3231 | retval = zfcp_fsf_req_create(erp_action->adapter, | 1879 | if (zfcp_fsf_req_sbal_get(adapter)) |
3232 | FSF_QTCB_CLOSE_LUN, | 1880 | goto out; |
3233 | ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | 1881 | |
3234 | erp_action->adapter->pool.fsf_req_erp, | 1882 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_LUN, |
3235 | &lock_flags, &fsf_req); | 1883 | ZFCP_REQ_AUTO_CLEANUP, |
3236 | if (retval < 0) { | 1884 | adapter->pool.fsf_req_erp); |
3237 | ZFCP_LOG_INFO("error: Could not create close unit request for " | 1885 | if (unlikely(IS_ERR(req))) { |
3238 | "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n", | 1886 | retval = PTR_ERR(req); |
3239 | erp_action->unit->fcp_lun, | ||
3240 | erp_action->port->wwpn, | ||
3241 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
3242 | goto out; | 1887 | goto out; |
3243 | } | 1888 | } |
3244 | 1889 | ||
3245 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1890 | sbale = zfcp_qdio_sbale_req(req); |
3246 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1891 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
3247 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1892 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
3248 | 1893 | ||
3249 | fsf_req->qtcb->header.port_handle = erp_action->port->handle; | 1894 | req->qtcb->header.port_handle = erp_action->port->handle; |
3250 | fsf_req->qtcb->header.lun_handle = erp_action->unit->handle; | 1895 | req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun; |
3251 | atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status); | 1896 | req->handler = zfcp_fsf_open_unit_handler; |
3252 | fsf_req->data = (unsigned long) erp_action->unit; | 1897 | req->data = erp_action->unit; |
3253 | fsf_req->erp_action = erp_action; | 1898 | req->erp_action = erp_action; |
3254 | erp_action->fsf_req = fsf_req; | 1899 | erp_action->fsf_req = req; |
3255 | 1900 | ||
3256 | zfcp_erp_start_timer(fsf_req); | 1901 | if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) |
3257 | retval = zfcp_fsf_req_send(erp_action->fsf_req); | 1902 | req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING; |
1903 | |||
1904 | atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status); | ||
1905 | |||
1906 | zfcp_fsf_start_erp_timer(req); | ||
1907 | retval = zfcp_fsf_req_send(req); | ||
3258 | if (retval) { | 1908 | if (retval) { |
3259 | ZFCP_LOG_INFO("error: Could not send a close unit request for " | 1909 | zfcp_fsf_req_free(req); |
3260 | "unit 0x%016Lx on port 0x%016Lx onadapter %s.\n", | ||
3261 | erp_action->unit->fcp_lun, | ||
3262 | erp_action->port->wwpn, | ||
3263 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
3264 | zfcp_fsf_req_free(fsf_req); | ||
3265 | erp_action->fsf_req = NULL; | 1910 | erp_action->fsf_req = NULL; |
3266 | goto out; | ||
3267 | } | 1911 | } |
3268 | 1912 | out: | |
3269 | ZFCP_LOG_TRACE("Close LUN request initiated (adapter %s, " | 1913 | spin_unlock(&adapter->req_q.lock); |
3270 | "port 0x%016Lx, unit 0x%016Lx)\n", | ||
3271 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
3272 | erp_action->port->wwpn, erp_action->unit->fcp_lun); | ||
3273 | out: | ||
3274 | write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | ||
3275 | lock_flags); | ||
3276 | return retval; | 1914 | return retval; |
3277 | } | 1915 | } |
3278 | 1916 | ||
3279 | /* | 1917 | static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req) |
3280 | * function: zfcp_fsf_close_unit_handler | ||
3281 | * | ||
3282 | * purpose: is called for finished Close LUN FSF command | ||
3283 | * | ||
3284 | * returns: | ||
3285 | */ | ||
3286 | static int | ||
3287 | zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req) | ||
3288 | { | 1918 | { |
3289 | int retval = -EINVAL; | 1919 | struct zfcp_unit *unit = req->data; |
3290 | struct zfcp_unit *unit; | ||
3291 | |||
3292 | unit = (struct zfcp_unit *) fsf_req->data; | ||
3293 | 1920 | ||
3294 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | 1921 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
3295 | /* don't change unit status in our bookkeeping */ | ||
3296 | goto skip_fsfstatus; | 1922 | goto skip_fsfstatus; |
3297 | } | ||
3298 | |||
3299 | /* evaluate FSF status in QTCB */ | ||
3300 | switch (fsf_req->qtcb->header.fsf_status) { | ||
3301 | 1923 | ||
1924 | switch (req->qtcb->header.fsf_status) { | ||
3302 | case FSF_PORT_HANDLE_NOT_VALID: | 1925 | case FSF_PORT_HANDLE_NOT_VALID: |
3303 | ZFCP_LOG_INFO("Temporary port identifier 0x%x for port " | 1926 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 110, req); |
3304 | "0x%016Lx on adapter %s invalid. This may " | 1927 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
3305 | "happen in rare circumstances\n", | ||
3306 | unit->port->handle, | ||
3307 | unit->port->wwpn, | ||
3308 | zfcp_get_busid_by_unit(unit)); | ||
3309 | ZFCP_LOG_DEBUG("status qualifier:\n"); | ||
3310 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3311 | (char *) &fsf_req->qtcb->header.fsf_status_qual, | ||
3312 | sizeof (union fsf_status_qual)); | ||
3313 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 110, fsf_req); | ||
3314 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3315 | break; | 1928 | break; |
3316 | |||
3317 | case FSF_LUN_HANDLE_NOT_VALID: | 1929 | case FSF_LUN_HANDLE_NOT_VALID: |
3318 | ZFCP_LOG_INFO("Temporary LUN identifier 0x%x of unit " | 1930 | zfcp_erp_port_reopen(unit->port, 0, 111, req); |
3319 | "0x%016Lx on port 0x%016Lx on adapter %s is " | 1931 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
3320 | "invalid. This may happen occasionally.\n", | ||
3321 | unit->handle, | ||
3322 | unit->fcp_lun, | ||
3323 | unit->port->wwpn, | ||
3324 | zfcp_get_busid_by_unit(unit)); | ||
3325 | ZFCP_LOG_DEBUG("Status qualifier data:\n"); | ||
3326 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3327 | (char *) &fsf_req->qtcb->header.fsf_status_qual, | ||
3328 | sizeof (union fsf_status_qual)); | ||
3329 | zfcp_erp_port_reopen(unit->port, 0, 111, fsf_req); | ||
3330 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3331 | break; | 1932 | break; |
3332 | |||
3333 | case FSF_PORT_BOXED: | 1933 | case FSF_PORT_BOXED: |
3334 | ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s " | 1934 | zfcp_erp_port_boxed(unit->port, 52, req); |
3335 | "needs to be reopened\n", | 1935 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
3336 | unit->port->wwpn, | 1936 | ZFCP_STATUS_FSFREQ_RETRY; |
3337 | zfcp_get_busid_by_unit(unit)); | ||
3338 | zfcp_erp_port_boxed(unit->port, 52, fsf_req); | ||
3339 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | ||
3340 | ZFCP_STATUS_FSFREQ_RETRY; | ||
3341 | break; | 1937 | break; |
3342 | |||
3343 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1938 | case FSF_ADAPTER_STATUS_AVAILABLE: |
3344 | switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) { | 1939 | switch (req->qtcb->header.fsf_status_qual.word[0]) { |
3345 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 1940 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
3346 | /* re-establish link to port */ | ||
3347 | zfcp_test_link(unit->port); | 1941 | zfcp_test_link(unit->port); |
3348 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1942 | /* fall through */ |
3349 | break; | ||
3350 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 1943 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
3351 | /* ERP strategy will escalate */ | 1944 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
3352 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3353 | break; | ||
3354 | default: | ||
3355 | ZFCP_LOG_NORMAL | ||
3356 | ("bug: Wrong status qualifier 0x%x arrived.\n", | ||
3357 | fsf_req->qtcb->header.fsf_status_qual.word[0]); | ||
3358 | break; | 1945 | break; |
3359 | } | 1946 | } |
3360 | break; | 1947 | break; |
3361 | |||
3362 | case FSF_GOOD: | 1948 | case FSF_GOOD: |
3363 | ZFCP_LOG_TRACE("unit 0x%016Lx on port 0x%016Lx on adapter %s " | ||
3364 | "closed, port handle 0x%x\n", | ||
3365 | unit->fcp_lun, | ||
3366 | unit->port->wwpn, | ||
3367 | zfcp_get_busid_by_unit(unit), | ||
3368 | unit->handle); | ||
3369 | /* mark unit as closed */ | ||
3370 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); | 1949 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); |
3371 | retval = 0; | ||
3372 | break; | ||
3373 | |||
3374 | default: | ||
3375 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
3376 | "(debug info 0x%x)\n", | ||
3377 | fsf_req->qtcb->header.fsf_status); | ||
3378 | break; | 1950 | break; |
3379 | } | 1951 | } |
3380 | 1952 | skip_fsfstatus: | |
3381 | skip_fsfstatus: | ||
3382 | atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status); | 1953 | atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status); |
3383 | return retval; | ||
3384 | } | 1954 | } |
3385 | 1955 | ||
3386 | /** | 1956 | /** |
3387 | * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) | 1957 | * zfcp_fsf_close_unit - close zfcp unit |
3388 | * @adapter: adapter where scsi command is issued | 1958 | * @erp_action: pointer to struct zfcp_unit |
3389 | * @unit: unit where command is sent to | 1959 | * Returns: 0 on success, error otherwise |
3390 | * @scsi_cmnd: scsi command to be sent | ||
3391 | * @timer: timer to be started when request is initiated | ||
3392 | * @req_flags: flags for fsf_request | ||
3393 | */ | 1960 | */ |
3394 | int | 1961 | int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) |
3395 | zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, | ||
3396 | struct zfcp_unit *unit, | ||
3397 | struct scsi_cmnd * scsi_cmnd, | ||
3398 | int use_timer, int req_flags) | ||
3399 | { | 1962 | { |
3400 | struct zfcp_fsf_req *fsf_req = NULL; | 1963 | volatile struct qdio_buffer_element *sbale; |
3401 | struct fcp_cmnd_iu *fcp_cmnd_iu; | 1964 | struct zfcp_adapter *adapter = erp_action->adapter; |
3402 | unsigned int sbtype; | 1965 | struct zfcp_fsf_req *req; |
3403 | unsigned long lock_flags; | 1966 | int retval = -EIO; |
3404 | int real_bytes = 0; | ||
3405 | int retval = 0; | ||
3406 | int mask; | ||
3407 | |||
3408 | /* setup new FSF request */ | ||
3409 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, | ||
3410 | adapter->pool.fsf_req_scsi, | ||
3411 | &lock_flags, &fsf_req); | ||
3412 | if (unlikely(retval < 0)) { | ||
3413 | ZFCP_LOG_DEBUG("error: Could not create FCP command request " | ||
3414 | "for unit 0x%016Lx on port 0x%016Lx on " | ||
3415 | "adapter %s\n", | ||
3416 | unit->fcp_lun, | ||
3417 | unit->port->wwpn, | ||
3418 | zfcp_get_busid_by_adapter(adapter)); | ||
3419 | goto failed_req_create; | ||
3420 | } | ||
3421 | |||
3422 | if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
3423 | &unit->status))) { | ||
3424 | retval = -EBUSY; | ||
3425 | goto unit_blocked; | ||
3426 | } | ||
3427 | |||
3428 | zfcp_unit_get(unit); | ||
3429 | fsf_req->unit = unit; | ||
3430 | |||
3431 | /* associate FSF request with SCSI request (for look up on abort) */ | ||
3432 | scsi_cmnd->host_scribble = (unsigned char *) fsf_req->req_id; | ||
3433 | |||
3434 | /* associate SCSI command with FSF request */ | ||
3435 | fsf_req->data = (unsigned long) scsi_cmnd; | ||
3436 | |||
3437 | /* set handles of unit and its parent port in QTCB */ | ||
3438 | fsf_req->qtcb->header.lun_handle = unit->handle; | ||
3439 | fsf_req->qtcb->header.port_handle = unit->port->handle; | ||
3440 | |||
3441 | /* FSF does not define the structure of the FCP_CMND IU */ | ||
3442 | fcp_cmnd_iu = (struct fcp_cmnd_iu *) | ||
3443 | &(fsf_req->qtcb->bottom.io.fcp_cmnd); | ||
3444 | |||
3445 | /* | ||
3446 | * set depending on data direction: | ||
3447 | * data direction bits in SBALE (SB Type) | ||
3448 | * data direction bits in QTCB | ||
3449 | * data direction bits in FCP_CMND IU | ||
3450 | */ | ||
3451 | switch (scsi_cmnd->sc_data_direction) { | ||
3452 | case DMA_NONE: | ||
3453 | fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; | ||
3454 | /* | ||
3455 | * FIXME(qdio): | ||
3456 | * what is the correct type for commands | ||
3457 | * without 'real' data buffers? | ||
3458 | */ | ||
3459 | sbtype = SBAL_FLAGS0_TYPE_READ; | ||
3460 | break; | ||
3461 | case DMA_FROM_DEVICE: | ||
3462 | fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ; | ||
3463 | sbtype = SBAL_FLAGS0_TYPE_READ; | ||
3464 | fcp_cmnd_iu->rddata = 1; | ||
3465 | break; | ||
3466 | case DMA_TO_DEVICE: | ||
3467 | fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE; | ||
3468 | sbtype = SBAL_FLAGS0_TYPE_WRITE; | ||
3469 | fcp_cmnd_iu->wddata = 1; | ||
3470 | break; | ||
3471 | case DMA_BIDIRECTIONAL: | ||
3472 | default: | ||
3473 | /* | ||
3474 | * dummy, catch this condition earlier | ||
3475 | * in zfcp_scsi_queuecommand | ||
3476 | */ | ||
3477 | goto failed_scsi_cmnd; | ||
3478 | } | ||
3479 | |||
3480 | /* set FC service class in QTCB (3 per default) */ | ||
3481 | fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT; | ||
3482 | |||
3483 | /* set FCP_LUN in FCP_CMND IU in QTCB */ | ||
3484 | fcp_cmnd_iu->fcp_lun = unit->fcp_lun; | ||
3485 | |||
3486 | mask = ZFCP_STATUS_UNIT_READONLY | ZFCP_STATUS_UNIT_SHARED; | ||
3487 | |||
3488 | /* set task attributes in FCP_CMND IU in QTCB */ | ||
3489 | if (likely((scsi_cmnd->device->simple_tags) || | ||
3490 | (atomic_test_mask(mask, &unit->status)))) | ||
3491 | fcp_cmnd_iu->task_attribute = SIMPLE_Q; | ||
3492 | else | ||
3493 | fcp_cmnd_iu->task_attribute = UNTAGGED; | ||
3494 | |||
3495 | /* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */ | ||
3496 | if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) { | ||
3497 | fcp_cmnd_iu->add_fcp_cdb_length | ||
3498 | = (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2; | ||
3499 | ZFCP_LOG_TRACE("SCSI CDB length is 0x%x, " | ||
3500 | "additional FCP_CDB length is 0x%x " | ||
3501 | "(shifted right 2 bits)\n", | ||
3502 | scsi_cmnd->cmd_len, | ||
3503 | fcp_cmnd_iu->add_fcp_cdb_length); | ||
3504 | } | ||
3505 | /* | ||
3506 | * copy SCSI CDB (including additional length, if any) to | ||
3507 | * FCP_CDB in FCP_CMND IU in QTCB | ||
3508 | */ | ||
3509 | memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); | ||
3510 | |||
3511 | /* FCP CMND IU length in QTCB */ | ||
3512 | fsf_req->qtcb->bottom.io.fcp_cmnd_length = | ||
3513 | sizeof (struct fcp_cmnd_iu) + | ||
3514 | fcp_cmnd_iu->add_fcp_cdb_length + sizeof (fcp_dl_t); | ||
3515 | 1967 | ||
3516 | /* generate SBALEs from data buffer */ | 1968 | spin_lock(&adapter->req_q.lock); |
3517 | real_bytes = zfcp_qdio_sbals_from_scsicmnd(fsf_req, sbtype, scsi_cmnd); | 1969 | if (zfcp_fsf_req_sbal_get(adapter)) |
3518 | if (unlikely(real_bytes < 0)) { | 1970 | goto out; |
3519 | if (fsf_req->sbal_number < ZFCP_MAX_SBALS_PER_REQ) { | 1971 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN, |
3520 | ZFCP_LOG_DEBUG( | 1972 | ZFCP_REQ_AUTO_CLEANUP, |
3521 | "Data did not fit into available buffer(s), " | 1973 | adapter->pool.fsf_req_erp); |
3522 | "waiting for more...\n"); | 1974 | if (unlikely(IS_ERR(req))) { |
3523 | retval = -EIO; | 1975 | retval = PTR_ERR(req); |
3524 | } else { | 1976 | goto out; |
3525 | ZFCP_LOG_NORMAL("error: No truncation implemented but " | ||
3526 | "required. Shutting down unit " | ||
3527 | "(adapter %s, port 0x%016Lx, " | ||
3528 | "unit 0x%016Lx)\n", | ||
3529 | zfcp_get_busid_by_unit(unit), | ||
3530 | unit->port->wwpn, | ||
3531 | unit->fcp_lun); | ||
3532 | zfcp_erp_unit_shutdown(unit, 0, 131, fsf_req); | ||
3533 | retval = -EINVAL; | ||
3534 | } | ||
3535 | goto no_fit; | ||
3536 | } | 1977 | } |
3537 | 1978 | ||
3538 | /* set length of FCP data length in FCP_CMND IU in QTCB */ | 1979 | sbale = zfcp_qdio_sbale_req(req); |
3539 | zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes); | 1980 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
1981 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
3540 | 1982 | ||
3541 | ZFCP_LOG_DEBUG("Sending SCSI command:\n"); | 1983 | req->qtcb->header.port_handle = erp_action->port->handle; |
3542 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 1984 | req->qtcb->header.lun_handle = erp_action->unit->handle; |
3543 | (char *) scsi_cmnd->cmnd, scsi_cmnd->cmd_len); | 1985 | req->handler = zfcp_fsf_close_unit_handler; |
1986 | req->data = erp_action->unit; | ||
1987 | req->erp_action = erp_action; | ||
1988 | erp_action->fsf_req = req; | ||
1989 | atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status); | ||
3544 | 1990 | ||
3545 | if (use_timer) | 1991 | zfcp_fsf_start_erp_timer(req); |
3546 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | 1992 | retval = zfcp_fsf_req_send(req); |
3547 | 1993 | if (retval) { | |
3548 | retval = zfcp_fsf_req_send(fsf_req); | 1994 | zfcp_fsf_req_free(req); |
3549 | if (unlikely(retval < 0)) { | 1995 | erp_action->fsf_req = NULL; |
3550 | ZFCP_LOG_INFO("error: Could not send FCP command request " | ||
3551 | "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n", | ||
3552 | zfcp_get_busid_by_adapter(adapter), | ||
3553 | unit->port->wwpn, | ||
3554 | unit->fcp_lun); | ||
3555 | goto send_failed; | ||
3556 | } | 1996 | } |
3557 | 1997 | out: | |
3558 | ZFCP_LOG_TRACE("Send FCP Command initiated (adapter %s, " | 1998 | spin_unlock(&adapter->req_q.lock); |
3559 | "port 0x%016Lx, unit 0x%016Lx)\n", | ||
3560 | zfcp_get_busid_by_adapter(adapter), | ||
3561 | unit->port->wwpn, | ||
3562 | unit->fcp_lun); | ||
3563 | goto success; | ||
3564 | |||
3565 | send_failed: | ||
3566 | no_fit: | ||
3567 | failed_scsi_cmnd: | ||
3568 | zfcp_unit_put(unit); | ||
3569 | unit_blocked: | ||
3570 | zfcp_fsf_req_free(fsf_req); | ||
3571 | fsf_req = NULL; | ||
3572 | scsi_cmnd->host_scribble = NULL; | ||
3573 | success: | ||
3574 | failed_req_create: | ||
3575 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | ||
3576 | return retval; | 1999 | return retval; |
3577 | } | 2000 | } |
3578 | 2001 | ||
3579 | struct zfcp_fsf_req * | 2002 | static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat) |
3580 | zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, | ||
3581 | struct zfcp_unit *unit, | ||
3582 | u8 tm_flags, int req_flags) | ||
3583 | { | 2003 | { |
3584 | struct zfcp_fsf_req *fsf_req = NULL; | 2004 | lat_rec->sum += lat; |
3585 | int retval = 0; | 2005 | lat_rec->min = min(lat_rec->min, lat); |
3586 | struct fcp_cmnd_iu *fcp_cmnd_iu; | 2006 | lat_rec->max = max(lat_rec->max, lat); |
3587 | unsigned long lock_flags; | ||
3588 | volatile struct qdio_buffer_element *sbale; | ||
3589 | |||
3590 | /* setup new FSF request */ | ||
3591 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, | ||
3592 | adapter->pool.fsf_req_scsi, | ||
3593 | &lock_flags, &fsf_req); | ||
3594 | if (retval < 0) { | ||
3595 | ZFCP_LOG_INFO("error: Could not create FCP command (task " | ||
3596 | "management) request for adapter %s, port " | ||
3597 | " 0x%016Lx, unit 0x%016Lx.\n", | ||
3598 | zfcp_get_busid_by_adapter(adapter), | ||
3599 | unit->port->wwpn, unit->fcp_lun); | ||
3600 | goto out; | ||
3601 | } | ||
3602 | |||
3603 | if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
3604 | &unit->status))) | ||
3605 | goto unit_blocked; | ||
3606 | |||
3607 | /* | ||
3608 | * Used to decide on proper handler in the return path, | ||
3609 | * could be either zfcp_fsf_send_fcp_command_task_handler or | ||
3610 | * zfcp_fsf_send_fcp_command_task_management_handler */ | ||
3611 | |||
3612 | fsf_req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT; | ||
3613 | |||
3614 | /* | ||
3615 | * hold a pointer to the unit being target of this | ||
3616 | * task management request | ||
3617 | */ | ||
3618 | fsf_req->data = (unsigned long) unit; | ||
3619 | |||
3620 | /* set FSF related fields in QTCB */ | ||
3621 | fsf_req->qtcb->header.lun_handle = unit->handle; | ||
3622 | fsf_req->qtcb->header.port_handle = unit->port->handle; | ||
3623 | fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; | ||
3624 | fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT; | ||
3625 | fsf_req->qtcb->bottom.io.fcp_cmnd_length = | ||
3626 | sizeof (struct fcp_cmnd_iu) + sizeof (fcp_dl_t); | ||
3627 | |||
3628 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | ||
3629 | sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; | ||
3630 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
3631 | |||
3632 | /* set FCP related fields in FCP_CMND IU in QTCB */ | ||
3633 | fcp_cmnd_iu = (struct fcp_cmnd_iu *) | ||
3634 | &(fsf_req->qtcb->bottom.io.fcp_cmnd); | ||
3635 | fcp_cmnd_iu->fcp_lun = unit->fcp_lun; | ||
3636 | fcp_cmnd_iu->task_management_flags = tm_flags; | ||
3637 | |||
3638 | zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT); | ||
3639 | retval = zfcp_fsf_req_send(fsf_req); | ||
3640 | if (!retval) | ||
3641 | goto out; | ||
3642 | |||
3643 | unit_blocked: | ||
3644 | zfcp_fsf_req_free(fsf_req); | ||
3645 | fsf_req = NULL; | ||
3646 | |||
3647 | out: | ||
3648 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | ||
3649 | return fsf_req; | ||
3650 | } | 2007 | } |
3651 | 2008 | ||
3652 | /* | 2009 | static void zfcp_fsf_req_latency(struct zfcp_fsf_req *req) |
3653 | * function: zfcp_fsf_send_fcp_command_handler | ||
3654 | * | ||
3655 | * purpose: is called for finished Send FCP Command | ||
3656 | * | ||
3657 | * returns: | ||
3658 | */ | ||
3659 | static int | ||
3660 | zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) | ||
3661 | { | 2010 | { |
3662 | int retval = -EINVAL; | 2011 | struct fsf_qual_latency_info *lat_inf; |
3663 | struct zfcp_unit *unit; | 2012 | struct latency_cont *lat; |
3664 | struct fsf_qtcb_header *header; | 2013 | struct zfcp_unit *unit = req->unit; |
3665 | u16 subtable, rule, counter; | 2014 | unsigned long flags; |
3666 | |||
3667 | header = &fsf_req->qtcb->header; | ||
3668 | |||
3669 | if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)) | ||
3670 | unit = (struct zfcp_unit *) fsf_req->data; | ||
3671 | else | ||
3672 | unit = fsf_req->unit; | ||
3673 | |||
3674 | if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { | ||
3675 | /* go directly to calls of special handlers */ | ||
3676 | goto skip_fsfstatus; | ||
3677 | } | ||
3678 | |||
3679 | /* evaluate FSF status in QTCB */ | ||
3680 | switch (header->fsf_status) { | ||
3681 | |||
3682 | case FSF_PORT_HANDLE_NOT_VALID: | ||
3683 | ZFCP_LOG_INFO("Temporary port identifier 0x%x for port " | ||
3684 | "0x%016Lx on adapter %s invalid\n", | ||
3685 | unit->port->handle, | ||
3686 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | ||
3687 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3688 | (char *) &header->fsf_status_qual, | ||
3689 | sizeof (union fsf_status_qual)); | ||
3690 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 112, fsf_req); | ||
3691 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3692 | break; | ||
3693 | |||
3694 | case FSF_LUN_HANDLE_NOT_VALID: | ||
3695 | ZFCP_LOG_INFO("Temporary LUN identifier 0x%x for unit " | ||
3696 | "0x%016Lx on port 0x%016Lx on adapter %s is " | ||
3697 | "invalid. This may happen occasionally.\n", | ||
3698 | unit->handle, | ||
3699 | unit->fcp_lun, | ||
3700 | unit->port->wwpn, | ||
3701 | zfcp_get_busid_by_unit(unit)); | ||
3702 | ZFCP_LOG_NORMAL("Status qualifier data:\n"); | ||
3703 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, | ||
3704 | (char *) &header->fsf_status_qual, | ||
3705 | sizeof (union fsf_status_qual)); | ||
3706 | zfcp_erp_port_reopen(unit->port, 0, 113, fsf_req); | ||
3707 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3708 | break; | ||
3709 | |||
3710 | case FSF_HANDLE_MISMATCH: | ||
3711 | ZFCP_LOG_NORMAL("bug: The port handle 0x%x has changed " | ||
3712 | "unexpectedly. (adapter %s, port 0x%016Lx, " | ||
3713 | "unit 0x%016Lx)\n", | ||
3714 | unit->port->handle, | ||
3715 | zfcp_get_busid_by_unit(unit), | ||
3716 | unit->port->wwpn, | ||
3717 | unit->fcp_lun); | ||
3718 | ZFCP_LOG_NORMAL("status qualifier:\n"); | ||
3719 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, | ||
3720 | (char *) &header->fsf_status_qual, | ||
3721 | sizeof (union fsf_status_qual)); | ||
3722 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 114, fsf_req); | ||
3723 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3724 | break; | ||
3725 | |||
3726 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: | ||
3727 | ZFCP_LOG_INFO("error: adapter %s does not support fc " | ||
3728 | "class %d.\n", | ||
3729 | zfcp_get_busid_by_unit(unit), | ||
3730 | ZFCP_FC_SERVICE_CLASS_DEFAULT); | ||
3731 | /* stop operation for this adapter */ | ||
3732 | zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 132, fsf_req); | ||
3733 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3734 | break; | ||
3735 | |||
3736 | case FSF_FCPLUN_NOT_VALID: | ||
3737 | ZFCP_LOG_NORMAL("bug: unit 0x%016Lx on port 0x%016Lx on " | ||
3738 | "adapter %s does not have correct unit " | ||
3739 | "handle 0x%x\n", | ||
3740 | unit->fcp_lun, | ||
3741 | unit->port->wwpn, | ||
3742 | zfcp_get_busid_by_unit(unit), | ||
3743 | unit->handle); | ||
3744 | ZFCP_LOG_DEBUG("status qualifier:\n"); | ||
3745 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3746 | (char *) &header->fsf_status_qual, | ||
3747 | sizeof (union fsf_status_qual)); | ||
3748 | zfcp_erp_port_reopen(unit->port, 0, 115, fsf_req); | ||
3749 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3750 | break; | ||
3751 | |||
3752 | case FSF_ACCESS_DENIED: | ||
3753 | ZFCP_LOG_NORMAL("Access denied, cannot send FCP command to " | ||
3754 | "unit 0x%016Lx on port 0x%016Lx on " | ||
3755 | "adapter %s\n", unit->fcp_lun, unit->port->wwpn, | ||
3756 | zfcp_get_busid_by_unit(unit)); | ||
3757 | for (counter = 0; counter < 2; counter++) { | ||
3758 | subtable = header->fsf_status_qual.halfword[counter * 2]; | ||
3759 | rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | ||
3760 | switch (subtable) { | ||
3761 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
3762 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
3763 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
3764 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
3765 | ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | ||
3766 | zfcp_act_subtable_type[subtable], rule); | ||
3767 | break; | ||
3768 | } | ||
3769 | } | ||
3770 | zfcp_erp_unit_access_denied(unit, 61, fsf_req); | ||
3771 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3772 | break; | ||
3773 | |||
3774 | case FSF_DIRECTION_INDICATOR_NOT_VALID: | ||
3775 | ZFCP_LOG_INFO("bug: Invalid data direction given for unit " | ||
3776 | "0x%016Lx on port 0x%016Lx on adapter %s " | ||
3777 | "(debug info %d)\n", | ||
3778 | unit->fcp_lun, | ||
3779 | unit->port->wwpn, | ||
3780 | zfcp_get_busid_by_unit(unit), | ||
3781 | fsf_req->qtcb->bottom.io.data_direction); | ||
3782 | /* stop operation for this adapter */ | ||
3783 | zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, fsf_req); | ||
3784 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3785 | break; | ||
3786 | |||
3787 | case FSF_CMND_LENGTH_NOT_VALID: | ||
3788 | ZFCP_LOG_NORMAL | ||
3789 | ("bug: An invalid control-data-block length field " | ||
3790 | "was found in a command for unit 0x%016Lx on port " | ||
3791 | "0x%016Lx on adapter %s " "(debug info %d)\n", | ||
3792 | unit->fcp_lun, unit->port->wwpn, | ||
3793 | zfcp_get_busid_by_unit(unit), | ||
3794 | fsf_req->qtcb->bottom.io.fcp_cmnd_length); | ||
3795 | /* stop operation for this adapter */ | ||
3796 | zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, fsf_req); | ||
3797 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3798 | break; | ||
3799 | 2015 | ||
3800 | case FSF_PORT_BOXED: | 2016 | lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info; |
3801 | ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s " | ||
3802 | "needs to be reopened\n", | ||
3803 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | ||
3804 | zfcp_erp_port_boxed(unit->port, 53, fsf_req); | ||
3805 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | ||
3806 | ZFCP_STATUS_FSFREQ_RETRY; | ||
3807 | break; | ||
3808 | 2017 | ||
3809 | case FSF_LUN_BOXED: | 2018 | switch (req->qtcb->bottom.io.data_direction) { |
3810 | ZFCP_LOG_NORMAL("unit needs to be reopened (adapter %s, " | 2019 | case FSF_DATADIR_READ: |
3811 | "wwpn=0x%016Lx, fcp_lun=0x%016Lx)\n", | 2020 | lat = &unit->latencies.read; |
3812 | zfcp_get_busid_by_unit(unit), | ||
3813 | unit->port->wwpn, unit->fcp_lun); | ||
3814 | zfcp_erp_unit_boxed(unit, 54, fsf_req); | ||
3815 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ||
3816 | | ZFCP_STATUS_FSFREQ_RETRY; | ||
3817 | break; | ||
3818 | |||
3819 | case FSF_ADAPTER_STATUS_AVAILABLE: | ||
3820 | switch (header->fsf_status_qual.word[0]) { | ||
3821 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | ||
3822 | /* re-establish link to port */ | ||
3823 | zfcp_test_link(unit->port); | ||
3824 | break; | ||
3825 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | ||
3826 | /* FIXME(hw) need proper specs for proper action */ | ||
3827 | /* let scsi stack deal with retries and escalation */ | ||
3828 | break; | ||
3829 | default: | ||
3830 | ZFCP_LOG_NORMAL | ||
3831 | ("Unknown status qualifier 0x%x arrived.\n", | ||
3832 | header->fsf_status_qual.word[0]); | ||
3833 | break; | ||
3834 | } | ||
3835 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3836 | break; | 2021 | break; |
3837 | 2022 | case FSF_DATADIR_WRITE: | |
3838 | case FSF_GOOD: | 2023 | lat = &unit->latencies.write; |
3839 | break; | 2024 | break; |
3840 | 2025 | case FSF_DATADIR_CMND: | |
3841 | case FSF_FCP_RSP_AVAILABLE: | 2026 | lat = &unit->latencies.cmd; |
3842 | break; | 2027 | break; |
2028 | default: | ||
2029 | return; | ||
3843 | } | 2030 | } |
3844 | 2031 | ||
3845 | skip_fsfstatus: | 2032 | spin_lock_irqsave(&unit->latencies.lock, flags); |
3846 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) { | 2033 | zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat); |
3847 | retval = | 2034 | zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat); |
3848 | zfcp_fsf_send_fcp_command_task_management_handler(fsf_req); | 2035 | lat->counter++; |
3849 | } else { | 2036 | spin_unlock_irqrestore(&unit->latencies.lock, flags); |
3850 | retval = zfcp_fsf_send_fcp_command_task_handler(fsf_req); | ||
3851 | fsf_req->unit = NULL; | ||
3852 | zfcp_unit_put(unit); | ||
3853 | } | ||
3854 | return retval; | ||
3855 | } | 2037 | } |
3856 | 2038 | ||
3857 | /* | 2039 | static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) |
3858 | * function: zfcp_fsf_send_fcp_command_task_handler | ||
3859 | * | ||
3860 | * purpose: evaluates FCP_RSP IU | ||
3861 | * | ||
3862 | * returns: | ||
3863 | */ | ||
3864 | static int | ||
3865 | zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) | ||
3866 | { | 2040 | { |
3867 | int retval = 0; | 2041 | struct scsi_cmnd *scpnt = req->data; |
3868 | struct scsi_cmnd *scpnt; | ||
3869 | struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) | 2042 | struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) |
3870 | &(fsf_req->qtcb->bottom.io.fcp_rsp); | 2043 | &(req->qtcb->bottom.io.fcp_rsp); |
3871 | struct fcp_cmnd_iu *fcp_cmnd_iu = (struct fcp_cmnd_iu *) | ||
3872 | &(fsf_req->qtcb->bottom.io.fcp_cmnd); | ||
3873 | u32 sns_len; | 2044 | u32 sns_len; |
3874 | char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu); | 2045 | char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; |
3875 | unsigned long flags; | 2046 | unsigned long flags; |
3876 | struct zfcp_unit *unit = fsf_req->unit; | 2047 | |
3877 | 2048 | if (unlikely(!scpnt)) | |
3878 | read_lock_irqsave(&fsf_req->adapter->abort_lock, flags); | 2049 | return; |
3879 | scpnt = (struct scsi_cmnd *) fsf_req->data; | 2050 | |
3880 | if (unlikely(!scpnt)) { | 2051 | read_lock_irqsave(&req->adapter->abort_lock, flags); |
3881 | ZFCP_LOG_DEBUG | 2052 | |
3882 | ("Command with fsf_req %p is not associated to " | 2053 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) { |
3883 | "a scsi command anymore. Aborted?\n", fsf_req); | 2054 | set_host_byte(scpnt, DID_SOFT_ERROR); |
3884 | goto out; | 2055 | set_driver_byte(scpnt, SUGGEST_RETRY); |
3885 | } | ||
3886 | if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED)) { | ||
3887 | /* FIXME: (design) mid-layer should handle DID_ABORT like | ||
3888 | * DID_SOFT_ERROR by retrying the request for devices | ||
3889 | * that allow retries. | ||
3890 | */ | ||
3891 | ZFCP_LOG_DEBUG("Setting DID_SOFT_ERROR and SUGGEST_RETRY\n"); | ||
3892 | set_host_byte(&scpnt->result, DID_SOFT_ERROR); | ||
3893 | set_driver_byte(&scpnt->result, SUGGEST_RETRY); | ||
3894 | goto skip_fsfstatus; | 2056 | goto skip_fsfstatus; |
3895 | } | 2057 | } |
3896 | 2058 | ||
3897 | if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { | 2059 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { |
3898 | ZFCP_LOG_DEBUG("Setting DID_ERROR\n"); | 2060 | set_host_byte(scpnt, DID_ERROR); |
3899 | set_host_byte(&scpnt->result, DID_ERROR); | ||
3900 | goto skip_fsfstatus; | 2061 | goto skip_fsfstatus; |
3901 | } | 2062 | } |
3902 | 2063 | ||
3903 | /* set message byte of result in SCSI command */ | 2064 | set_msg_byte(scpnt, COMMAND_COMPLETE); |
3904 | scpnt->result |= COMMAND_COMPLETE << 8; | ||
3905 | 2065 | ||
3906 | /* | ||
3907 | * copy SCSI status code of FCP_STATUS of FCP_RSP IU to status byte | ||
3908 | * of result in SCSI command | ||
3909 | */ | ||
3910 | scpnt->result |= fcp_rsp_iu->scsi_status; | 2066 | scpnt->result |= fcp_rsp_iu->scsi_status; |
3911 | if (unlikely(fcp_rsp_iu->scsi_status)) { | ||
3912 | /* DEBUG */ | ||
3913 | ZFCP_LOG_DEBUG("status for SCSI Command:\n"); | ||
3914 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3915 | scpnt->cmnd, scpnt->cmd_len); | ||
3916 | ZFCP_LOG_DEBUG("SCSI status code 0x%x\n", | ||
3917 | fcp_rsp_iu->scsi_status); | ||
3918 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3919 | (void *) fcp_rsp_iu, sizeof (struct fcp_rsp_iu)); | ||
3920 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3921 | zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), | ||
3922 | fcp_rsp_iu->fcp_sns_len); | ||
3923 | } | ||
3924 | 2067 | ||
3925 | /* check FCP_RSP_INFO */ | 2068 | if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) |
2069 | zfcp_fsf_req_latency(req); | ||
2070 | |||
3926 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { | 2071 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { |
3927 | ZFCP_LOG_DEBUG("rsp_len is valid\n"); | 2072 | if (fcp_rsp_info[3] == RSP_CODE_GOOD) |
3928 | switch (fcp_rsp_info[3]) { | 2073 | set_host_byte(scpnt, DID_OK); |
3929 | case RSP_CODE_GOOD: | 2074 | else { |
3930 | /* ok, continue */ | 2075 | set_host_byte(scpnt, DID_ERROR); |
3931 | ZFCP_LOG_TRACE("no failure or Task Management " | ||
3932 | "Function complete\n"); | ||
3933 | set_host_byte(&scpnt->result, DID_OK); | ||
3934 | break; | ||
3935 | case RSP_CODE_LENGTH_MISMATCH: | ||
3936 | /* hardware bug */ | ||
3937 | ZFCP_LOG_NORMAL("bug: FCP response code indictates " | ||
3938 | "that the fibrechannel protocol data " | ||
3939 | "length differs from the burst length. " | ||
3940 | "The problem occured on unit 0x%016Lx " | ||
3941 | "on port 0x%016Lx on adapter %s", | ||
3942 | unit->fcp_lun, | ||
3943 | unit->port->wwpn, | ||
3944 | zfcp_get_busid_by_unit(unit)); | ||
3945 | /* dump SCSI CDB as prepared by zfcp */ | ||
3946 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3947 | (char *) &fsf_req->qtcb-> | ||
3948 | bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); | ||
3949 | set_host_byte(&scpnt->result, DID_ERROR); | ||
3950 | goto skip_fsfstatus; | ||
3951 | case RSP_CODE_FIELD_INVALID: | ||
3952 | /* driver or hardware bug */ | ||
3953 | ZFCP_LOG_NORMAL("bug: FCP response code indictates " | ||
3954 | "that the fibrechannel protocol data " | ||
3955 | "fields were incorrectly set up. " | ||
3956 | "The problem occured on the unit " | ||
3957 | "0x%016Lx on port 0x%016Lx on " | ||
3958 | "adapter %s", | ||
3959 | unit->fcp_lun, | ||
3960 | unit->port->wwpn, | ||
3961 | zfcp_get_busid_by_unit(unit)); | ||
3962 | /* dump SCSI CDB as prepared by zfcp */ | ||
3963 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3964 | (char *) &fsf_req->qtcb-> | ||
3965 | bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); | ||
3966 | set_host_byte(&scpnt->result, DID_ERROR); | ||
3967 | goto skip_fsfstatus; | ||
3968 | case RSP_CODE_RO_MISMATCH: | ||
3969 | /* hardware bug */ | ||
3970 | ZFCP_LOG_NORMAL("bug: The FCP response code indicates " | ||
3971 | "that conflicting values for the " | ||
3972 | "fibrechannel payload offset from the " | ||
3973 | "header were found. " | ||
3974 | "The problem occured on unit 0x%016Lx " | ||
3975 | "on port 0x%016Lx on adapter %s.\n", | ||
3976 | unit->fcp_lun, | ||
3977 | unit->port->wwpn, | ||
3978 | zfcp_get_busid_by_unit(unit)); | ||
3979 | /* dump SCSI CDB as prepared by zfcp */ | ||
3980 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3981 | (char *) &fsf_req->qtcb-> | ||
3982 | bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); | ||
3983 | set_host_byte(&scpnt->result, DID_ERROR); | ||
3984 | goto skip_fsfstatus; | ||
3985 | default: | ||
3986 | ZFCP_LOG_NORMAL("bug: An invalid FCP response " | ||
3987 | "code was detected for a command. " | ||
3988 | "The problem occured on the unit " | ||
3989 | "0x%016Lx on port 0x%016Lx on " | ||
3990 | "adapter %s (debug info 0x%x)\n", | ||
3991 | unit->fcp_lun, | ||
3992 | unit->port->wwpn, | ||
3993 | zfcp_get_busid_by_unit(unit), | ||
3994 | fcp_rsp_info[3]); | ||
3995 | /* dump SCSI CDB as prepared by zfcp */ | ||
3996 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3997 | (char *) &fsf_req->qtcb-> | ||
3998 | bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); | ||
3999 | set_host_byte(&scpnt->result, DID_ERROR); | ||
4000 | goto skip_fsfstatus; | 2076 | goto skip_fsfstatus; |
4001 | } | 2077 | } |
4002 | } | 2078 | } |
4003 | 2079 | ||
4004 | /* check for sense data */ | ||
4005 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) { | 2080 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) { |
4006 | sns_len = FSF_FCP_RSP_SIZE - | 2081 | sns_len = FSF_FCP_RSP_SIZE - sizeof(struct fcp_rsp_iu) + |
4007 | sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len; | 2082 | fcp_rsp_iu->fcp_rsp_len; |
4008 | ZFCP_LOG_TRACE("room for %i bytes sense data in QTCB\n", | ||
4009 | sns_len); | ||
4010 | sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE); | 2083 | sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE); |
4011 | ZFCP_LOG_TRACE("room for %i bytes sense data in SCSI command\n", | ||
4012 | SCSI_SENSE_BUFFERSIZE); | ||
4013 | sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len); | 2084 | sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len); |
4014 | ZFCP_LOG_TRACE("scpnt->result =0x%x, command was:\n", | ||
4015 | scpnt->result); | ||
4016 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, | ||
4017 | scpnt->cmnd, scpnt->cmd_len); | ||
4018 | 2085 | ||
4019 | ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n", | ||
4020 | fcp_rsp_iu->fcp_sns_len); | ||
4021 | memcpy(scpnt->sense_buffer, | 2086 | memcpy(scpnt->sense_buffer, |
4022 | zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len); | 2087 | zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len); |
4023 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, | ||
4024 | (void *)scpnt->sense_buffer, sns_len); | ||
4025 | } | ||
4026 | |||
4027 | /* check for overrun */ | ||
4028 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_over)) { | ||
4029 | ZFCP_LOG_INFO("A data overrun was detected for a command. " | ||
4030 | "unit 0x%016Lx, port 0x%016Lx, adapter %s. " | ||
4031 | "The response data length is " | ||
4032 | "%d, the original length was %d.\n", | ||
4033 | unit->fcp_lun, | ||
4034 | unit->port->wwpn, | ||
4035 | zfcp_get_busid_by_unit(unit), | ||
4036 | fcp_rsp_iu->fcp_resid, | ||
4037 | (int) zfcp_get_fcp_dl(fcp_cmnd_iu)); | ||
4038 | } | 2088 | } |
4039 | 2089 | ||
4040 | /* check for underrun */ | ||
4041 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) { | 2090 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) { |
4042 | ZFCP_LOG_INFO("A data underrun was detected for a command. " | ||
4043 | "unit 0x%016Lx, port 0x%016Lx, adapter %s. " | ||
4044 | "The response data length is " | ||
4045 | "%d, the original length was %d.\n", | ||
4046 | unit->fcp_lun, | ||
4047 | unit->port->wwpn, | ||
4048 | zfcp_get_busid_by_unit(unit), | ||
4049 | fcp_rsp_iu->fcp_resid, | ||
4050 | (int) zfcp_get_fcp_dl(fcp_cmnd_iu)); | ||
4051 | |||
4052 | scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid); | 2091 | scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid); |
4053 | if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) < | 2092 | if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) < |
4054 | scpnt->underflow) | 2093 | scpnt->underflow) |
4055 | set_host_byte(&scpnt->result, DID_ERROR); | 2094 | set_host_byte(scpnt, DID_ERROR); |
4056 | } | 2095 | } |
4057 | 2096 | skip_fsfstatus: | |
4058 | skip_fsfstatus: | ||
4059 | ZFCP_LOG_DEBUG("scpnt->result =0x%x\n", scpnt->result); | ||
4060 | |||
4061 | if (scpnt->result != 0) | 2097 | if (scpnt->result != 0) |
4062 | zfcp_scsi_dbf_event_result("erro", 3, fsf_req->adapter, scpnt, fsf_req); | 2098 | zfcp_scsi_dbf_event_result("erro", 3, req->adapter, scpnt, req); |
4063 | else if (scpnt->retries > 0) | 2099 | else if (scpnt->retries > 0) |
4064 | zfcp_scsi_dbf_event_result("retr", 4, fsf_req->adapter, scpnt, fsf_req); | 2100 | zfcp_scsi_dbf_event_result("retr", 4, req->adapter, scpnt, req); |
4065 | else | 2101 | else |
4066 | zfcp_scsi_dbf_event_result("norm", 6, fsf_req->adapter, scpnt, fsf_req); | 2102 | zfcp_scsi_dbf_event_result("norm", 6, req->adapter, scpnt, req); |
4067 | 2103 | ||
4068 | /* cleanup pointer (need this especially for abort) */ | ||
4069 | scpnt->host_scribble = NULL; | 2104 | scpnt->host_scribble = NULL; |
4070 | |||
4071 | /* always call back */ | ||
4072 | (scpnt->scsi_done) (scpnt); | 2105 | (scpnt->scsi_done) (scpnt); |
4073 | |||
4074 | /* | 2106 | /* |
4075 | * We must hold this lock until scsi_done has been called. | 2107 | * We must hold this lock until scsi_done has been called. |
4076 | * Otherwise we may call scsi_done after abort regarding this | 2108 | * Otherwise we may call scsi_done after abort regarding this |
4077 | * command has completed. | 2109 | * command has completed. |
4078 | * Note: scsi_done must not block! | 2110 | * Note: scsi_done must not block! |
4079 | */ | 2111 | */ |
4080 | out: | 2112 | read_unlock_irqrestore(&req->adapter->abort_lock, flags); |
4081 | read_unlock_irqrestore(&fsf_req->adapter->abort_lock, flags); | ||
4082 | return retval; | ||
4083 | } | 2113 | } |
4084 | 2114 | ||
4085 | /* | 2115 | static void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req) |
4086 | * function: zfcp_fsf_send_fcp_command_task_management_handler | ||
4087 | * | ||
4088 | * purpose: evaluates FCP_RSP IU | ||
4089 | * | ||
4090 | * returns: | ||
4091 | */ | ||
4092 | static int | ||
4093 | zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req) | ||
4094 | { | 2116 | { |
4095 | int retval = 0; | ||
4096 | struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) | 2117 | struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) |
4097 | &(fsf_req->qtcb->bottom.io.fcp_rsp); | 2118 | &(req->qtcb->bottom.io.fcp_rsp); |
4098 | char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu); | 2119 | char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; |
4099 | struct zfcp_unit *unit = (struct zfcp_unit *) fsf_req->data; | ||
4100 | |||
4101 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
4102 | fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; | ||
4103 | goto skip_fsfstatus; | ||
4104 | } | ||
4105 | 2120 | ||
4106 | /* check FCP_RSP_INFO */ | 2121 | if ((fcp_rsp_info[3] != RSP_CODE_GOOD) || |
4107 | switch (fcp_rsp_info[3]) { | 2122 | (req->status & ZFCP_STATUS_FSFREQ_ERROR)) |
4108 | case RSP_CODE_GOOD: | 2123 | req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; |
4109 | /* ok, continue */ | ||
4110 | ZFCP_LOG_DEBUG("no failure or Task Management " | ||
4111 | "Function complete\n"); | ||
4112 | break; | ||
4113 | case RSP_CODE_TASKMAN_UNSUPP: | ||
4114 | ZFCP_LOG_NORMAL("bug: A reuested task management function " | ||
4115 | "is not supported on the target device " | ||
4116 | "unit 0x%016Lx, port 0x%016Lx, adapter %s\n ", | ||
4117 | unit->fcp_lun, | ||
4118 | unit->port->wwpn, | ||
4119 | zfcp_get_busid_by_unit(unit)); | ||
4120 | fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP; | ||
4121 | break; | ||
4122 | case RSP_CODE_TASKMAN_FAILED: | ||
4123 | ZFCP_LOG_NORMAL("bug: A reuested task management function " | ||
4124 | "failed to complete successfully. " | ||
4125 | "unit 0x%016Lx, port 0x%016Lx, adapter %s.\n", | ||
4126 | unit->fcp_lun, | ||
4127 | unit->port->wwpn, | ||
4128 | zfcp_get_busid_by_unit(unit)); | ||
4129 | fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; | ||
4130 | break; | ||
4131 | default: | ||
4132 | ZFCP_LOG_NORMAL("bug: An invalid FCP response " | ||
4133 | "code was detected for a command. " | ||
4134 | "unit 0x%016Lx, port 0x%016Lx, adapter %s " | ||
4135 | "(debug info 0x%x)\n", | ||
4136 | unit->fcp_lun, | ||
4137 | unit->port->wwpn, | ||
4138 | zfcp_get_busid_by_unit(unit), | ||
4139 | fcp_rsp_info[3]); | ||
4140 | fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; | ||
4141 | } | ||
4142 | |||
4143 | skip_fsfstatus: | ||
4144 | return retval; | ||
4145 | } | 2124 | } |
4146 | 2125 | ||
4147 | 2126 | ||
4148 | /* | 2127 | static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req) |
4149 | * function: zfcp_fsf_control_file | ||
4150 | * | ||
4151 | * purpose: Initiator of the control file upload/download FSF requests | ||
4152 | * | ||
4153 | * returns: 0 - FSF request is successfuly created and queued | ||
4154 | * -EOPNOTSUPP - The FCP adapter does not have Control File support | ||
4155 | * -EINVAL - Invalid direction specified | ||
4156 | * -ENOMEM - Insufficient memory | ||
4157 | * -EPERM - Cannot create FSF request or place it in QDIO queue | ||
4158 | */ | ||
4159 | int | ||
4160 | zfcp_fsf_control_file(struct zfcp_adapter *adapter, | ||
4161 | struct zfcp_fsf_req **fsf_req_ptr, | ||
4162 | u32 fsf_command, | ||
4163 | u32 option, | ||
4164 | struct zfcp_sg_list *sg_list) | ||
4165 | { | 2128 | { |
4166 | struct zfcp_fsf_req *fsf_req; | 2129 | struct zfcp_unit *unit; |
4167 | struct fsf_qtcb_bottom_support *bottom; | 2130 | struct fsf_qtcb_header *header = &req->qtcb->header; |
4168 | volatile struct qdio_buffer_element *sbale; | ||
4169 | unsigned long lock_flags; | ||
4170 | int req_flags = 0; | ||
4171 | int direction; | ||
4172 | int retval = 0; | ||
4173 | |||
4174 | if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) { | ||
4175 | ZFCP_LOG_INFO("cfdc not supported (adapter %s)\n", | ||
4176 | zfcp_get_busid_by_adapter(adapter)); | ||
4177 | retval = -EOPNOTSUPP; | ||
4178 | goto out; | ||
4179 | } | ||
4180 | |||
4181 | switch (fsf_command) { | ||
4182 | |||
4183 | case FSF_QTCB_DOWNLOAD_CONTROL_FILE: | ||
4184 | direction = SBAL_FLAGS0_TYPE_WRITE; | ||
4185 | if ((option != FSF_CFDC_OPTION_FULL_ACCESS) && | ||
4186 | (option != FSF_CFDC_OPTION_RESTRICTED_ACCESS)) | ||
4187 | req_flags = ZFCP_WAIT_FOR_SBAL; | ||
4188 | break; | ||
4189 | |||
4190 | case FSF_QTCB_UPLOAD_CONTROL_FILE: | ||
4191 | direction = SBAL_FLAGS0_TYPE_READ; | ||
4192 | break; | ||
4193 | |||
4194 | default: | ||
4195 | ZFCP_LOG_INFO("Invalid FSF command code 0x%08x\n", fsf_command); | ||
4196 | retval = -EINVAL; | ||
4197 | goto out; | ||
4198 | } | ||
4199 | |||
4200 | retval = zfcp_fsf_req_create(adapter, fsf_command, req_flags, | ||
4201 | NULL, &lock_flags, &fsf_req); | ||
4202 | if (retval < 0) { | ||
4203 | ZFCP_LOG_INFO("error: Could not create FSF request for the " | ||
4204 | "adapter %s\n", | ||
4205 | zfcp_get_busid_by_adapter(adapter)); | ||
4206 | retval = -EPERM; | ||
4207 | goto unlock_queue_lock; | ||
4208 | } | ||
4209 | |||
4210 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | ||
4211 | sbale[0].flags |= direction; | ||
4212 | |||
4213 | bottom = &fsf_req->qtcb->bottom.support; | ||
4214 | bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; | ||
4215 | bottom->option = option; | ||
4216 | |||
4217 | if (sg_list->count > 0) { | ||
4218 | int bytes; | ||
4219 | |||
4220 | bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction, | ||
4221 | sg_list->sg, sg_list->count, | ||
4222 | ZFCP_MAX_SBALS_PER_REQ); | ||
4223 | if (bytes != ZFCP_CFDC_MAX_CONTROL_FILE_SIZE) { | ||
4224 | ZFCP_LOG_INFO( | ||
4225 | "error: Could not create sufficient number of " | ||
4226 | "SBALS for an FSF request to the adapter %s\n", | ||
4227 | zfcp_get_busid_by_adapter(adapter)); | ||
4228 | retval = -ENOMEM; | ||
4229 | goto free_fsf_req; | ||
4230 | } | ||
4231 | } else | ||
4232 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
4233 | |||
4234 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | ||
4235 | retval = zfcp_fsf_req_send(fsf_req); | ||
4236 | if (retval < 0) { | ||
4237 | ZFCP_LOG_INFO("initiation of cfdc up/download failed" | ||
4238 | "(adapter %s)\n", | ||
4239 | zfcp_get_busid_by_adapter(adapter)); | ||
4240 | retval = -EPERM; | ||
4241 | goto free_fsf_req; | ||
4242 | } | ||
4243 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | ||
4244 | |||
4245 | ZFCP_LOG_NORMAL("Control file %s FSF request has been sent to the " | ||
4246 | "adapter %s\n", | ||
4247 | fsf_command == FSF_QTCB_DOWNLOAD_CONTROL_FILE ? | ||
4248 | "download" : "upload", | ||
4249 | zfcp_get_busid_by_adapter(adapter)); | ||
4250 | |||
4251 | wait_event(fsf_req->completion_wq, | ||
4252 | fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | ||
4253 | |||
4254 | *fsf_req_ptr = fsf_req; | ||
4255 | goto out; | ||
4256 | |||
4257 | free_fsf_req: | ||
4258 | zfcp_fsf_req_free(fsf_req); | ||
4259 | unlock_queue_lock: | ||
4260 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | ||
4261 | out: | ||
4262 | return retval; | ||
4263 | } | ||
4264 | |||
4265 | 2131 | ||
4266 | /* | 2132 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)) |
4267 | * function: zfcp_fsf_control_file_handler | 2133 | unit = req->data; |
4268 | * | 2134 | else |
4269 | * purpose: Handler of the control file upload/download FSF requests | 2135 | unit = req->unit; |
4270 | * | ||
4271 | * returns: 0 - FSF request successfuly processed | ||
4272 | * -EAGAIN - Operation has to be repeated because of a temporary problem | ||
4273 | * -EACCES - There is no permission to execute an operation | ||
4274 | * -EPERM - The control file is not in a right format | ||
4275 | * -EIO - There is a problem with the FCP adapter | ||
4276 | * -EINVAL - Invalid operation | ||
4277 | * -EFAULT - User space memory I/O operation fault | ||
4278 | */ | ||
4279 | static int | ||
4280 | zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req) | ||
4281 | { | ||
4282 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
4283 | struct fsf_qtcb_header *header = &fsf_req->qtcb->header; | ||
4284 | struct fsf_qtcb_bottom_support *bottom = &fsf_req->qtcb->bottom.support; | ||
4285 | int retval = 0; | ||
4286 | 2136 | ||
4287 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | 2137 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) |
4288 | retval = -EINVAL; | ||
4289 | goto skip_fsfstatus; | 2138 | goto skip_fsfstatus; |
4290 | } | ||
4291 | 2139 | ||
4292 | switch (header->fsf_status) { | 2140 | switch (header->fsf_status) { |
4293 | 2141 | case FSF_HANDLE_MISMATCH: | |
4294 | case FSF_GOOD: | 2142 | case FSF_PORT_HANDLE_NOT_VALID: |
4295 | ZFCP_LOG_NORMAL( | 2143 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 112, req); |
4296 | "The FSF request has been successfully completed " | 2144 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
4297 | "on the adapter %s\n", | ||
4298 | zfcp_get_busid_by_adapter(adapter)); | ||
4299 | break; | ||
4300 | |||
4301 | case FSF_OPERATION_PARTIALLY_SUCCESSFUL: | ||
4302 | if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) { | ||
4303 | switch (header->fsf_status_qual.word[0]) { | ||
4304 | |||
4305 | case FSF_SQ_CFDC_HARDENED_ON_SE: | ||
4306 | ZFCP_LOG_NORMAL( | ||
4307 | "CFDC on the adapter %s has being " | ||
4308 | "hardened on primary and secondary SE\n", | ||
4309 | zfcp_get_busid_by_adapter(adapter)); | ||
4310 | break; | ||
4311 | |||
4312 | case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE: | ||
4313 | ZFCP_LOG_NORMAL( | ||
4314 | "CFDC of the adapter %s could not " | ||
4315 | "be saved on the SE\n", | ||
4316 | zfcp_get_busid_by_adapter(adapter)); | ||
4317 | break; | ||
4318 | |||
4319 | case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2: | ||
4320 | ZFCP_LOG_NORMAL( | ||
4321 | "CFDC of the adapter %s could not " | ||
4322 | "be copied to the secondary SE\n", | ||
4323 | zfcp_get_busid_by_adapter(adapter)); | ||
4324 | break; | ||
4325 | |||
4326 | default: | ||
4327 | ZFCP_LOG_NORMAL( | ||
4328 | "CFDC could not be hardened " | ||
4329 | "on the adapter %s\n", | ||
4330 | zfcp_get_busid_by_adapter(adapter)); | ||
4331 | } | ||
4332 | } | ||
4333 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4334 | retval = -EAGAIN; | ||
4335 | break; | ||
4336 | |||
4337 | case FSF_AUTHORIZATION_FAILURE: | ||
4338 | ZFCP_LOG_NORMAL( | ||
4339 | "Adapter %s does not accept privileged commands\n", | ||
4340 | zfcp_get_busid_by_adapter(adapter)); | ||
4341 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4342 | retval = -EACCES; | ||
4343 | break; | 2145 | break; |
4344 | 2146 | case FSF_FCPLUN_NOT_VALID: | |
4345 | case FSF_CFDC_ERROR_DETECTED: | 2147 | case FSF_LUN_HANDLE_NOT_VALID: |
4346 | ZFCP_LOG_NORMAL( | 2148 | zfcp_erp_port_reopen(unit->port, 0, 113, req); |
4347 | "Error at position %d in the CFDC, " | 2149 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
4348 | "CFDC is discarded by the adapter %s\n", | ||
4349 | header->fsf_status_qual.word[0], | ||
4350 | zfcp_get_busid_by_adapter(adapter)); | ||
4351 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4352 | retval = -EPERM; | ||
4353 | break; | 2150 | break; |
4354 | 2151 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: | |
4355 | case FSF_CONTROL_FILE_UPDATE_ERROR: | 2152 | zfcp_fsf_class_not_supp(req); |
4356 | ZFCP_LOG_NORMAL( | ||
4357 | "Adapter %s cannot harden the control file, " | ||
4358 | "file is discarded\n", | ||
4359 | zfcp_get_busid_by_adapter(adapter)); | ||
4360 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4361 | retval = -EIO; | ||
4362 | break; | 2153 | break; |
4363 | 2154 | case FSF_ACCESS_DENIED: | |
4364 | case FSF_CONTROL_FILE_TOO_LARGE: | 2155 | zfcp_fsf_access_denied_unit(req, unit); |
4365 | ZFCP_LOG_NORMAL( | ||
4366 | "Control file is too large, file is discarded " | ||
4367 | "by the adapter %s\n", | ||
4368 | zfcp_get_busid_by_adapter(adapter)); | ||
4369 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4370 | retval = -EIO; | ||
4371 | break; | 2156 | break; |
4372 | 2157 | case FSF_DIRECTION_INDICATOR_NOT_VALID: | |
4373 | case FSF_ACCESS_CONFLICT_DETECTED: | 2158 | dev_err(&req->adapter->ccw_device->dev, |
4374 | if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) | 2159 | "Invalid data direction (%d) given for unit " |
4375 | ZFCP_LOG_NORMAL( | 2160 | "0x%016Lx on port 0x%016Lx, shutting down " |
4376 | "CFDC has been discarded by the adapter %s, " | 2161 | "adapter.\n", |
4377 | "because activation would impact " | 2162 | req->qtcb->bottom.io.data_direction, |
4378 | "%d active connection(s)\n", | 2163 | unit->fcp_lun, unit->port->wwpn); |
4379 | zfcp_get_busid_by_adapter(adapter), | 2164 | zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, req); |
4380 | header->fsf_status_qual.word[0]); | 2165 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
4381 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4382 | retval = -EIO; | ||
4383 | break; | 2166 | break; |
4384 | 2167 | case FSF_CMND_LENGTH_NOT_VALID: | |
4385 | case FSF_CONFLICTS_OVERRULED: | 2168 | dev_err(&req->adapter->ccw_device->dev, |
4386 | if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) | 2169 | "An invalid control-data-block length field (%d) " |
4387 | ZFCP_LOG_NORMAL( | 2170 | "was found in a command for unit 0x%016Lx on port " |
4388 | "CFDC has been activated on the adapter %s, " | 2171 | "0x%016Lx. Shutting down adapter.\n", |
4389 | "but activation has impacted " | 2172 | req->qtcb->bottom.io.fcp_cmnd_length, |
4390 | "%d active connection(s)\n", | 2173 | unit->fcp_lun, unit->port->wwpn); |
4391 | zfcp_get_busid_by_adapter(adapter), | 2174 | zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, req); |
4392 | header->fsf_status_qual.word[0]); | 2175 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
4393 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4394 | retval = -EIO; | ||
4395 | break; | 2176 | break; |
4396 | 2177 | case FSF_PORT_BOXED: | |
4397 | case FSF_UNKNOWN_OP_SUBTYPE: | 2178 | zfcp_erp_port_boxed(unit->port, 53, req); |
4398 | ZFCP_LOG_NORMAL("unknown operation subtype (adapter: %s, " | 2179 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
4399 | "op_subtype=0x%x)\n", | 2180 | ZFCP_STATUS_FSFREQ_RETRY; |
4400 | zfcp_get_busid_by_adapter(adapter), | ||
4401 | bottom->operation_subtype); | ||
4402 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4403 | retval = -EINVAL; | ||
4404 | break; | 2181 | break; |
4405 | 2182 | case FSF_LUN_BOXED: | |
4406 | case FSF_INVALID_COMMAND_OPTION: | 2183 | zfcp_erp_unit_boxed(unit, 54, req); |
4407 | ZFCP_LOG_NORMAL( | 2184 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
4408 | "Invalid option 0x%x has been specified " | 2185 | ZFCP_STATUS_FSFREQ_RETRY; |
4409 | "in QTCB bottom sent to the adapter %s\n", | ||
4410 | bottom->option, | ||
4411 | zfcp_get_busid_by_adapter(adapter)); | ||
4412 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4413 | retval = -EINVAL; | ||
4414 | break; | 2186 | break; |
4415 | 2187 | case FSF_ADAPTER_STATUS_AVAILABLE: | |
4416 | default: | 2188 | if (header->fsf_status_qual.word[0] == |
4417 | ZFCP_LOG_NORMAL( | 2189 | FSF_SQ_INVOKE_LINK_TEST_PROCEDURE) |
4418 | "bug: An unknown/unexpected FSF status 0x%08x " | 2190 | zfcp_test_link(unit->port); |
4419 | "was presented on the adapter %s\n", | 2191 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
4420 | header->fsf_status, | ||
4421 | zfcp_get_busid_by_adapter(adapter)); | ||
4422 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4423 | retval = -EINVAL; | ||
4424 | break; | 2192 | break; |
4425 | } | 2193 | } |
4426 | |||
4427 | skip_fsfstatus: | 2194 | skip_fsfstatus: |
4428 | return retval; | 2195 | if (req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) |
4429 | } | 2196 | zfcp_fsf_send_fcp_ctm_handler(req); |
4430 | 2197 | else { | |
4431 | static inline int | 2198 | zfcp_fsf_send_fcp_command_task_handler(req); |
4432 | zfcp_fsf_req_sbal_check(unsigned long *flags, | 2199 | req->unit = NULL; |
4433 | struct zfcp_qdio_queue *queue, int needed) | 2200 | zfcp_unit_put(unit); |
4434 | { | ||
4435 | write_lock_irqsave(&queue->queue_lock, *flags); | ||
4436 | if (likely(atomic_read(&queue->free_count) >= needed)) | ||
4437 | return 1; | ||
4438 | write_unlock_irqrestore(&queue->queue_lock, *flags); | ||
4439 | return 0; | ||
4440 | } | ||
4441 | |||
4442 | /* | ||
4443 | * set qtcb pointer in fsf_req and initialize QTCB | ||
4444 | */ | ||
4445 | static void | ||
4446 | zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req) | ||
4447 | { | ||
4448 | if (likely(fsf_req->qtcb != NULL)) { | ||
4449 | fsf_req->qtcb->prefix.req_seq_no = | ||
4450 | fsf_req->adapter->fsf_req_seq_no; | ||
4451 | fsf_req->qtcb->prefix.req_id = fsf_req->req_id; | ||
4452 | fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION; | ||
4453 | fsf_req->qtcb->prefix.qtcb_type = | ||
4454 | fsf_qtcb_type[fsf_req->fsf_command]; | ||
4455 | fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION; | ||
4456 | fsf_req->qtcb->header.req_handle = fsf_req->req_id; | ||
4457 | fsf_req->qtcb->header.fsf_command = fsf_req->fsf_command; | ||
4458 | } | 2201 | } |
4459 | } | 2202 | } |
4460 | 2203 | ||
4461 | /** | 2204 | /** |
4462 | * zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue | 2205 | * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) |
4463 | * @adapter: adapter for which request queue is examined | 2206 | * @adapter: adapter where scsi command is issued |
4464 | * @req_flags: flags indicating whether to wait for needed SBAL or not | 2207 | * @unit: unit where command is sent to |
4465 | * @lock_flags: lock_flags if queue_lock is taken | 2208 | * @scsi_cmnd: scsi command to be sent |
4466 | * Return: 0 on success, otherwise -EIO, or -ERESTARTSYS | 2209 | * @timer: timer to be started when request is initiated |
4467 | * Locks: lock adapter->request_queue->queue_lock on success | 2210 | * @req_flags: flags for fsf_request |
4468 | */ | ||
4469 | static int | ||
4470 | zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags, | ||
4471 | unsigned long *lock_flags) | ||
4472 | { | ||
4473 | long ret; | ||
4474 | struct zfcp_qdio_queue *req_queue = &adapter->request_queue; | ||
4475 | |||
4476 | if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) { | ||
4477 | ret = wait_event_interruptible_timeout(adapter->request_wq, | ||
4478 | zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1), | ||
4479 | ZFCP_SBAL_TIMEOUT); | ||
4480 | if (ret < 0) | ||
4481 | return ret; | ||
4482 | if (!ret) | ||
4483 | return -EIO; | ||
4484 | } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1)) | ||
4485 | return -EIO; | ||
4486 | |||
4487 | return 0; | ||
4488 | } | ||
4489 | |||
4490 | /* | ||
4491 | * function: zfcp_fsf_req_create | ||
4492 | * | ||
4493 | * purpose: create an FSF request at the specified adapter and | ||
4494 | * setup common fields | ||
4495 | * | ||
4496 | * returns: -ENOMEM if there was insufficient memory for a request | ||
4497 | * -EIO if no qdio buffers could be allocate to the request | ||
4498 | * -EINVAL/-EPERM on bug conditions in req_dequeue | ||
4499 | * 0 in success | ||
4500 | * | ||
4501 | * note: The created request is returned by reference. | ||
4502 | * | ||
4503 | * locks: lock of concerned request queue must not be held, | ||
4504 | * but is held on completion (write, irqsave) | ||
4505 | */ | 2211 | */ |
4506 | int | 2212 | int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, |
4507 | zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, | 2213 | struct zfcp_unit *unit, |
4508 | mempool_t *pool, unsigned long *lock_flags, | 2214 | struct scsi_cmnd *scsi_cmnd, |
4509 | struct zfcp_fsf_req **fsf_req_p) | 2215 | int use_timer, int req_flags) |
4510 | { | 2216 | { |
4511 | volatile struct qdio_buffer_element *sbale; | 2217 | struct zfcp_fsf_req *req; |
4512 | struct zfcp_fsf_req *fsf_req = NULL; | 2218 | struct fcp_cmnd_iu *fcp_cmnd_iu; |
4513 | int ret = 0; | 2219 | unsigned int sbtype; |
4514 | struct zfcp_qdio_queue *req_queue = &adapter->request_queue; | 2220 | int real_bytes, retval = -EIO; |
4515 | |||
4516 | /* allocate new FSF request */ | ||
4517 | fsf_req = zfcp_fsf_req_alloc(pool, req_flags); | ||
4518 | if (unlikely(NULL == fsf_req)) { | ||
4519 | ZFCP_LOG_DEBUG("error: Could not put an FSF request into " | ||
4520 | "the outbound (send) queue.\n"); | ||
4521 | ret = -ENOMEM; | ||
4522 | goto failed_fsf_req; | ||
4523 | } | ||
4524 | |||
4525 | fsf_req->adapter = adapter; | ||
4526 | fsf_req->fsf_command = fsf_cmd; | ||
4527 | INIT_LIST_HEAD(&fsf_req->list); | ||
4528 | init_timer(&fsf_req->timer); | ||
4529 | 2221 | ||
4530 | /* initialize waitqueue which may be used to wait on | 2222 | if (unlikely(!(atomic_read(&unit->status) & |
4531 | this request completion */ | 2223 | ZFCP_STATUS_COMMON_UNBLOCKED))) |
4532 | init_waitqueue_head(&fsf_req->completion_wq); | 2224 | return -EBUSY; |
4533 | 2225 | ||
4534 | ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags); | 2226 | spin_lock(&adapter->req_q.lock); |
4535 | if (ret < 0) | 2227 | if (!atomic_read(&adapter->req_q.count)) |
4536 | goto failed_sbals; | 2228 | goto out; |
2229 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, | ||
2230 | adapter->pool.fsf_req_scsi); | ||
2231 | if (unlikely(IS_ERR(req))) { | ||
2232 | retval = PTR_ERR(req); | ||
2233 | goto out; | ||
2234 | } | ||
4537 | 2235 | ||
4538 | /* this is serialized (we are holding req_queue-lock of adapter) */ | 2236 | zfcp_unit_get(unit); |
4539 | if (adapter->req_no == 0) | 2237 | req->unit = unit; |
4540 | adapter->req_no++; | 2238 | req->data = scsi_cmnd; |
4541 | fsf_req->req_id = adapter->req_no++; | 2239 | req->handler = zfcp_fsf_send_fcp_command_handler; |
2240 | req->qtcb->header.lun_handle = unit->handle; | ||
2241 | req->qtcb->header.port_handle = unit->port->handle; | ||
2242 | req->qtcb->bottom.io.service_class = FSF_CLASS_3; | ||
4542 | 2243 | ||
4543 | zfcp_fsf_req_qtcb_init(fsf_req); | 2244 | scsi_cmnd->host_scribble = (unsigned char *) req->req_id; |
4544 | 2245 | ||
2246 | fcp_cmnd_iu = (struct fcp_cmnd_iu *) &(req->qtcb->bottom.io.fcp_cmnd); | ||
2247 | fcp_cmnd_iu->fcp_lun = unit->fcp_lun; | ||
4545 | /* | 2248 | /* |
4546 | * We hold queue_lock here. Check if QDIOUP is set and let request fail | 2249 | * set depending on data direction: |
4547 | * if it is not set (see also *_open_qdio and *_close_qdio). | 2250 | * data direction bits in SBALE (SB Type) |
2251 | * data direction bits in QTCB | ||
2252 | * data direction bits in FCP_CMND IU | ||
4548 | */ | 2253 | */ |
4549 | 2254 | switch (scsi_cmnd->sc_data_direction) { | |
4550 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) { | 2255 | case DMA_NONE: |
4551 | write_unlock_irqrestore(&req_queue->queue_lock, *lock_flags); | 2256 | req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; |
4552 | ret = -EIO; | 2257 | sbtype = SBAL_FLAGS0_TYPE_READ; |
4553 | goto failed_sbals; | 2258 | break; |
2259 | case DMA_FROM_DEVICE: | ||
2260 | req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ; | ||
2261 | sbtype = SBAL_FLAGS0_TYPE_READ; | ||
2262 | fcp_cmnd_iu->rddata = 1; | ||
2263 | break; | ||
2264 | case DMA_TO_DEVICE: | ||
2265 | req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE; | ||
2266 | sbtype = SBAL_FLAGS0_TYPE_WRITE; | ||
2267 | fcp_cmnd_iu->wddata = 1; | ||
2268 | break; | ||
2269 | case DMA_BIDIRECTIONAL: | ||
2270 | default: | ||
2271 | retval = -EIO; | ||
2272 | goto failed_scsi_cmnd; | ||
4554 | } | 2273 | } |
4555 | 2274 | ||
4556 | if (fsf_req->qtcb) { | 2275 | if (likely((scsi_cmnd->device->simple_tags) || |
4557 | fsf_req->seq_no = adapter->fsf_req_seq_no; | 2276 | ((atomic_read(&unit->status) & ZFCP_STATUS_UNIT_READONLY) && |
4558 | fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; | 2277 | (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_SHARED)))) |
4559 | } | 2278 | fcp_cmnd_iu->task_attribute = SIMPLE_Q; |
4560 | fsf_req->sbal_number = 1; | 2279 | else |
4561 | fsf_req->sbal_first = req_queue->free_index; | 2280 | fcp_cmnd_iu->task_attribute = UNTAGGED; |
4562 | fsf_req->sbal_curr = req_queue->free_index; | ||
4563 | fsf_req->sbale_curr = 1; | ||
4564 | 2281 | ||
4565 | if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) { | 2282 | if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) |
4566 | fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; | 2283 | fcp_cmnd_iu->add_fcp_cdb_length = |
4567 | } | 2284 | (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2; |
4568 | 2285 | ||
4569 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 2286 | memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); |
4570 | 2287 | ||
4571 | /* setup common SBALE fields */ | 2288 | req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + |
4572 | sbale[0].addr = (void *) fsf_req->req_id; | 2289 | fcp_cmnd_iu->add_fcp_cdb_length + sizeof(fcp_dl_t); |
4573 | sbale[0].flags |= SBAL_FLAGS0_COMMAND; | 2290 | |
4574 | if (likely(fsf_req->qtcb != NULL)) { | 2291 | real_bytes = zfcp_qdio_sbals_from_sg(req, sbtype, |
4575 | sbale[1].addr = (void *) fsf_req->qtcb; | 2292 | scsi_sglist(scsi_cmnd), |
4576 | sbale[1].length = sizeof(struct fsf_qtcb); | 2293 | FSF_MAX_SBALS_PER_REQ); |
2294 | if (unlikely(real_bytes < 0)) { | ||
2295 | if (req->sbal_number < FSF_MAX_SBALS_PER_REQ) | ||
2296 | retval = -EIO; | ||
2297 | else { | ||
2298 | dev_err(&adapter->ccw_device->dev, | ||
2299 | "SCSI request too large. " | ||
2300 | "Shutting down unit 0x%016Lx on port " | ||
2301 | "0x%016Lx.\n", unit->fcp_lun, | ||
2302 | unit->port->wwpn); | ||
2303 | zfcp_erp_unit_shutdown(unit, 0, 131, req); | ||
2304 | retval = -EINVAL; | ||
2305 | } | ||
2306 | goto failed_scsi_cmnd; | ||
4577 | } | 2307 | } |
4578 | 2308 | ||
4579 | ZFCP_LOG_TRACE("got %i free BUFFERs starting at index %i\n", | 2309 | zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes); |
4580 | fsf_req->sbal_number, fsf_req->sbal_first); | ||
4581 | 2310 | ||
4582 | goto success; | 2311 | if (use_timer) |
2312 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); | ||
4583 | 2313 | ||
4584 | failed_sbals: | 2314 | retval = zfcp_fsf_req_send(req); |
4585 | /* dequeue new FSF request previously enqueued */ | 2315 | if (unlikely(retval)) |
4586 | zfcp_fsf_req_free(fsf_req); | 2316 | goto failed_scsi_cmnd; |
4587 | fsf_req = NULL; | ||
4588 | 2317 | ||
4589 | failed_fsf_req: | 2318 | goto out; |
4590 | write_lock_irqsave(&req_queue->queue_lock, *lock_flags); | 2319 | |
4591 | success: | 2320 | failed_scsi_cmnd: |
4592 | *fsf_req_p = fsf_req; | 2321 | zfcp_unit_put(unit); |
4593 | return ret; | 2322 | zfcp_fsf_req_free(req); |
2323 | scsi_cmnd->host_scribble = NULL; | ||
2324 | out: | ||
2325 | spin_unlock(&adapter->req_q.lock); | ||
2326 | return retval; | ||
4594 | } | 2327 | } |
4595 | 2328 | ||
4596 | /* | 2329 | /** |
4597 | * function: zfcp_fsf_req_send | 2330 | * zfcp_fsf_send_fcp_ctm - send SCSI task management command |
4598 | * | 2331 | * @adapter: pointer to struct zfcp-adapter |
4599 | * purpose: start transfer of FSF request via QDIO | 2332 | * @unit: pointer to struct zfcp_unit |
4600 | * | 2333 | * @tm_flags: unsigned byte for task management flags |
4601 | * returns: 0 - request transfer succesfully started | 2334 | * @req_flags: int request flags |
4602 | * !0 - start of request transfer failed | 2335 | * Returns: on success pointer to struct fsf_req, NULL otherwise |
4603 | */ | 2336 | */ |
4604 | static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req) | 2337 | struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter, |
2338 | struct zfcp_unit *unit, | ||
2339 | u8 tm_flags, int req_flags) | ||
4605 | { | 2340 | { |
4606 | struct zfcp_adapter *adapter; | ||
4607 | struct zfcp_qdio_queue *req_queue; | ||
4608 | volatile struct qdio_buffer_element *sbale; | 2341 | volatile struct qdio_buffer_element *sbale; |
4609 | int inc_seq_no; | 2342 | struct zfcp_fsf_req *req = NULL; |
4610 | int new_distance_from_int; | 2343 | struct fcp_cmnd_iu *fcp_cmnd_iu; |
4611 | int retval = 0; | ||
4612 | 2344 | ||
4613 | adapter = fsf_req->adapter; | 2345 | if (unlikely(!(atomic_read(&unit->status) & |
4614 | req_queue = &adapter->request_queue, | 2346 | ZFCP_STATUS_COMMON_UNBLOCKED))) |
2347 | return NULL; | ||
4615 | 2348 | ||
2349 | spin_lock(&adapter->req_q.lock); | ||
2350 | if (!atomic_read(&adapter->req_q.count)) | ||
2351 | goto out; | ||
2352 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, | ||
2353 | adapter->pool.fsf_req_scsi); | ||
2354 | if (unlikely(IS_ERR(req))) | ||
2355 | goto out; | ||
4616 | 2356 | ||
4617 | /* FIXME(debug): remove it later */ | 2357 | req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT; |
4618 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_first, 0); | 2358 | req->data = unit; |
4619 | ZFCP_LOG_DEBUG("SBALE0 flags=0x%x\n", sbale[0].flags); | 2359 | req->handler = zfcp_fsf_send_fcp_command_handler; |
4620 | ZFCP_LOG_TRACE("HEX DUMP OF SBALE1 PAYLOAD:\n"); | 2360 | req->qtcb->header.lun_handle = unit->handle; |
4621 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr, | 2361 | req->qtcb->header.port_handle = unit->port->handle; |
4622 | sbale[1].length); | 2362 | req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; |
2363 | req->qtcb->bottom.io.service_class = FSF_CLASS_3; | ||
2364 | req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + | ||
2365 | sizeof(fcp_dl_t); | ||
2366 | |||
2367 | sbale = zfcp_qdio_sbale_req(req); | ||
2368 | sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; | ||
2369 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
4623 | 2370 | ||
4624 | /* put allocated FSF request into hash table */ | 2371 | fcp_cmnd_iu = (struct fcp_cmnd_iu *) &req->qtcb->bottom.io.fcp_cmnd; |
4625 | spin_lock(&adapter->req_list_lock); | 2372 | fcp_cmnd_iu->fcp_lun = unit->fcp_lun; |
4626 | zfcp_reqlist_add(adapter, fsf_req); | 2373 | fcp_cmnd_iu->task_management_flags = tm_flags; |
4627 | spin_unlock(&adapter->req_list_lock); | ||
4628 | 2374 | ||
4629 | inc_seq_no = (fsf_req->qtcb != NULL); | 2375 | zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); |
2376 | if (!zfcp_fsf_req_send(req)) | ||
2377 | goto out; | ||
4630 | 2378 | ||
4631 | ZFCP_LOG_TRACE("request queue of adapter %s: " | 2379 | zfcp_fsf_req_free(req); |
4632 | "next free SBAL is %i, %i free SBALs\n", | 2380 | req = NULL; |
4633 | zfcp_get_busid_by_adapter(adapter), | 2381 | out: |
4634 | req_queue->free_index, | 2382 | spin_unlock(&adapter->req_q.lock); |
4635 | atomic_read(&req_queue->free_count)); | 2383 | return req; |
2384 | } | ||
4636 | 2385 | ||
4637 | ZFCP_LOG_DEBUG("calling do_QDIO adapter %s, flags=0x%x, queue_no=%i, " | 2386 | static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req) |
4638 | "index_in_queue=%i, count=%i, buffers=%p\n", | 2387 | { |
4639 | zfcp_get_busid_by_adapter(adapter), | 2388 | if (req->qtcb->header.fsf_status != FSF_GOOD) |
4640 | QDIO_FLAG_SYNC_OUTPUT, | 2389 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
4641 | 0, fsf_req->sbal_first, fsf_req->sbal_number, | 2390 | } |
4642 | &req_queue->buffer[fsf_req->sbal_first]); | ||
4643 | 2391 | ||
4644 | /* | 2392 | /** |
4645 | * adjust the number of free SBALs in request queue as well as | 2393 | * zfcp_fsf_control_file - control file upload/download |
4646 | * position of first one | 2394 | * @adapter: pointer to struct zfcp_adapter |
4647 | */ | 2395 | * @fsf_cfdc: pointer to struct zfcp_fsf_cfdc |
4648 | atomic_sub(fsf_req->sbal_number, &req_queue->free_count); | 2396 | * Returns: on success pointer to struct zfcp_fsf_req, NULL otherwise |
4649 | ZFCP_LOG_TRACE("free_count=%d\n", atomic_read(&req_queue->free_count)); | 2397 | */ |
4650 | req_queue->free_index += fsf_req->sbal_number; /* increase */ | 2398 | struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, |
4651 | req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap if needed */ | 2399 | struct zfcp_fsf_cfdc *fsf_cfdc) |
4652 | new_distance_from_int = zfcp_qdio_determine_pci(req_queue, fsf_req); | 2400 | { |
2401 | volatile struct qdio_buffer_element *sbale; | ||
2402 | struct zfcp_fsf_req *req = NULL; | ||
2403 | struct fsf_qtcb_bottom_support *bottom; | ||
2404 | int direction, retval = -EIO, bytes; | ||
2405 | |||
2406 | if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) | ||
2407 | return ERR_PTR(-EOPNOTSUPP); | ||
2408 | |||
2409 | switch (fsf_cfdc->command) { | ||
2410 | case FSF_QTCB_DOWNLOAD_CONTROL_FILE: | ||
2411 | direction = SBAL_FLAGS0_TYPE_WRITE; | ||
2412 | break; | ||
2413 | case FSF_QTCB_UPLOAD_CONTROL_FILE: | ||
2414 | direction = SBAL_FLAGS0_TYPE_READ; | ||
2415 | break; | ||
2416 | default: | ||
2417 | return ERR_PTR(-EINVAL); | ||
2418 | } | ||
4653 | 2419 | ||
4654 | fsf_req->issued = get_clock(); | 2420 | spin_lock(&adapter->req_q.lock); |
2421 | if (zfcp_fsf_req_sbal_get(adapter)) | ||
2422 | goto out; | ||
4655 | 2423 | ||
4656 | retval = do_QDIO(adapter->ccw_device, | 2424 | req = zfcp_fsf_req_create(adapter, fsf_cfdc->command, 0, NULL); |
4657 | QDIO_FLAG_SYNC_OUTPUT, | 2425 | if (unlikely(IS_ERR(req))) { |
4658 | 0, fsf_req->sbal_first, fsf_req->sbal_number, NULL); | 2426 | retval = -EPERM; |
2427 | goto out; | ||
2428 | } | ||
4659 | 2429 | ||
4660 | if (unlikely(retval)) { | 2430 | req->handler = zfcp_fsf_control_file_handler; |
4661 | /* Queues are down..... */ | 2431 | |
4662 | retval = -EIO; | 2432 | sbale = zfcp_qdio_sbale_req(req); |
4663 | del_timer(&fsf_req->timer); | 2433 | sbale[0].flags |= direction; |
4664 | spin_lock(&adapter->req_list_lock); | ||
4665 | zfcp_reqlist_remove(adapter, fsf_req); | ||
4666 | spin_unlock(&adapter->req_list_lock); | ||
4667 | /* undo changes in request queue made for this request */ | ||
4668 | zfcp_qdio_zero_sbals(req_queue->buffer, | ||
4669 | fsf_req->sbal_first, fsf_req->sbal_number); | ||
4670 | atomic_add(fsf_req->sbal_number, &req_queue->free_count); | ||
4671 | req_queue->free_index -= fsf_req->sbal_number; | ||
4672 | req_queue->free_index += QDIO_MAX_BUFFERS_PER_Q; | ||
4673 | req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */ | ||
4674 | zfcp_erp_adapter_reopen(adapter, 0, 116, fsf_req); | ||
4675 | } else { | ||
4676 | req_queue->distance_from_int = new_distance_from_int; | ||
4677 | /* | ||
4678 | * increase FSF sequence counter - | ||
4679 | * this must only be done for request successfully enqueued to | ||
4680 | * QDIO this rejected requests may be cleaned up by calling | ||
4681 | * routines resulting in missing sequence counter values | ||
4682 | * otherwise, | ||
4683 | */ | ||
4684 | 2434 | ||
4685 | /* Don't increase for unsolicited status */ | 2435 | bottom = &req->qtcb->bottom.support; |
4686 | if (inc_seq_no) | 2436 | bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; |
4687 | adapter->fsf_req_seq_no++; | 2437 | bottom->option = fsf_cfdc->option; |
4688 | 2438 | ||
4689 | /* count FSF requests pending */ | 2439 | bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg, |
4690 | atomic_inc(&adapter->reqs_active); | 2440 | FSF_MAX_SBALS_PER_REQ); |
2441 | if (bytes != ZFCP_CFDC_MAX_SIZE) { | ||
2442 | retval = -ENOMEM; | ||
2443 | zfcp_fsf_req_free(req); | ||
2444 | goto out; | ||
4691 | } | 2445 | } |
4692 | return retval; | ||
4693 | } | ||
4694 | 2446 | ||
4695 | #undef ZFCP_LOG_AREA | 2447 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); |
2448 | retval = zfcp_fsf_req_send(req); | ||
2449 | out: | ||
2450 | spin_unlock(&adapter->req_q.lock); | ||
2451 | |||
2452 | if (!retval) { | ||
2453 | wait_event(req->completion_wq, | ||
2454 | req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | ||
2455 | return req; | ||
2456 | } | ||
2457 | return ERR_PTR(retval); | ||
2458 | } | ||
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 099970b27001..bf94b4da0763 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h | |||
@@ -1,27 +1,16 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Interface to the FSF support functions. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #ifndef FSF_H | 9 | #ifndef FSF_H |
23 | #define FSF_H | 10 | #define FSF_H |
24 | 11 | ||
12 | #include <linux/pfn.h> | ||
13 | |||
25 | #define FSF_QTCB_CURRENT_VERSION 0x00000001 | 14 | #define FSF_QTCB_CURRENT_VERSION 0x00000001 |
26 | 15 | ||
27 | /* FSF commands */ | 16 | /* FSF commands */ |
@@ -258,6 +247,16 @@ | |||
258 | #define FSF_UNIT_ACCESS_EXCLUSIVE 0x02000000 | 247 | #define FSF_UNIT_ACCESS_EXCLUSIVE 0x02000000 |
259 | #define FSF_UNIT_ACCESS_OUTBOUND_TRANSFER 0x10000000 | 248 | #define FSF_UNIT_ACCESS_OUTBOUND_TRANSFER 0x10000000 |
260 | 249 | ||
250 | /* FSF interface for CFDC */ | ||
251 | #define ZFCP_CFDC_MAX_SIZE 127 * 1024 | ||
252 | #define ZFCP_CFDC_PAGES PFN_UP(ZFCP_CFDC_MAX_SIZE) | ||
253 | |||
254 | struct zfcp_fsf_cfdc { | ||
255 | struct scatterlist sg[ZFCP_CFDC_PAGES]; | ||
256 | u32 command; | ||
257 | u32 option; | ||
258 | }; | ||
259 | |||
261 | struct fsf_queue_designator { | 260 | struct fsf_queue_designator { |
262 | u8 cssid; | 261 | u8 cssid; |
263 | u8 chpid; | 262 | u8 chpid; |
@@ -288,6 +287,18 @@ struct fsf_bit_error_payload { | |||
288 | u32 current_transmit_b2b_credit; | 287 | u32 current_transmit_b2b_credit; |
289 | } __attribute__ ((packed)); | 288 | } __attribute__ ((packed)); |
290 | 289 | ||
290 | struct fsf_link_down_info { | ||
291 | u32 error_code; | ||
292 | u32 res1; | ||
293 | u8 res2[2]; | ||
294 | u8 primary_status; | ||
295 | u8 ioerr_code; | ||
296 | u8 action_code; | ||
297 | u8 reason_code; | ||
298 | u8 explanation_code; | ||
299 | u8 vendor_specific_code; | ||
300 | } __attribute__ ((packed)); | ||
301 | |||
291 | struct fsf_status_read_buffer { | 302 | struct fsf_status_read_buffer { |
292 | u32 status_type; | 303 | u32 status_type; |
293 | u32 status_subtype; | 304 | u32 status_subtype; |
@@ -298,7 +309,12 @@ struct fsf_status_read_buffer { | |||
298 | u32 class; | 309 | u32 class; |
299 | u64 fcp_lun; | 310 | u64 fcp_lun; |
300 | u8 res3[24]; | 311 | u8 res3[24]; |
301 | u8 payload[FSF_STATUS_READ_PAYLOAD_SIZE]; | 312 | union { |
313 | u8 data[FSF_STATUS_READ_PAYLOAD_SIZE]; | ||
314 | u32 word[FSF_STATUS_READ_PAYLOAD_SIZE/sizeof(u32)]; | ||
315 | struct fsf_link_down_info link_down_info; | ||
316 | struct fsf_bit_error_payload bit_error; | ||
317 | } payload; | ||
302 | } __attribute__ ((packed)); | 318 | } __attribute__ ((packed)); |
303 | 319 | ||
304 | struct fsf_qual_version_error { | 320 | struct fsf_qual_version_error { |
@@ -311,23 +327,19 @@ struct fsf_qual_sequence_error { | |||
311 | u32 res1[3]; | 327 | u32 res1[3]; |
312 | } __attribute__ ((packed)); | 328 | } __attribute__ ((packed)); |
313 | 329 | ||
314 | struct fsf_link_down_info { | 330 | struct fsf_qual_latency_info { |
315 | u32 error_code; | 331 | u32 channel_lat; |
316 | u32 res1; | 332 | u32 fabric_lat; |
317 | u8 res2[2]; | 333 | u8 res1[8]; |
318 | u8 primary_status; | ||
319 | u8 ioerr_code; | ||
320 | u8 action_code; | ||
321 | u8 reason_code; | ||
322 | u8 explanation_code; | ||
323 | u8 vendor_specific_code; | ||
324 | } __attribute__ ((packed)); | 334 | } __attribute__ ((packed)); |
325 | 335 | ||
326 | union fsf_prot_status_qual { | 336 | union fsf_prot_status_qual { |
337 | u32 word[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u32)]; | ||
327 | u64 doubleword[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u64)]; | 338 | u64 doubleword[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u64)]; |
328 | struct fsf_qual_version_error version_error; | 339 | struct fsf_qual_version_error version_error; |
329 | struct fsf_qual_sequence_error sequence_error; | 340 | struct fsf_qual_sequence_error sequence_error; |
330 | struct fsf_link_down_info link_down_info; | 341 | struct fsf_link_down_info link_down_info; |
342 | struct fsf_qual_latency_info latency_info; | ||
331 | } __attribute__ ((packed)); | 343 | } __attribute__ ((packed)); |
332 | 344 | ||
333 | struct fsf_qtcb_prefix { | 345 | struct fsf_qtcb_prefix { |
@@ -437,7 +449,9 @@ struct fsf_qtcb_bottom_config { | |||
437 | u32 fc_link_speed; | 449 | u32 fc_link_speed; |
438 | u32 adapter_type; | 450 | u32 adapter_type; |
439 | u32 peer_d_id; | 451 | u32 peer_d_id; |
440 | u8 res2[12]; | 452 | u8 res1[2]; |
453 | u16 timer_interval; | ||
454 | u8 res2[8]; | ||
441 | u32 s_id; | 455 | u32 s_id; |
442 | struct fsf_nport_serv_param nport_serv_param; | 456 | struct fsf_nport_serv_param nport_serv_param; |
443 | u8 reserved_nport_serv_param[16]; | 457 | u8 reserved_nport_serv_param[16]; |
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 8ca5f074c687..72e3094796d4 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c | |||
@@ -1,241 +1,103 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Setup and helper functions to access QDIO. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #include "zfcp_ext.h" | 9 | #include "zfcp_ext.h" |
23 | 10 | ||
24 | static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int); | 11 | /* FIXME(tune): free space should be one max. SBAL chain plus what? */ |
25 | static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get | 12 | #define ZFCP_QDIO_PCI_INTERVAL (QDIO_MAX_BUFFERS_PER_Q \ |
26 | (struct zfcp_qdio_queue *, int, int); | 13 | - (FSF_MAX_SBALS_PER_REQ + 4)) |
27 | static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp | 14 | #define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer)) |
28 | (struct zfcp_fsf_req *, int, int); | ||
29 | static volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain | ||
30 | (struct zfcp_fsf_req *, unsigned long); | ||
31 | static volatile struct qdio_buffer_element *zfcp_qdio_sbale_next | ||
32 | (struct zfcp_fsf_req *, unsigned long); | ||
33 | static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int); | ||
34 | static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *); | ||
35 | static void zfcp_qdio_sbale_fill | ||
36 | (struct zfcp_fsf_req *, unsigned long, void *, int); | ||
37 | static int zfcp_qdio_sbals_from_segment | ||
38 | (struct zfcp_fsf_req *, unsigned long, void *, unsigned long); | ||
39 | |||
40 | static qdio_handler_t zfcp_qdio_request_handler; | ||
41 | static qdio_handler_t zfcp_qdio_response_handler; | ||
42 | static int zfcp_qdio_handler_error_check(struct zfcp_adapter *, | ||
43 | unsigned int, unsigned int, unsigned int, int, int); | ||
44 | |||
45 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_QDIO | ||
46 | |||
47 | /* | ||
48 | * Frees BUFFER memory for each of the pointers of the struct qdio_buffer array | ||
49 | * in the adapter struct sbuf is the pointer array. | ||
50 | * | ||
51 | * locks: must only be called with zfcp_data.config_sema taken | ||
52 | */ | ||
53 | static void | ||
54 | zfcp_qdio_buffers_dequeue(struct qdio_buffer **sbuf) | ||
55 | { | ||
56 | int pos; | ||
57 | |||
58 | for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) | ||
59 | free_page((unsigned long) sbuf[pos]); | ||
60 | } | ||
61 | 15 | ||
62 | /* | 16 | static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal) |
63 | * Allocates BUFFER memory to each of the pointers of the qdio_buffer_t | ||
64 | * array in the adapter struct. | ||
65 | * Cur_buf is the pointer array | ||
66 | * | ||
67 | * returns: zero on success else -ENOMEM | ||
68 | * locks: must only be called with zfcp_data.config_sema taken | ||
69 | */ | ||
70 | static int | ||
71 | zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbuf) | ||
72 | { | 17 | { |
73 | int pos; | 18 | int pos; |
74 | 19 | ||
75 | for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) { | 20 | for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) { |
76 | sbuf[pos] = (struct qdio_buffer *) get_zeroed_page(GFP_KERNEL); | 21 | sbal[pos] = (struct qdio_buffer *) get_zeroed_page(GFP_KERNEL); |
77 | if (!sbuf[pos]) { | 22 | if (!sbal[pos]) |
78 | zfcp_qdio_buffers_dequeue(sbuf); | ||
79 | return -ENOMEM; | 23 | return -ENOMEM; |
80 | } | ||
81 | } | 24 | } |
82 | for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos++) | 25 | for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos++) |
83 | if (pos % QBUFF_PER_PAGE) | 26 | if (pos % QBUFF_PER_PAGE) |
84 | sbuf[pos] = sbuf[pos - 1] + 1; | 27 | sbal[pos] = sbal[pos - 1] + 1; |
85 | return 0; | 28 | return 0; |
86 | } | 29 | } |
87 | 30 | ||
88 | /* locks: must only be called with zfcp_data.config_sema taken */ | 31 | static volatile struct qdio_buffer_element * |
89 | int | 32 | zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx) |
90 | zfcp_qdio_allocate_queues(struct zfcp_adapter *adapter) | ||
91 | { | 33 | { |
92 | int ret; | 34 | return &q->sbal[sbal_idx]->element[sbale_idx]; |
93 | |||
94 | ret = zfcp_qdio_buffers_enqueue(adapter->request_queue.buffer); | ||
95 | if (ret) | ||
96 | return ret; | ||
97 | return zfcp_qdio_buffers_enqueue(adapter->response_queue.buffer); | ||
98 | } | 35 | } |
99 | 36 | ||
100 | /* locks: must only be called with zfcp_data.config_sema taken */ | 37 | /** |
101 | void | 38 | * zfcp_qdio_free - free memory used by request- and resposne queue |
102 | zfcp_qdio_free_queues(struct zfcp_adapter *adapter) | 39 | * @adapter: pointer to the zfcp_adapter structure |
40 | */ | ||
41 | void zfcp_qdio_free(struct zfcp_adapter *adapter) | ||
103 | { | 42 | { |
104 | ZFCP_LOG_TRACE("freeing request_queue buffers\n"); | 43 | struct qdio_buffer **sbal_req, **sbal_resp; |
105 | zfcp_qdio_buffers_dequeue(adapter->request_queue.buffer); | 44 | int p; |
106 | 45 | ||
107 | ZFCP_LOG_TRACE("freeing response_queue buffers\n"); | 46 | if (adapter->ccw_device) |
108 | zfcp_qdio_buffers_dequeue(adapter->response_queue.buffer); | 47 | qdio_free(adapter->ccw_device); |
109 | } | ||
110 | 48 | ||
111 | int | 49 | sbal_req = adapter->req_q.sbal; |
112 | zfcp_qdio_allocate(struct zfcp_adapter *adapter) | 50 | sbal_resp = adapter->resp_q.sbal; |
113 | { | ||
114 | struct qdio_initialize *init_data; | ||
115 | 51 | ||
116 | init_data = &adapter->qdio_init_data; | 52 | for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) { |
53 | free_page((unsigned long) sbal_req[p]); | ||
54 | free_page((unsigned long) sbal_resp[p]); | ||
55 | } | ||
56 | } | ||
117 | 57 | ||
118 | init_data->cdev = adapter->ccw_device; | 58 | static void zfcp_qdio_handler_error(struct zfcp_adapter *adapter, u8 id) |
119 | init_data->q_format = QDIO_SCSI_QFMT; | 59 | { |
120 | memcpy(init_data->adapter_name, zfcp_get_busid_by_adapter(adapter), 8); | 60 | dev_warn(&adapter->ccw_device->dev, "QDIO problem occurred.\n"); |
121 | ASCEBC(init_data->adapter_name, 8); | ||
122 | init_data->qib_param_field_format = 0; | ||
123 | init_data->qib_param_field = NULL; | ||
124 | init_data->input_slib_elements = NULL; | ||
125 | init_data->output_slib_elements = NULL; | ||
126 | init_data->min_input_threshold = ZFCP_MIN_INPUT_THRESHOLD; | ||
127 | init_data->max_input_threshold = ZFCP_MAX_INPUT_THRESHOLD; | ||
128 | init_data->min_output_threshold = ZFCP_MIN_OUTPUT_THRESHOLD; | ||
129 | init_data->max_output_threshold = ZFCP_MAX_OUTPUT_THRESHOLD; | ||
130 | init_data->no_input_qs = 1; | ||
131 | init_data->no_output_qs = 1; | ||
132 | init_data->input_handler = zfcp_qdio_response_handler; | ||
133 | init_data->output_handler = zfcp_qdio_request_handler; | ||
134 | init_data->int_parm = (unsigned long) adapter; | ||
135 | init_data->flags = QDIO_INBOUND_0COPY_SBALS | | ||
136 | QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS; | ||
137 | init_data->input_sbal_addr_array = | ||
138 | (void **) (adapter->response_queue.buffer); | ||
139 | init_data->output_sbal_addr_array = | ||
140 | (void **) (adapter->request_queue.buffer); | ||
141 | 61 | ||
142 | return qdio_allocate(init_data); | 62 | zfcp_erp_adapter_reopen(adapter, |
63 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | | ||
64 | ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL); | ||
143 | } | 65 | } |
144 | 66 | ||
145 | /* | 67 | static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt) |
146 | * function: zfcp_qdio_handler_error_check | ||
147 | * | ||
148 | * purpose: called by the response handler to determine error condition | ||
149 | * | ||
150 | * returns: error flag | ||
151 | * | ||
152 | */ | ||
153 | static int | ||
154 | zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status, | ||
155 | unsigned int qdio_error, unsigned int siga_error, | ||
156 | int first_element, int elements_processed) | ||
157 | { | 68 | { |
158 | int retval = 0; | 69 | int i, sbal_idx; |
159 | 70 | ||
160 | if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) { | 71 | for (i = first; i < first + cnt; i++) { |
161 | retval = -EIO; | 72 | sbal_idx = i % QDIO_MAX_BUFFERS_PER_Q; |
162 | 73 | memset(sbal[sbal_idx], 0, sizeof(struct qdio_buffer)); | |
163 | ZFCP_LOG_INFO("QDIO problem occurred (status=0x%x, " | ||
164 | "qdio_error=0x%x, siga_error=0x%x)\n", | ||
165 | status, qdio_error, siga_error); | ||
166 | |||
167 | zfcp_hba_dbf_event_qdio(adapter, status, qdio_error, siga_error, | ||
168 | first_element, elements_processed); | ||
169 | /* | ||
170 | * Restarting IO on the failed adapter from scratch. | ||
171 | * Since we have been using this adapter, it is save to assume | ||
172 | * that it is not failed but recoverable. The card seems to | ||
173 | * report link-up events by self-initiated queue shutdown. | ||
174 | * That is why we need to clear the link-down flag | ||
175 | * which is set again in case we have missed by a mile. | ||
176 | */ | ||
177 | zfcp_erp_adapter_reopen(adapter, | ||
178 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | | ||
179 | ZFCP_STATUS_COMMON_ERP_FAILED, 140, | ||
180 | NULL); | ||
181 | } | 74 | } |
182 | return retval; | ||
183 | } | 75 | } |
184 | 76 | ||
185 | /* | 77 | static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int status, |
186 | * function: zfcp_qdio_request_handler | 78 | unsigned int qdio_err, unsigned int siga_err, |
187 | * | 79 | unsigned int queue_no, int first, int count, |
188 | * purpose: is called by QDIO layer for completed SBALs in request queue | 80 | unsigned long parm) |
189 | * | ||
190 | * returns: (void) | ||
191 | */ | ||
192 | static void | ||
193 | zfcp_qdio_request_handler(struct ccw_device *ccw_device, | ||
194 | unsigned int status, | ||
195 | unsigned int qdio_error, | ||
196 | unsigned int siga_error, | ||
197 | unsigned int queue_number, | ||
198 | int first_element, | ||
199 | int elements_processed, | ||
200 | unsigned long int_parm) | ||
201 | { | 81 | { |
202 | struct zfcp_adapter *adapter; | 82 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm; |
203 | struct zfcp_qdio_queue *queue; | 83 | struct zfcp_qdio_queue *queue = &adapter->req_q; |
204 | |||
205 | adapter = (struct zfcp_adapter *) int_parm; | ||
206 | queue = &adapter->request_queue; | ||
207 | |||
208 | ZFCP_LOG_DEBUG("adapter %s, first=%d, elements_processed=%d\n", | ||
209 | zfcp_get_busid_by_adapter(adapter), | ||
210 | first_element, elements_processed); | ||
211 | 84 | ||
212 | if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error, | 85 | if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) { |
213 | siga_error, first_element, | 86 | zfcp_hba_dbf_event_qdio(adapter, status, qdio_err, siga_err, |
214 | elements_processed))) | 87 | first, count); |
215 | goto out; | 88 | zfcp_qdio_handler_error(adapter, 140); |
216 | /* | 89 | return; |
217 | * we stored address of struct zfcp_adapter data structure | 90 | } |
218 | * associated with irq in int_parm | ||
219 | */ | ||
220 | 91 | ||
221 | /* cleanup all SBALs being program-owned now */ | 92 | /* cleanup all SBALs being program-owned now */ |
222 | zfcp_qdio_zero_sbals(queue->buffer, first_element, elements_processed); | 93 | zfcp_qdio_zero_sbals(queue->sbal, first, count); |
223 | 94 | ||
224 | /* increase free space in outbound queue */ | 95 | atomic_add(count, &queue->count); |
225 | atomic_add(elements_processed, &queue->free_count); | ||
226 | ZFCP_LOG_DEBUG("free_count=%d\n", atomic_read(&queue->free_count)); | ||
227 | wake_up(&adapter->request_wq); | 96 | wake_up(&adapter->request_wq); |
228 | ZFCP_LOG_DEBUG("elements_processed=%d, free count=%d\n", | ||
229 | elements_processed, atomic_read(&queue->free_count)); | ||
230 | out: | ||
231 | return; | ||
232 | } | 97 | } |
233 | 98 | ||
234 | /** | ||
235 | * zfcp_qdio_reqid_check - checks for valid reqids. | ||
236 | */ | ||
237 | static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, | 99 | static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, |
238 | unsigned long req_id) | 100 | unsigned long req_id, int sbal_idx) |
239 | { | 101 | { |
240 | struct zfcp_fsf_req *fsf_req; | 102 | struct zfcp_fsf_req *fsf_req; |
241 | unsigned long flags; | 103 | unsigned long flags; |
@@ -248,203 +110,117 @@ static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, | |||
248 | * Unknown request means that we have potentially memory | 110 | * Unknown request means that we have potentially memory |
249 | * corruption and must stop the machine immediatly. | 111 | * corruption and must stop the machine immediatly. |
250 | */ | 112 | */ |
251 | panic("error: unknown request id (%ld) on adapter %s.\n", | 113 | panic("error: unknown request id (%lx) on adapter %s.\n", |
252 | req_id, zfcp_get_busid_by_adapter(adapter)); | 114 | req_id, zfcp_get_busid_by_adapter(adapter)); |
253 | 115 | ||
254 | zfcp_reqlist_remove(adapter, fsf_req); | 116 | zfcp_reqlist_remove(adapter, fsf_req); |
255 | atomic_dec(&adapter->reqs_active); | ||
256 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); | 117 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); |
257 | 118 | ||
258 | /* finish the FSF request */ | 119 | fsf_req->sbal_response = sbal_idx; |
259 | zfcp_fsf_req_complete(fsf_req); | 120 | zfcp_fsf_req_complete(fsf_req); |
260 | } | 121 | } |
261 | 122 | ||
262 | /* | 123 | static void zfcp_qdio_resp_put_back(struct zfcp_adapter *adapter, int processed) |
263 | * function: zfcp_qdio_response_handler | ||
264 | * | ||
265 | * purpose: is called by QDIO layer for completed SBALs in response queue | ||
266 | * | ||
267 | * returns: (void) | ||
268 | */ | ||
269 | static void | ||
270 | zfcp_qdio_response_handler(struct ccw_device *ccw_device, | ||
271 | unsigned int status, | ||
272 | unsigned int qdio_error, | ||
273 | unsigned int siga_error, | ||
274 | unsigned int queue_number, | ||
275 | int first_element, | ||
276 | int elements_processed, | ||
277 | unsigned long int_parm) | ||
278 | { | 124 | { |
279 | struct zfcp_adapter *adapter; | 125 | struct zfcp_qdio_queue *queue = &adapter->resp_q; |
280 | struct zfcp_qdio_queue *queue; | 126 | struct ccw_device *cdev = adapter->ccw_device; |
281 | int buffer_index; | 127 | u8 count, start = queue->first; |
282 | int i; | 128 | unsigned int retval; |
283 | struct qdio_buffer *buffer; | ||
284 | int retval = 0; | ||
285 | u8 count; | ||
286 | u8 start; | ||
287 | volatile struct qdio_buffer_element *buffere = NULL; | ||
288 | int buffere_index; | ||
289 | |||
290 | adapter = (struct zfcp_adapter *) int_parm; | ||
291 | queue = &adapter->response_queue; | ||
292 | |||
293 | if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error, | ||
294 | siga_error, first_element, | ||
295 | elements_processed))) | ||
296 | goto out; | ||
297 | 129 | ||
298 | /* | 130 | count = atomic_read(&queue->count) + processed; |
299 | * we stored address of struct zfcp_adapter data structure | 131 | |
300 | * associated with irq in int_parm | 132 | retval = do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, |
301 | */ | 133 | 0, start, count, NULL); |
134 | |||
135 | if (unlikely(retval)) { | ||
136 | atomic_set(&queue->count, count); | ||
137 | /* FIXME: Recover this with an adapter reopen? */ | ||
138 | } else { | ||
139 | queue->first += count; | ||
140 | queue->first %= QDIO_MAX_BUFFERS_PER_Q; | ||
141 | atomic_set(&queue->count, 0); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int status, | ||
146 | unsigned int qdio_err, unsigned int siga_err, | ||
147 | unsigned int queue_no, int first, int count, | ||
148 | unsigned long parm) | ||
149 | { | ||
150 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm; | ||
151 | struct zfcp_qdio_queue *queue = &adapter->resp_q; | ||
152 | volatile struct qdio_buffer_element *sbale; | ||
153 | int sbal_idx, sbale_idx, sbal_no; | ||
154 | |||
155 | if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) { | ||
156 | zfcp_hba_dbf_event_qdio(adapter, status, qdio_err, siga_err, | ||
157 | first, count); | ||
158 | zfcp_qdio_handler_error(adapter, 147); | ||
159 | return; | ||
160 | } | ||
302 | 161 | ||
303 | buffere = &(queue->buffer[first_element]->element[0]); | ||
304 | ZFCP_LOG_DEBUG("first BUFFERE flags=0x%x\n", buffere->flags); | ||
305 | /* | 162 | /* |
306 | * go through all SBALs from input queue currently | 163 | * go through all SBALs from input queue currently |
307 | * returned by QDIO layer | 164 | * returned by QDIO layer |
308 | */ | 165 | */ |
309 | 166 | for (sbal_no = 0; sbal_no < count; sbal_no++) { | |
310 | for (i = 0; i < elements_processed; i++) { | 167 | sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q; |
311 | |||
312 | buffer_index = first_element + i; | ||
313 | buffer_index %= QDIO_MAX_BUFFERS_PER_Q; | ||
314 | buffer = queue->buffer[buffer_index]; | ||
315 | 168 | ||
316 | /* go through all SBALEs of SBAL */ | 169 | /* go through all SBALEs of SBAL */ |
317 | for (buffere_index = 0; | 170 | for (sbale_idx = 0; sbale_idx < QDIO_MAX_ELEMENTS_PER_BUFFER; |
318 | buffere_index < QDIO_MAX_ELEMENTS_PER_BUFFER; | 171 | sbale_idx++) { |
319 | buffere_index++) { | 172 | sbale = zfcp_qdio_sbale(queue, sbal_idx, sbale_idx); |
320 | |||
321 | /* look for QDIO request identifiers in SB */ | ||
322 | buffere = &buffer->element[buffere_index]; | ||
323 | zfcp_qdio_reqid_check(adapter, | 173 | zfcp_qdio_reqid_check(adapter, |
324 | (unsigned long) buffere->addr); | 174 | (unsigned long) sbale->addr, |
325 | 175 | sbal_idx); | |
326 | /* | 176 | if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY)) |
327 | * A single used SBALE per inbound SBALE has been | ||
328 | * implemented by QDIO so far. Hope they will | ||
329 | * do some optimisation. Will need to change to | ||
330 | * unlikely() then. | ||
331 | */ | ||
332 | if (likely(buffere->flags & SBAL_FLAGS_LAST_ENTRY)) | ||
333 | break; | 177 | break; |
334 | }; | 178 | }; |
335 | 179 | ||
336 | if (unlikely(!(buffere->flags & SBAL_FLAGS_LAST_ENTRY))) { | 180 | if (unlikely(!(sbale->flags & SBAL_FLAGS_LAST_ENTRY))) |
337 | ZFCP_LOG_NORMAL("bug: End of inbound data " | 181 | dev_warn(&adapter->ccw_device->dev, |
338 | "not marked!\n"); | 182 | "Protocol violation by adapter. " |
339 | } | 183 | "Continuing operations.\n"); |
340 | } | 184 | } |
341 | 185 | ||
342 | /* | 186 | /* |
343 | * put range of SBALs back to response queue | 187 | * put range of SBALs back to response queue |
344 | * (including SBALs which have already been free before) | 188 | * (including SBALs which have already been free before) |
345 | */ | 189 | */ |
346 | count = atomic_read(&queue->free_count) + elements_processed; | 190 | zfcp_qdio_resp_put_back(adapter, count); |
347 | start = queue->free_index; | ||
348 | |||
349 | ZFCP_LOG_TRACE("calling do_QDIO on adapter %s (flags=0x%x, " | ||
350 | "queue_no=%i, index_in_queue=%i, count=%i, " | ||
351 | "buffers=0x%lx\n", | ||
352 | zfcp_get_busid_by_adapter(adapter), | ||
353 | QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, | ||
354 | 0, start, count, (unsigned long) &queue->buffer[start]); | ||
355 | |||
356 | retval = do_QDIO(ccw_device, | ||
357 | QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, | ||
358 | 0, start, count, NULL); | ||
359 | |||
360 | if (unlikely(retval)) { | ||
361 | atomic_set(&queue->free_count, count); | ||
362 | ZFCP_LOG_DEBUG("clearing of inbound data regions failed, " | ||
363 | "queues may be down " | ||
364 | "(count=%d, start=%d, retval=%d)\n", | ||
365 | count, start, retval); | ||
366 | } else { | ||
367 | queue->free_index += count; | ||
368 | queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; | ||
369 | atomic_set(&queue->free_count, 0); | ||
370 | ZFCP_LOG_TRACE("%i buffers enqueued to response " | ||
371 | "queue at position %i\n", count, start); | ||
372 | } | ||
373 | out: | ||
374 | return; | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * zfcp_qdio_sbale_get - return pointer to SBALE of qdio_queue | ||
379 | * @queue: queue from which SBALE should be returned | ||
380 | * @sbal: specifies number of SBAL in queue | ||
381 | * @sbale: specifes number of SBALE in SBAL | ||
382 | */ | ||
383 | static inline volatile struct qdio_buffer_element * | ||
384 | zfcp_qdio_sbale_get(struct zfcp_qdio_queue *queue, int sbal, int sbale) | ||
385 | { | ||
386 | return &queue->buffer[sbal]->element[sbale]; | ||
387 | } | 191 | } |
388 | 192 | ||
389 | /** | 193 | /** |
390 | * zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for | 194 | * zfcp_qdio_sbale_req - return ptr to SBALE of req_q for a struct zfcp_fsf_req |
391 | * a struct zfcp_fsf_req | 195 | * @fsf_req: pointer to struct fsf_req |
196 | * Returns: pointer to qdio_buffer_element (SBALE) structure | ||
392 | */ | 197 | */ |
393 | volatile struct qdio_buffer_element * | 198 | volatile struct qdio_buffer_element * |
394 | zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale) | 199 | zfcp_qdio_sbale_req(struct zfcp_fsf_req *req) |
395 | { | 200 | { |
396 | return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue, | 201 | return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, 0); |
397 | sbal, sbale); | ||
398 | } | 202 | } |
399 | 203 | ||
400 | /** | 204 | /** |
401 | * zfcp_qdio_sbale_resp - return pointer to SBALE of response_queue for | 205 | * zfcp_qdio_sbale_curr - return curr SBALE on req_q for a struct zfcp_fsf_req |
402 | * a struct zfcp_fsf_req | 206 | * @fsf_req: pointer to struct fsf_req |
403 | */ | 207 | * Returns: pointer to qdio_buffer_element (SBALE) structure |
404 | static inline volatile struct qdio_buffer_element * | ||
405 | zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale) | ||
406 | { | ||
407 | return zfcp_qdio_sbale_get(&fsf_req->adapter->response_queue, | ||
408 | sbal, sbale); | ||
409 | } | ||
410 | |||
411 | /** | ||
412 | * zfcp_qdio_sbale_curr - return current SBALE on request_queue for | ||
413 | * a struct zfcp_fsf_req | ||
414 | */ | 208 | */ |
415 | volatile struct qdio_buffer_element * | 209 | volatile struct qdio_buffer_element * |
416 | zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req) | 210 | zfcp_qdio_sbale_curr(struct zfcp_fsf_req *req) |
417 | { | 211 | { |
418 | return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, | 212 | return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, |
419 | fsf_req->sbale_curr); | 213 | req->sbale_curr); |
420 | } | 214 | } |
421 | 215 | ||
422 | /** | 216 | static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) |
423 | * zfcp_qdio_sbal_limit - determine maximum number of SBALs that can be used | ||
424 | * on the request_queue for a struct zfcp_fsf_req | ||
425 | * @fsf_req: the number of the last SBAL that can be used is stored herein | ||
426 | * @max_sbals: used to pass an upper limit for the number of SBALs | ||
427 | * | ||
428 | * Note: We can assume at least one free SBAL in the request_queue when called. | ||
429 | */ | ||
430 | static void | ||
431 | zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) | ||
432 | { | 217 | { |
433 | int count = atomic_read(&fsf_req->adapter->request_queue.free_count); | 218 | int count = atomic_read(&fsf_req->adapter->req_q.count); |
434 | count = min(count, max_sbals); | 219 | count = min(count, max_sbals); |
435 | fsf_req->sbal_last = fsf_req->sbal_first; | 220 | fsf_req->sbal_limit = (fsf_req->sbal_first + count - 1) |
436 | fsf_req->sbal_last += (count - 1); | 221 | % QDIO_MAX_BUFFERS_PER_Q; |
437 | fsf_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q; | ||
438 | } | 222 | } |
439 | 223 | ||
440 | /** | ||
441 | * zfcp_qdio_sbal_chain - chain SBALs if more than one SBAL is needed for a | ||
442 | * request | ||
443 | * @fsf_req: zfcp_fsf_req to be processed | ||
444 | * @sbtype: SBAL flags which have to be set in first SBALE of new SBAL | ||
445 | * | ||
446 | * This function changes sbal_curr, sbale_curr, sbal_number of fsf_req. | ||
447 | */ | ||
448 | static volatile struct qdio_buffer_element * | 224 | static volatile struct qdio_buffer_element * |
449 | zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) | 225 | zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) |
450 | { | 226 | { |
@@ -455,16 +231,16 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) | |||
455 | sbale->flags |= SBAL_FLAGS_LAST_ENTRY; | 231 | sbale->flags |= SBAL_FLAGS_LAST_ENTRY; |
456 | 232 | ||
457 | /* don't exceed last allowed SBAL */ | 233 | /* don't exceed last allowed SBAL */ |
458 | if (fsf_req->sbal_curr == fsf_req->sbal_last) | 234 | if (fsf_req->sbal_last == fsf_req->sbal_limit) |
459 | return NULL; | 235 | return NULL; |
460 | 236 | ||
461 | /* set chaining flag in first SBALE of current SBAL */ | 237 | /* set chaining flag in first SBALE of current SBAL */ |
462 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 238 | sbale = zfcp_qdio_sbale_req(fsf_req); |
463 | sbale->flags |= SBAL_FLAGS0_MORE_SBALS; | 239 | sbale->flags |= SBAL_FLAGS0_MORE_SBALS; |
464 | 240 | ||
465 | /* calculate index of next SBAL */ | 241 | /* calculate index of next SBAL */ |
466 | fsf_req->sbal_curr++; | 242 | fsf_req->sbal_last++; |
467 | fsf_req->sbal_curr %= QDIO_MAX_BUFFERS_PER_Q; | 243 | fsf_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q; |
468 | 244 | ||
469 | /* keep this requests number of SBALs up-to-date */ | 245 | /* keep this requests number of SBALs up-to-date */ |
470 | fsf_req->sbal_number++; | 246 | fsf_req->sbal_number++; |
@@ -479,214 +255,255 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) | |||
479 | return sbale; | 255 | return sbale; |
480 | } | 256 | } |
481 | 257 | ||
482 | /** | ||
483 | * zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed | ||
484 | */ | ||
485 | static volatile struct qdio_buffer_element * | 258 | static volatile struct qdio_buffer_element * |
486 | zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) | 259 | zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) |
487 | { | 260 | { |
488 | if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) | 261 | if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) |
489 | return zfcp_qdio_sbal_chain(fsf_req, sbtype); | 262 | return zfcp_qdio_sbal_chain(fsf_req, sbtype); |
490 | |||
491 | fsf_req->sbale_curr++; | 263 | fsf_req->sbale_curr++; |
492 | |||
493 | return zfcp_qdio_sbale_curr(fsf_req); | 264 | return zfcp_qdio_sbale_curr(fsf_req); |
494 | } | 265 | } |
495 | 266 | ||
496 | /** | 267 | static void zfcp_qdio_undo_sbals(struct zfcp_fsf_req *fsf_req) |
497 | * zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue | ||
498 | * with zero from | ||
499 | */ | ||
500 | static int | ||
501 | zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last) | ||
502 | { | ||
503 | struct qdio_buffer **buf = queue->buffer; | ||
504 | int curr = first; | ||
505 | int count = 0; | ||
506 | |||
507 | for(;;) { | ||
508 | curr %= QDIO_MAX_BUFFERS_PER_Q; | ||
509 | count++; | ||
510 | memset(buf[curr], 0, sizeof(struct qdio_buffer)); | ||
511 | if (curr == last) | ||
512 | break; | ||
513 | curr++; | ||
514 | } | ||
515 | return count; | ||
516 | } | ||
517 | |||
518 | |||
519 | /** | ||
520 | * zfcp_qdio_sbals_wipe - reset all changes in SBALs for an fsf_req | ||
521 | */ | ||
522 | static inline int | ||
523 | zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req) | ||
524 | { | 268 | { |
525 | return zfcp_qdio_sbals_zero(&fsf_req->adapter->request_queue, | 269 | struct qdio_buffer **sbal = fsf_req->adapter->req_q.sbal; |
526 | fsf_req->sbal_first, fsf_req->sbal_curr); | 270 | int first = fsf_req->sbal_first; |
271 | int last = fsf_req->sbal_last; | ||
272 | int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) % | ||
273 | QDIO_MAX_BUFFERS_PER_Q + 1; | ||
274 | zfcp_qdio_zero_sbals(sbal, first, count); | ||
527 | } | 275 | } |
528 | 276 | ||
529 | 277 | static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req, | |
530 | /** | 278 | unsigned int sbtype, void *start_addr, |
531 | * zfcp_qdio_sbale_fill - set address and length in current SBALE | 279 | unsigned int total_length) |
532 | * on request_queue | ||
533 | */ | ||
534 | static void | ||
535 | zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, | ||
536 | void *addr, int length) | ||
537 | { | 280 | { |
538 | volatile struct qdio_buffer_element *sbale; | 281 | volatile struct qdio_buffer_element *sbale; |
539 | |||
540 | sbale = zfcp_qdio_sbale_curr(fsf_req); | ||
541 | sbale->addr = addr; | ||
542 | sbale->length = length; | ||
543 | } | ||
544 | |||
545 | /** | ||
546 | * zfcp_qdio_sbals_from_segment - map memory segment to SBALE(s) | ||
547 | * @fsf_req: request to be processed | ||
548 | * @sbtype: SBALE flags | ||
549 | * @start_addr: address of memory segment | ||
550 | * @total_length: length of memory segment | ||
551 | * | ||
552 | * Alignment and length of the segment determine how many SBALEs are needed | ||
553 | * for the memory segment. | ||
554 | */ | ||
555 | static int | ||
556 | zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, | ||
557 | void *start_addr, unsigned long total_length) | ||
558 | { | ||
559 | unsigned long remaining, length; | 282 | unsigned long remaining, length; |
560 | void *addr; | 283 | void *addr; |
561 | 284 | ||
562 | /* split segment up heeding page boundaries */ | 285 | /* split segment up */ |
563 | for (addr = start_addr, remaining = total_length; remaining > 0; | 286 | for (addr = start_addr, remaining = total_length; remaining > 0; |
564 | addr += length, remaining -= length) { | 287 | addr += length, remaining -= length) { |
565 | /* get next free SBALE for new piece */ | 288 | sbale = zfcp_qdio_sbale_next(fsf_req, sbtype); |
566 | if (NULL == zfcp_qdio_sbale_next(fsf_req, sbtype)) { | 289 | if (!sbale) { |
567 | /* no SBALE left, clean up and leave */ | 290 | zfcp_qdio_undo_sbals(fsf_req); |
568 | zfcp_qdio_sbals_wipe(fsf_req); | ||
569 | return -EINVAL; | 291 | return -EINVAL; |
570 | } | 292 | } |
571 | /* calculate length of new piece */ | 293 | |
294 | /* new piece must not exceed next page boundary */ | ||
572 | length = min(remaining, | 295 | length = min(remaining, |
573 | (PAGE_SIZE - ((unsigned long) addr & | 296 | (PAGE_SIZE - ((unsigned long)addr & |
574 | (PAGE_SIZE - 1)))); | 297 | (PAGE_SIZE - 1)))); |
575 | /* fill current SBALE with calculated piece */ | 298 | sbale->addr = addr; |
576 | zfcp_qdio_sbale_fill(fsf_req, sbtype, addr, length); | 299 | sbale->length = length; |
577 | } | 300 | } |
578 | return total_length; | 301 | return 0; |
579 | } | 302 | } |
580 | 303 | ||
581 | |||
582 | /** | 304 | /** |
583 | * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list | 305 | * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list |
584 | * @fsf_req: request to be processed | 306 | * @fsf_req: request to be processed |
585 | * @sbtype: SBALE flags | 307 | * @sbtype: SBALE flags |
586 | * @sg: scatter-gather list | 308 | * @sg: scatter-gather list |
587 | * @sg_count: number of elements in scatter-gather list | ||
588 | * @max_sbals: upper bound for number of SBALs to be used | 309 | * @max_sbals: upper bound for number of SBALs to be used |
310 | * Returns: number of bytes, or error (negativ) | ||
589 | */ | 311 | */ |
590 | int | 312 | int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, |
591 | zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, | 313 | struct scatterlist *sg, int max_sbals) |
592 | struct scatterlist *sgl, int sg_count, int max_sbals) | ||
593 | { | 314 | { |
594 | int sg_index; | ||
595 | struct scatterlist *sg_segment; | ||
596 | int retval; | ||
597 | volatile struct qdio_buffer_element *sbale; | 315 | volatile struct qdio_buffer_element *sbale; |
598 | int bytes = 0; | 316 | int retval, bytes = 0; |
599 | 317 | ||
600 | /* figure out last allowed SBAL */ | 318 | /* figure out last allowed SBAL */ |
601 | zfcp_qdio_sbal_limit(fsf_req, max_sbals); | 319 | zfcp_qdio_sbal_limit(fsf_req, max_sbals); |
602 | 320 | ||
603 | /* set storage-block type for current SBAL */ | 321 | /* set storage-block type for this request */ |
604 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 322 | sbale = zfcp_qdio_sbale_req(fsf_req); |
605 | sbale->flags |= sbtype; | 323 | sbale->flags |= sbtype; |
606 | 324 | ||
607 | /* process all segements of scatter-gather list */ | 325 | for (; sg; sg = sg_next(sg)) { |
608 | for_each_sg(sgl, sg_segment, sg_count, sg_index) { | 326 | retval = zfcp_qdio_fill_sbals(fsf_req, sbtype, sg_virt(sg), |
609 | retval = zfcp_qdio_sbals_from_segment( | 327 | sg->length); |
610 | fsf_req, | 328 | if (retval < 0) |
611 | sbtype, | 329 | return retval; |
612 | zfcp_sg_to_address(sg_segment), | 330 | bytes += sg->length; |
613 | sg_segment->length); | ||
614 | if (retval < 0) { | ||
615 | bytes = retval; | ||
616 | goto out; | ||
617 | } else | ||
618 | bytes += retval; | ||
619 | } | 331 | } |
332 | |||
620 | /* assume that no other SBALEs are to follow in the same SBAL */ | 333 | /* assume that no other SBALEs are to follow in the same SBAL */ |
621 | sbale = zfcp_qdio_sbale_curr(fsf_req); | 334 | sbale = zfcp_qdio_sbale_curr(fsf_req); |
622 | sbale->flags |= SBAL_FLAGS_LAST_ENTRY; | 335 | sbale->flags |= SBAL_FLAGS_LAST_ENTRY; |
623 | out: | 336 | |
624 | return bytes; | 337 | return bytes; |
625 | } | 338 | } |
626 | 339 | ||
627 | |||
628 | /** | 340 | /** |
629 | * zfcp_qdio_sbals_from_scsicmnd - fill SBALs from scsi command | 341 | * zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO |
630 | * @fsf_req: request to be processed | 342 | * @fsf_req: pointer to struct zfcp_fsf_req |
631 | * @sbtype: SBALE flags | 343 | * Returns: 0 on success, error otherwise |
632 | * @scsi_cmnd: either scatter-gather list or buffer contained herein is used | ||
633 | * to fill SBALs | ||
634 | */ | 344 | */ |
635 | int | 345 | int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req) |
636 | zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req, | ||
637 | unsigned long sbtype, struct scsi_cmnd *scsi_cmnd) | ||
638 | { | 346 | { |
639 | return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, scsi_sglist(scsi_cmnd), | 347 | struct zfcp_adapter *adapter = fsf_req->adapter; |
640 | scsi_sg_count(scsi_cmnd), | 348 | struct zfcp_qdio_queue *req_q = &adapter->req_q; |
641 | ZFCP_MAX_SBALS_PER_REQ); | 349 | int first = fsf_req->sbal_first; |
350 | int count = fsf_req->sbal_number; | ||
351 | int retval, pci, pci_batch; | ||
352 | volatile struct qdio_buffer_element *sbale; | ||
353 | |||
354 | /* acknowledgements for transferred buffers */ | ||
355 | pci_batch = req_q->pci_batch + count; | ||
356 | if (unlikely(pci_batch >= ZFCP_QDIO_PCI_INTERVAL)) { | ||
357 | pci_batch %= ZFCP_QDIO_PCI_INTERVAL; | ||
358 | pci = first + count - (pci_batch + 1); | ||
359 | pci %= QDIO_MAX_BUFFERS_PER_Q; | ||
360 | sbale = zfcp_qdio_sbale(req_q, pci, 0); | ||
361 | sbale->flags |= SBAL_FLAGS0_PCI; | ||
362 | } | ||
363 | |||
364 | retval = do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0, first, | ||
365 | count, NULL); | ||
366 | if (unlikely(retval)) { | ||
367 | zfcp_qdio_zero_sbals(req_q->sbal, first, count); | ||
368 | return retval; | ||
369 | } | ||
370 | |||
371 | /* account for transferred buffers */ | ||
372 | atomic_sub(count, &req_q->count); | ||
373 | req_q->first += count; | ||
374 | req_q->first %= QDIO_MAX_BUFFERS_PER_Q; | ||
375 | req_q->pci_batch = pci_batch; | ||
376 | return 0; | ||
642 | } | 377 | } |
643 | 378 | ||
644 | /** | 379 | /** |
645 | * zfcp_qdio_determine_pci - set PCI flag in first SBALE on qdio queue if needed | 380 | * zfcp_qdio_allocate - allocate queue memory and initialize QDIO data |
381 | * @adapter: pointer to struct zfcp_adapter | ||
382 | * Returns: -ENOMEM on memory allocation error or return value from | ||
383 | * qdio_allocate | ||
646 | */ | 384 | */ |
647 | int | 385 | int zfcp_qdio_allocate(struct zfcp_adapter *adapter) |
648 | zfcp_qdio_determine_pci(struct zfcp_qdio_queue *req_queue, | ||
649 | struct zfcp_fsf_req *fsf_req) | ||
650 | { | 386 | { |
651 | int new_distance_from_int; | 387 | struct qdio_initialize *init_data; |
652 | int pci_pos; | ||
653 | volatile struct qdio_buffer_element *sbale; | ||
654 | 388 | ||
655 | new_distance_from_int = req_queue->distance_from_int + | 389 | if (zfcp_qdio_buffers_enqueue(adapter->req_q.sbal) || |
656 | fsf_req->sbal_number; | 390 | zfcp_qdio_buffers_enqueue(adapter->resp_q.sbal)) |
657 | 391 | return -ENOMEM; | |
658 | if (unlikely(new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL)) { | 392 | |
659 | new_distance_from_int %= ZFCP_QDIO_PCI_INTERVAL; | 393 | init_data = &adapter->qdio_init_data; |
660 | pci_pos = fsf_req->sbal_first; | 394 | |
661 | pci_pos += fsf_req->sbal_number; | 395 | init_data->cdev = adapter->ccw_device; |
662 | pci_pos -= new_distance_from_int; | 396 | init_data->q_format = QDIO_ZFCP_QFMT; |
663 | pci_pos -= 1; | 397 | memcpy(init_data->adapter_name, zfcp_get_busid_by_adapter(adapter), 8); |
664 | pci_pos %= QDIO_MAX_BUFFERS_PER_Q; | 398 | ASCEBC(init_data->adapter_name, 8); |
665 | sbale = zfcp_qdio_sbale_req(fsf_req, pci_pos, 0); | 399 | init_data->qib_param_field_format = 0; |
666 | sbale->flags |= SBAL_FLAGS0_PCI; | 400 | init_data->qib_param_field = NULL; |
667 | } | 401 | init_data->input_slib_elements = NULL; |
668 | return new_distance_from_int; | 402 | init_data->output_slib_elements = NULL; |
403 | init_data->min_input_threshold = 1; | ||
404 | init_data->max_input_threshold = 5000; | ||
405 | init_data->min_output_threshold = 1; | ||
406 | init_data->max_output_threshold = 1000; | ||
407 | init_data->no_input_qs = 1; | ||
408 | init_data->no_output_qs = 1; | ||
409 | init_data->input_handler = zfcp_qdio_int_resp; | ||
410 | init_data->output_handler = zfcp_qdio_int_req; | ||
411 | init_data->int_parm = (unsigned long) adapter; | ||
412 | init_data->flags = QDIO_INBOUND_0COPY_SBALS | | ||
413 | QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS; | ||
414 | init_data->input_sbal_addr_array = | ||
415 | (void **) (adapter->resp_q.sbal); | ||
416 | init_data->output_sbal_addr_array = | ||
417 | (void **) (adapter->req_q.sbal); | ||
418 | |||
419 | return qdio_allocate(init_data); | ||
669 | } | 420 | } |
670 | 421 | ||
671 | /* | 422 | /** |
672 | * function: zfcp_zero_sbals | 423 | * zfcp_close_qdio - close qdio queues for an adapter |
673 | * | ||
674 | * purpose: zeros specified range of SBALs | ||
675 | * | ||
676 | * returns: | ||
677 | */ | 424 | */ |
678 | void | 425 | void zfcp_qdio_close(struct zfcp_adapter *adapter) |
679 | zfcp_qdio_zero_sbals(struct qdio_buffer *buf[], int first, int clean_count) | ||
680 | { | 426 | { |
681 | int cur_pos; | 427 | struct zfcp_qdio_queue *req_q; |
682 | int index; | 428 | int first, count; |
683 | 429 | ||
684 | for (cur_pos = first; cur_pos < (first + clean_count); cur_pos++) { | 430 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) |
685 | index = cur_pos % QDIO_MAX_BUFFERS_PER_Q; | 431 | return; |
686 | memset(buf[index], 0, sizeof (struct qdio_buffer)); | 432 | |
687 | ZFCP_LOG_TRACE("zeroing BUFFER %d at address %p\n", | 433 | /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ |
688 | index, buf[index]); | 434 | req_q = &adapter->req_q; |
435 | spin_lock(&req_q->lock); | ||
436 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); | ||
437 | spin_unlock(&req_q->lock); | ||
438 | |||
439 | while (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR) | ||
440 | == -EINPROGRESS) | ||
441 | ssleep(1); | ||
442 | |||
443 | /* cleanup used outbound sbals */ | ||
444 | count = atomic_read(&req_q->count); | ||
445 | if (count < QDIO_MAX_BUFFERS_PER_Q) { | ||
446 | first = (req_q->first + count) % QDIO_MAX_BUFFERS_PER_Q; | ||
447 | count = QDIO_MAX_BUFFERS_PER_Q - count; | ||
448 | zfcp_qdio_zero_sbals(req_q->sbal, first, count); | ||
689 | } | 449 | } |
450 | req_q->first = 0; | ||
451 | atomic_set(&req_q->count, 0); | ||
452 | req_q->pci_batch = 0; | ||
453 | adapter->resp_q.first = 0; | ||
454 | atomic_set(&adapter->resp_q.count, 0); | ||
690 | } | 455 | } |
691 | 456 | ||
692 | #undef ZFCP_LOG_AREA | 457 | /** |
458 | * zfcp_qdio_open - prepare and initialize response queue | ||
459 | * @adapter: pointer to struct zfcp_adapter | ||
460 | * Returns: 0 on success, otherwise -EIO | ||
461 | */ | ||
462 | int zfcp_qdio_open(struct zfcp_adapter *adapter) | ||
463 | { | ||
464 | volatile struct qdio_buffer_element *sbale; | ||
465 | int cc; | ||
466 | |||
467 | if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) | ||
468 | return -EIO; | ||
469 | |||
470 | if (qdio_establish(&adapter->qdio_init_data)) { | ||
471 | dev_err(&adapter->ccw_device->dev, | ||
472 | "Establish of QDIO queues failed.\n"); | ||
473 | return -EIO; | ||
474 | } | ||
475 | |||
476 | if (qdio_activate(adapter->ccw_device, 0)) { | ||
477 | dev_err(&adapter->ccw_device->dev, | ||
478 | "Activate of QDIO queues failed.\n"); | ||
479 | goto failed_qdio; | ||
480 | } | ||
481 | |||
482 | for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) { | ||
483 | sbale = &(adapter->resp_q.sbal[cc]->element[0]); | ||
484 | sbale->length = 0; | ||
485 | sbale->flags = SBAL_FLAGS_LAST_ENTRY; | ||
486 | sbale->addr = NULL; | ||
487 | } | ||
488 | |||
489 | if (do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_INPUT, 0, 0, | ||
490 | QDIO_MAX_BUFFERS_PER_Q, NULL)) { | ||
491 | dev_err(&adapter->ccw_device->dev, | ||
492 | "Init of QDIO response queue failed.\n"); | ||
493 | goto failed_qdio; | ||
494 | } | ||
495 | |||
496 | /* set index of first avalable SBALS / number of available SBALS */ | ||
497 | adapter->req_q.first = 0; | ||
498 | atomic_set(&adapter->req_q.count, QDIO_MAX_BUFFERS_PER_Q); | ||
499 | adapter->req_q.pci_batch = 0; | ||
500 | |||
501 | return 0; | ||
502 | |||
503 | failed_qdio: | ||
504 | while (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR) | ||
505 | == -EINPROGRESS) | ||
506 | ssleep(1); | ||
507 | |||
508 | return -EIO; | ||
509 | } | ||
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 01687559dc06..aeae56b00b45 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -1,220 +1,65 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Interface to Linux SCSI midlayer. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI | ||
23 | |||
24 | #include "zfcp_ext.h" | 9 | #include "zfcp_ext.h" |
25 | #include <asm/atomic.h> | 10 | #include <asm/atomic.h> |
26 | 11 | ||
27 | static void zfcp_scsi_slave_destroy(struct scsi_device *sdp); | ||
28 | static int zfcp_scsi_slave_alloc(struct scsi_device *sdp); | ||
29 | static int zfcp_scsi_slave_configure(struct scsi_device *sdp); | ||
30 | static int zfcp_scsi_queuecommand(struct scsi_cmnd *, | ||
31 | void (*done) (struct scsi_cmnd *)); | ||
32 | static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *); | ||
33 | static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *); | ||
34 | static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *); | ||
35 | static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *); | ||
36 | static int zfcp_task_management_function(struct zfcp_unit *, u8, | ||
37 | struct scsi_cmnd *); | ||
38 | |||
39 | static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, | ||
40 | unsigned int, unsigned int); | ||
41 | |||
42 | static struct device_attribute *zfcp_sysfs_sdev_attrs[]; | ||
43 | static struct device_attribute *zfcp_a_stats_attrs[]; | ||
44 | |||
45 | struct zfcp_data zfcp_data = { | ||
46 | .scsi_host_template = { | ||
47 | .name = ZFCP_NAME, | ||
48 | .module = THIS_MODULE, | ||
49 | .proc_name = "zfcp", | ||
50 | .slave_alloc = zfcp_scsi_slave_alloc, | ||
51 | .slave_configure = zfcp_scsi_slave_configure, | ||
52 | .slave_destroy = zfcp_scsi_slave_destroy, | ||
53 | .queuecommand = zfcp_scsi_queuecommand, | ||
54 | .eh_abort_handler = zfcp_scsi_eh_abort_handler, | ||
55 | .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler, | ||
56 | .eh_target_reset_handler = zfcp_scsi_eh_target_reset_handler, | ||
57 | .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler, | ||
58 | .can_queue = 4096, | ||
59 | .this_id = -1, | ||
60 | .sg_tablesize = ZFCP_MAX_SBALES_PER_REQ, | ||
61 | .cmd_per_lun = 1, | ||
62 | .use_clustering = 1, | ||
63 | .sdev_attrs = zfcp_sysfs_sdev_attrs, | ||
64 | .max_sectors = ZFCP_MAX_SECTORS, | ||
65 | .shost_attrs = zfcp_a_stats_attrs, | ||
66 | }, | ||
67 | .driver_version = ZFCP_VERSION, | ||
68 | }; | ||
69 | |||
70 | /* Find start of Response Information in FCP response unit*/ | ||
71 | char * | ||
72 | zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) | ||
73 | { | ||
74 | char *fcp_rsp_info_ptr; | ||
75 | |||
76 | fcp_rsp_info_ptr = | ||
77 | (unsigned char *) fcp_rsp_iu + (sizeof (struct fcp_rsp_iu)); | ||
78 | |||
79 | return fcp_rsp_info_ptr; | ||
80 | } | ||
81 | |||
82 | /* Find start of Sense Information in FCP response unit*/ | 12 | /* Find start of Sense Information in FCP response unit*/ |
83 | char * | 13 | char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) |
84 | zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) | ||
85 | { | 14 | { |
86 | char *fcp_sns_info_ptr; | 15 | char *fcp_sns_info_ptr; |
87 | 16 | ||
88 | fcp_sns_info_ptr = | 17 | fcp_sns_info_ptr = (unsigned char *) &fcp_rsp_iu[1]; |
89 | (unsigned char *) fcp_rsp_iu + (sizeof (struct fcp_rsp_iu)); | ||
90 | if (fcp_rsp_iu->validity.bits.fcp_rsp_len_valid) | 18 | if (fcp_rsp_iu->validity.bits.fcp_rsp_len_valid) |
91 | fcp_sns_info_ptr = (char *) fcp_sns_info_ptr + | 19 | fcp_sns_info_ptr += fcp_rsp_iu->fcp_rsp_len; |
92 | fcp_rsp_iu->fcp_rsp_len; | ||
93 | 20 | ||
94 | return fcp_sns_info_ptr; | 21 | return fcp_sns_info_ptr; |
95 | } | 22 | } |
96 | 23 | ||
97 | static fcp_dl_t * | 24 | void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl) |
98 | zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd) | ||
99 | { | 25 | { |
100 | int additional_length = fcp_cmd->add_fcp_cdb_length << 2; | 26 | fcp_dl_t *fcp_dl_ptr; |
101 | fcp_dl_t *fcp_dl_addr; | ||
102 | 27 | ||
103 | fcp_dl_addr = (fcp_dl_t *) | ||
104 | ((unsigned char *) fcp_cmd + | ||
105 | sizeof (struct fcp_cmnd_iu) + additional_length); | ||
106 | /* | 28 | /* |
107 | * fcp_dl_addr = start address of fcp_cmnd structure + | 29 | * fcp_dl_addr = start address of fcp_cmnd structure + |
108 | * size of fixed part + size of dynamically sized add_dcp_cdb field | 30 | * size of fixed part + size of dynamically sized add_dcp_cdb field |
109 | * SEE FCP-2 documentation | 31 | * SEE FCP-2 documentation |
110 | */ | 32 | */ |
111 | return fcp_dl_addr; | 33 | fcp_dl_ptr = (fcp_dl_t *) ((unsigned char *) &fcp_cmd[1] + |
34 | (fcp_cmd->add_fcp_cdb_length << 2)); | ||
35 | *fcp_dl_ptr = fcp_dl; | ||
112 | } | 36 | } |
113 | 37 | ||
114 | fcp_dl_t | ||
115 | zfcp_get_fcp_dl(struct fcp_cmnd_iu * fcp_cmd) | ||
116 | { | ||
117 | return *zfcp_get_fcp_dl_ptr(fcp_cmd); | ||
118 | } | ||
119 | |||
120 | void | ||
121 | zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl) | ||
122 | { | ||
123 | *zfcp_get_fcp_dl_ptr(fcp_cmd) = fcp_dl; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * note: it's a bit-or operation not an assignment | ||
128 | * regarding the specified byte | ||
129 | */ | ||
130 | static inline void | ||
131 | set_byte(int *result, char status, char pos) | ||
132 | { | ||
133 | *result |= status << (pos * 8); | ||
134 | } | ||
135 | |||
136 | void | ||
137 | set_host_byte(int *result, char status) | ||
138 | { | ||
139 | set_byte(result, status, 2); | ||
140 | } | ||
141 | |||
142 | void | ||
143 | set_driver_byte(int *result, char status) | ||
144 | { | ||
145 | set_byte(result, status, 3); | ||
146 | } | ||
147 | |||
148 | static int | ||
149 | zfcp_scsi_slave_alloc(struct scsi_device *sdp) | ||
150 | { | ||
151 | struct zfcp_adapter *adapter; | ||
152 | struct zfcp_unit *unit; | ||
153 | unsigned long flags; | ||
154 | int retval = -ENXIO; | ||
155 | |||
156 | adapter = (struct zfcp_adapter *) sdp->host->hostdata[0]; | ||
157 | if (!adapter) | ||
158 | goto out; | ||
159 | |||
160 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
161 | unit = zfcp_unit_lookup(adapter, sdp->channel, sdp->id, sdp->lun); | ||
162 | if (unit && atomic_test_mask(ZFCP_STATUS_UNIT_REGISTERED, | ||
163 | &unit->status)) { | ||
164 | sdp->hostdata = unit; | ||
165 | unit->device = sdp; | ||
166 | zfcp_unit_get(unit); | ||
167 | retval = 0; | ||
168 | } | ||
169 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
170 | out: | ||
171 | return retval; | ||
172 | } | ||
173 | |||
174 | /** | ||
175 | * zfcp_scsi_slave_destroy - called when scsi device is removed | ||
176 | * | ||
177 | * Remove reference to associated scsi device for an zfcp_unit. | ||
178 | * Mark zfcp_unit as failed. The scsi device might be deleted via sysfs | ||
179 | * or a scan for this device might have failed. | ||
180 | */ | ||
181 | static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) | 38 | static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) |
182 | { | 39 | { |
183 | struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; | 40 | struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; |
184 | 41 | WARN_ON(!unit); | |
185 | if (unit) { | 42 | if (unit) { |
186 | atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); | 43 | atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); |
187 | sdpnt->hostdata = NULL; | 44 | sdpnt->hostdata = NULL; |
188 | unit->device = NULL; | 45 | unit->device = NULL; |
189 | zfcp_erp_unit_failed(unit, 12, NULL); | 46 | zfcp_erp_unit_failed(unit, 12, NULL); |
190 | zfcp_unit_put(unit); | 47 | zfcp_unit_put(unit); |
191 | } else | 48 | } |
192 | ZFCP_LOG_NORMAL("bug: no unit associated with SCSI device at " | ||
193 | "address %p\n", sdpnt); | ||
194 | } | 49 | } |
195 | 50 | ||
196 | /* | 51 | static int zfcp_scsi_slave_configure(struct scsi_device *sdp) |
197 | * called from scsi midlayer to allow finetuning of a device. | ||
198 | */ | ||
199 | static int | ||
200 | zfcp_scsi_slave_configure(struct scsi_device *sdp) | ||
201 | { | 52 | { |
202 | if (sdp->tagged_supported) | 53 | if (sdp->tagged_supported) |
203 | scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, ZFCP_CMND_PER_LUN); | 54 | scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, 32); |
204 | else | 55 | else |
205 | scsi_adjust_queue_depth(sdp, 0, 1); | 56 | scsi_adjust_queue_depth(sdp, 0, 1); |
206 | return 0; | 57 | return 0; |
207 | } | 58 | } |
208 | 59 | ||
209 | /** | 60 | static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) |
210 | * zfcp_scsi_command_fail - set result in scsi_cmnd and call scsi_done function | ||
211 | * @scpnt: pointer to struct scsi_cmnd where result is set | ||
212 | * @result: result to be set in scpnt (e.g. DID_ERROR) | ||
213 | */ | ||
214 | static void | ||
215 | zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) | ||
216 | { | 61 | { |
217 | set_host_byte(&scpnt->result, result); | 62 | set_host_byte(scpnt, result); |
218 | if ((scpnt->device != NULL) && (scpnt->device->host != NULL)) | 63 | if ((scpnt->device != NULL) && (scpnt->device->host != NULL)) |
219 | zfcp_scsi_dbf_event_result("fail", 4, | 64 | zfcp_scsi_dbf_event_result("fail", 4, |
220 | (struct zfcp_adapter*) scpnt->device->host->hostdata[0], | 65 | (struct zfcp_adapter*) scpnt->device->host->hostdata[0], |
@@ -223,114 +68,13 @@ zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) | |||
223 | scpnt->scsi_done(scpnt); | 68 | scpnt->scsi_done(scpnt); |
224 | } | 69 | } |
225 | 70 | ||
226 | /** | 71 | static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, |
227 | * zfcp_scsi_command_async - worker for zfcp_scsi_queuecommand and | 72 | void (*done) (struct scsi_cmnd *)) |
228 | * zfcp_scsi_command_sync | ||
229 | * @adapter: adapter where scsi command is issued | ||
230 | * @unit: unit to which scsi command is sent | ||
231 | * @scpnt: scsi command to be sent | ||
232 | * @timer: timer to be started if request is successfully initiated | ||
233 | * | ||
234 | * Note: In scsi_done function must be set in scpnt. | ||
235 | */ | ||
236 | int | ||
237 | zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit, | ||
238 | struct scsi_cmnd *scpnt, int use_timer) | ||
239 | { | ||
240 | int tmp; | ||
241 | int retval; | ||
242 | |||
243 | retval = 0; | ||
244 | |||
245 | BUG_ON((adapter == NULL) || (adapter != unit->port->adapter)); | ||
246 | BUG_ON(scpnt->scsi_done == NULL); | ||
247 | |||
248 | if (unlikely(NULL == unit)) { | ||
249 | zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); | ||
250 | goto out; | ||
251 | } | ||
252 | |||
253 | if (unlikely( | ||
254 | atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) || | ||
255 | !atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status))) { | ||
256 | ZFCP_LOG_DEBUG("stopping SCSI I/O on unit 0x%016Lx on port " | ||
257 | "0x%016Lx on adapter %s\n", | ||
258 | unit->fcp_lun, unit->port->wwpn, | ||
259 | zfcp_get_busid_by_adapter(adapter)); | ||
260 | zfcp_scsi_command_fail(scpnt, DID_ERROR); | ||
261 | goto out; | ||
262 | } | ||
263 | |||
264 | tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer, | ||
265 | ZFCP_REQ_AUTO_CLEANUP); | ||
266 | if (unlikely(tmp == -EBUSY)) { | ||
267 | ZFCP_LOG_DEBUG("adapter %s not ready or unit 0x%016Lx " | ||
268 | "on port 0x%016Lx in recovery\n", | ||
269 | zfcp_get_busid_by_unit(unit), | ||
270 | unit->fcp_lun, unit->port->wwpn); | ||
271 | zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); | ||
272 | goto out; | ||
273 | } | ||
274 | |||
275 | if (unlikely(tmp < 0)) { | ||
276 | ZFCP_LOG_DEBUG("error: initiation of Send FCP Cmnd failed\n"); | ||
277 | retval = SCSI_MLQUEUE_HOST_BUSY; | ||
278 | } | ||
279 | |||
280 | out: | ||
281 | return retval; | ||
282 | } | ||
283 | |||
284 | static void | ||
285 | zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt) | ||
286 | { | ||
287 | struct completion *wait = (struct completion *) scpnt->SCp.ptr; | ||
288 | complete(wait); | ||
289 | } | ||
290 | |||
291 | |||
292 | /** | ||
293 | * zfcp_scsi_command_sync - send a SCSI command and wait for completion | ||
294 | * @unit: unit where command is sent to | ||
295 | * @scpnt: scsi command to be sent | ||
296 | * @use_timer: indicates whether timer should be setup or not | ||
297 | * Return: 0 | ||
298 | * | ||
299 | * Errors are indicated in scpnt->result | ||
300 | */ | ||
301 | int | ||
302 | zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt, | ||
303 | int use_timer) | ||
304 | { | ||
305 | int ret; | ||
306 | DECLARE_COMPLETION_ONSTACK(wait); | ||
307 | |||
308 | scpnt->SCp.ptr = (void *) &wait; /* silent re-use */ | ||
309 | scpnt->scsi_done = zfcp_scsi_command_sync_handler; | ||
310 | ret = zfcp_scsi_command_async(unit->port->adapter, unit, scpnt, | ||
311 | use_timer); | ||
312 | if (ret == 0) | ||
313 | wait_for_completion(&wait); | ||
314 | |||
315 | scpnt->SCp.ptr = NULL; | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | /* | ||
321 | * function: zfcp_scsi_queuecommand | ||
322 | * | ||
323 | * purpose: enqueues a SCSI command to the specified target device | ||
324 | * | ||
325 | * returns: 0 - success, SCSI command enqueued | ||
326 | * !0 - failure | ||
327 | */ | ||
328 | static int | ||
329 | zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, | ||
330 | void (*done) (struct scsi_cmnd *)) | ||
331 | { | 73 | { |
332 | struct zfcp_unit *unit; | 74 | struct zfcp_unit *unit; |
333 | struct zfcp_adapter *adapter; | 75 | struct zfcp_adapter *adapter; |
76 | int status; | ||
77 | int ret; | ||
334 | 78 | ||
335 | /* reset the status for this request */ | 79 | /* reset the status for this request */ |
336 | scpnt->result = 0; | 80 | scpnt->result = 0; |
@@ -342,44 +86,76 @@ zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, | |||
342 | * (stored there by zfcp_scsi_slave_alloc) | 86 | * (stored there by zfcp_scsi_slave_alloc) |
343 | */ | 87 | */ |
344 | adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; | 88 | adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; |
345 | unit = (struct zfcp_unit *) scpnt->device->hostdata; | 89 | unit = scpnt->device->hostdata; |
90 | |||
91 | BUG_ON(!adapter || (adapter != unit->port->adapter)); | ||
92 | BUG_ON(!scpnt->scsi_done); | ||
346 | 93 | ||
347 | return zfcp_scsi_command_async(adapter, unit, scpnt, 0); | 94 | if (unlikely(!unit)) { |
95 | zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | status = atomic_read(&unit->status); | ||
100 | if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) || | ||
101 | !(status & ZFCP_STATUS_COMMON_RUNNING))) { | ||
102 | zfcp_scsi_command_fail(scpnt, DID_ERROR); | ||
103 | return 0;; | ||
104 | } | ||
105 | |||
106 | ret = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, 0, | ||
107 | ZFCP_REQ_AUTO_CLEANUP); | ||
108 | if (unlikely(ret == -EBUSY)) | ||
109 | zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); | ||
110 | else if (unlikely(ret < 0)) | ||
111 | return SCSI_MLQUEUE_HOST_BUSY; | ||
112 | |||
113 | return ret; | ||
348 | } | 114 | } |
349 | 115 | ||
350 | static struct zfcp_unit * | 116 | static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter, |
351 | zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id, | 117 | int channel, unsigned int id, |
352 | unsigned int lun) | 118 | unsigned int lun) |
353 | { | 119 | { |
354 | struct zfcp_port *port; | 120 | struct zfcp_port *port; |
355 | struct zfcp_unit *unit, *retval = NULL; | 121 | struct zfcp_unit *unit; |
356 | 122 | ||
357 | list_for_each_entry(port, &adapter->port_list_head, list) { | 123 | list_for_each_entry(port, &adapter->port_list_head, list) { |
358 | if (!port->rport || (id != port->rport->scsi_target_id)) | 124 | if (!port->rport || (id != port->rport->scsi_target_id)) |
359 | continue; | 125 | continue; |
360 | list_for_each_entry(unit, &port->unit_list_head, list) | 126 | list_for_each_entry(unit, &port->unit_list_head, list) |
361 | if (lun == unit->scsi_lun) { | 127 | if (lun == unit->scsi_lun) |
362 | retval = unit; | 128 | return unit; |
363 | goto out; | ||
364 | } | ||
365 | } | 129 | } |
366 | out: | 130 | |
131 | return NULL; | ||
132 | } | ||
133 | |||
134 | static int zfcp_scsi_slave_alloc(struct scsi_device *sdp) | ||
135 | { | ||
136 | struct zfcp_adapter *adapter; | ||
137 | struct zfcp_unit *unit; | ||
138 | unsigned long flags; | ||
139 | int retval = -ENXIO; | ||
140 | |||
141 | adapter = (struct zfcp_adapter *) sdp->host->hostdata[0]; | ||
142 | if (!adapter) | ||
143 | goto out; | ||
144 | |||
145 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
146 | unit = zfcp_unit_lookup(adapter, sdp->channel, sdp->id, sdp->lun); | ||
147 | if (unit && | ||
148 | (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_REGISTERED)) { | ||
149 | sdp->hostdata = unit; | ||
150 | unit->device = sdp; | ||
151 | zfcp_unit_get(unit); | ||
152 | retval = 0; | ||
153 | } | ||
154 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
155 | out: | ||
367 | return retval; | 156 | return retval; |
368 | } | 157 | } |
369 | 158 | ||
370 | /** | ||
371 | * zfcp_scsi_eh_abort_handler - abort the specified SCSI command | ||
372 | * @scpnt: pointer to scsi_cmnd to be aborted | ||
373 | * Return: SUCCESS - command has been aborted and cleaned up in internal | ||
374 | * bookkeeping, SCSI stack won't be called for aborted command | ||
375 | * FAILED - otherwise | ||
376 | * | ||
377 | * We do not need to care for a SCSI command which completes normally | ||
378 | * but late during this abort routine runs. We are allowed to return | ||
379 | * late commands to the SCSI stack. It tracks the state of commands and | ||
380 | * will handle late commands. (Usually, the normal completion of late | ||
381 | * commands is ignored with respect to the running abort operation.) | ||
382 | */ | ||
383 | static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) | 159 | static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) |
384 | { | 160 | { |
385 | struct Scsi_Host *scsi_host; | 161 | struct Scsi_Host *scsi_host; |
@@ -387,44 +163,37 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) | |||
387 | struct zfcp_unit *unit; | 163 | struct zfcp_unit *unit; |
388 | struct zfcp_fsf_req *fsf_req; | 164 | struct zfcp_fsf_req *fsf_req; |
389 | unsigned long flags; | 165 | unsigned long flags; |
390 | unsigned long old_req_id; | 166 | unsigned long old_req_id = (unsigned long) scpnt->host_scribble; |
391 | int retval = SUCCESS; | 167 | int retval = SUCCESS; |
392 | 168 | ||
393 | scsi_host = scpnt->device->host; | 169 | scsi_host = scpnt->device->host; |
394 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; | 170 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; |
395 | unit = (struct zfcp_unit *) scpnt->device->hostdata; | 171 | unit = scpnt->device->hostdata; |
396 | |||
397 | ZFCP_LOG_INFO("aborting scsi_cmnd=%p on adapter %s\n", | ||
398 | scpnt, zfcp_get_busid_by_adapter(adapter)); | ||
399 | 172 | ||
400 | /* avoid race condition between late normal completion and abort */ | 173 | /* avoid race condition between late normal completion and abort */ |
401 | write_lock_irqsave(&adapter->abort_lock, flags); | 174 | write_lock_irqsave(&adapter->abort_lock, flags); |
402 | 175 | ||
403 | /* Check whether corresponding fsf_req is still pending */ | 176 | /* Check whether corresponding fsf_req is still pending */ |
404 | spin_lock(&adapter->req_list_lock); | 177 | spin_lock(&adapter->req_list_lock); |
405 | fsf_req = zfcp_reqlist_find(adapter, | 178 | fsf_req = zfcp_reqlist_find(adapter, old_req_id); |
406 | (unsigned long) scpnt->host_scribble); | ||
407 | spin_unlock(&adapter->req_list_lock); | 179 | spin_unlock(&adapter->req_list_lock); |
408 | if (!fsf_req) { | 180 | if (!fsf_req) { |
409 | write_unlock_irqrestore(&adapter->abort_lock, flags); | 181 | write_unlock_irqrestore(&adapter->abort_lock, flags); |
410 | zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0); | 182 | zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0); |
411 | retval = SUCCESS; | 183 | return retval; |
412 | goto out; | ||
413 | } | 184 | } |
414 | fsf_req->data = 0; | 185 | fsf_req->data = NULL; |
415 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING; | 186 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING; |
416 | old_req_id = fsf_req->req_id; | ||
417 | 187 | ||
418 | /* don't access old fsf_req after releasing the abort_lock */ | 188 | /* don't access old fsf_req after releasing the abort_lock */ |
419 | write_unlock_irqrestore(&adapter->abort_lock, flags); | 189 | write_unlock_irqrestore(&adapter->abort_lock, flags); |
420 | 190 | ||
421 | fsf_req = zfcp_fsf_abort_fcp_command(old_req_id, adapter, unit, 0); | 191 | fsf_req = zfcp_fsf_abort_fcp_command(old_req_id, adapter, unit, 0); |
422 | if (!fsf_req) { | 192 | if (!fsf_req) { |
423 | ZFCP_LOG_INFO("error: initiation of Abort FCP Cmnd failed\n"); | ||
424 | zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, | 193 | zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, |
425 | old_req_id); | 194 | old_req_id); |
426 | retval = FAILED; | 195 | retval = FAILED; |
427 | goto out; | 196 | return retval; |
428 | } | 197 | } |
429 | 198 | ||
430 | __wait_event(fsf_req->completion_wq, | 199 | __wait_event(fsf_req->completion_wq, |
@@ -432,66 +201,29 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) | |||
432 | 201 | ||
433 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { | 202 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { |
434 | zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, fsf_req, 0); | 203 | zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, fsf_req, 0); |
435 | retval = SUCCESS; | ||
436 | } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { | 204 | } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { |
437 | zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, fsf_req, 0); | 205 | zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, fsf_req, 0); |
438 | retval = SUCCESS; | ||
439 | } else { | 206 | } else { |
440 | zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, fsf_req, 0); | 207 | zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, fsf_req, 0); |
441 | retval = FAILED; | 208 | retval = FAILED; |
442 | } | 209 | } |
443 | zfcp_fsf_req_free(fsf_req); | 210 | zfcp_fsf_req_free(fsf_req); |
444 | out: | ||
445 | return retval; | ||
446 | } | ||
447 | |||
448 | static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) | ||
449 | { | ||
450 | int retval; | ||
451 | struct zfcp_unit *unit = scpnt->device->hostdata; | ||
452 | 211 | ||
453 | if (!unit) { | 212 | return retval; |
454 | WARN_ON(1); | ||
455 | return SUCCESS; | ||
456 | } | ||
457 | retval = zfcp_task_management_function(unit, | ||
458 | FCP_LOGICAL_UNIT_RESET, | ||
459 | scpnt); | ||
460 | return retval ? FAILED : SUCCESS; | ||
461 | } | ||
462 | |||
463 | static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) | ||
464 | { | ||
465 | int retval; | ||
466 | struct zfcp_unit *unit = scpnt->device->hostdata; | ||
467 | |||
468 | if (!unit) { | ||
469 | WARN_ON(1); | ||
470 | return SUCCESS; | ||
471 | } | ||
472 | retval = zfcp_task_management_function(unit, FCP_TARGET_RESET, scpnt); | ||
473 | return retval ? FAILED : SUCCESS; | ||
474 | } | 213 | } |
475 | 214 | ||
476 | static int | 215 | static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags, |
477 | zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags, | 216 | struct scsi_cmnd *scpnt) |
478 | struct scsi_cmnd *scpnt) | ||
479 | { | 217 | { |
480 | struct zfcp_adapter *adapter = unit->port->adapter; | 218 | struct zfcp_adapter *adapter = unit->port->adapter; |
481 | struct zfcp_fsf_req *fsf_req; | 219 | struct zfcp_fsf_req *fsf_req; |
482 | int retval = 0; | 220 | int retval = SUCCESS; |
483 | 221 | ||
484 | /* issue task management function */ | 222 | /* issue task management function */ |
485 | fsf_req = zfcp_fsf_send_fcp_command_task_management | 223 | fsf_req = zfcp_fsf_send_fcp_ctm(adapter, unit, tm_flags, 0); |
486 | (adapter, unit, tm_flags, 0); | ||
487 | if (!fsf_req) { | 224 | if (!fsf_req) { |
488 | ZFCP_LOG_INFO("error: creation of task management request " | ||
489 | "failed for unit 0x%016Lx on port 0x%016Lx on " | ||
490 | "adapter %s\n", unit->fcp_lun, unit->port->wwpn, | ||
491 | zfcp_get_busid_by_adapter(adapter)); | ||
492 | zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt); | 225 | zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt); |
493 | retval = -ENOMEM; | 226 | return FAILED; |
494 | goto out; | ||
495 | } | 227 | } |
496 | 228 | ||
497 | __wait_event(fsf_req->completion_wq, | 229 | __wait_event(fsf_req->completion_wq, |
@@ -502,87 +234,90 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags, | |||
502 | */ | 234 | */ |
503 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { | 235 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { |
504 | zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); | 236 | zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); |
505 | retval = -EIO; | 237 | retval = FAILED; |
506 | } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) { | 238 | } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) { |
507 | zfcp_scsi_dbf_event_devreset("nsup", tm_flags, unit, scpnt); | 239 | zfcp_scsi_dbf_event_devreset("nsup", tm_flags, unit, scpnt); |
508 | retval = -ENOTSUPP; | 240 | retval = FAILED; |
509 | } else | 241 | } else |
510 | zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt); | 242 | zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt); |
511 | 243 | ||
512 | zfcp_fsf_req_free(fsf_req); | 244 | zfcp_fsf_req_free(fsf_req); |
513 | out: | 245 | |
514 | return retval; | 246 | return retval; |
515 | } | 247 | } |
516 | 248 | ||
517 | /** | 249 | static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) |
518 | * zfcp_scsi_eh_host_reset_handler - handler for host reset | 250 | { |
519 | */ | 251 | struct zfcp_unit *unit = scpnt->device->hostdata; |
252 | |||
253 | if (!unit) { | ||
254 | WARN_ON(1); | ||
255 | return SUCCESS; | ||
256 | } | ||
257 | return zfcp_task_mgmt_function(unit, FCP_LOGICAL_UNIT_RESET, scpnt); | ||
258 | } | ||
259 | |||
260 | static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) | ||
261 | { | ||
262 | struct zfcp_unit *unit = scpnt->device->hostdata; | ||
263 | |||
264 | if (!unit) { | ||
265 | WARN_ON(1); | ||
266 | return SUCCESS; | ||
267 | } | ||
268 | return zfcp_task_mgmt_function(unit, FCP_TARGET_RESET, scpnt); | ||
269 | } | ||
270 | |||
520 | static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) | 271 | static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) |
521 | { | 272 | { |
522 | struct zfcp_unit *unit; | 273 | struct zfcp_unit *unit; |
523 | struct zfcp_adapter *adapter; | 274 | struct zfcp_adapter *adapter; |
524 | 275 | ||
525 | unit = (struct zfcp_unit*) scpnt->device->hostdata; | 276 | unit = scpnt->device->hostdata; |
526 | adapter = unit->port->adapter; | 277 | adapter = unit->port->adapter; |
527 | |||
528 | ZFCP_LOG_NORMAL("host reset because of problems with " | ||
529 | "unit 0x%016Lx on port 0x%016Lx, adapter %s\n", | ||
530 | unit->fcp_lun, unit->port->wwpn, | ||
531 | zfcp_get_busid_by_adapter(unit->port->adapter)); | ||
532 | |||
533 | zfcp_erp_adapter_reopen(adapter, 0, 141, scpnt); | 278 | zfcp_erp_adapter_reopen(adapter, 0, 141, scpnt); |
534 | zfcp_erp_wait(adapter); | 279 | zfcp_erp_wait(adapter); |
535 | 280 | ||
536 | return SUCCESS; | 281 | return SUCCESS; |
537 | } | 282 | } |
538 | 283 | ||
539 | int | 284 | int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) |
540 | zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) | ||
541 | { | 285 | { |
542 | int retval = 0; | 286 | struct ccw_dev_id dev_id; |
543 | static unsigned int unique_id = 0; | ||
544 | 287 | ||
545 | if (adapter->scsi_host) | 288 | if (adapter->scsi_host) |
546 | goto out; | 289 | return 0; |
547 | 290 | ||
291 | ccw_device_get_id(adapter->ccw_device, &dev_id); | ||
548 | /* register adapter as SCSI host with mid layer of SCSI stack */ | 292 | /* register adapter as SCSI host with mid layer of SCSI stack */ |
549 | adapter->scsi_host = scsi_host_alloc(&zfcp_data.scsi_host_template, | 293 | adapter->scsi_host = scsi_host_alloc(&zfcp_data.scsi_host_template, |
550 | sizeof (struct zfcp_adapter *)); | 294 | sizeof (struct zfcp_adapter *)); |
551 | if (!adapter->scsi_host) { | 295 | if (!adapter->scsi_host) { |
552 | ZFCP_LOG_NORMAL("error: registration with SCSI stack failed " | 296 | dev_err(&adapter->ccw_device->dev, |
553 | "for adapter %s ", | 297 | "registration with SCSI stack failed."); |
554 | zfcp_get_busid_by_adapter(adapter)); | 298 | return -EIO; |
555 | retval = -EIO; | ||
556 | goto out; | ||
557 | } | 299 | } |
558 | ZFCP_LOG_DEBUG("host registered, scsi_host=%p\n", adapter->scsi_host); | ||
559 | 300 | ||
560 | /* tell the SCSI stack some characteristics of this adapter */ | 301 | /* tell the SCSI stack some characteristics of this adapter */ |
561 | adapter->scsi_host->max_id = 1; | 302 | adapter->scsi_host->max_id = 1; |
562 | adapter->scsi_host->max_lun = 1; | 303 | adapter->scsi_host->max_lun = 1; |
563 | adapter->scsi_host->max_channel = 0; | 304 | adapter->scsi_host->max_channel = 0; |
564 | adapter->scsi_host->unique_id = unique_id++; /* FIXME */ | 305 | adapter->scsi_host->unique_id = dev_id.devno; |
565 | adapter->scsi_host->max_cmd_len = ZFCP_MAX_SCSI_CMND_LENGTH; | 306 | adapter->scsi_host->max_cmd_len = 255; |
566 | adapter->scsi_host->transportt = zfcp_data.scsi_transport_template; | 307 | adapter->scsi_host->transportt = zfcp_data.scsi_transport_template; |
567 | 308 | ||
568 | /* | ||
569 | * save a pointer to our own adapter data structure within | ||
570 | * hostdata field of SCSI host data structure | ||
571 | */ | ||
572 | adapter->scsi_host->hostdata[0] = (unsigned long) adapter; | 309 | adapter->scsi_host->hostdata[0] = (unsigned long) adapter; |
573 | 310 | ||
574 | if (scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev)) { | 311 | if (scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev)) { |
575 | scsi_host_put(adapter->scsi_host); | 312 | scsi_host_put(adapter->scsi_host); |
576 | retval = -EIO; | 313 | return -EIO; |
577 | goto out; | ||
578 | } | 314 | } |
579 | atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status); | 315 | atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status); |
580 | out: | 316 | |
581 | return retval; | 317 | return 0; |
582 | } | 318 | } |
583 | 319 | ||
584 | void | 320 | void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) |
585 | zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) | ||
586 | { | 321 | { |
587 | struct Scsi_Host *shost; | 322 | struct Scsi_Host *shost; |
588 | struct zfcp_port *port; | 323 | struct zfcp_port *port; |
@@ -590,10 +325,12 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) | |||
590 | shost = adapter->scsi_host; | 325 | shost = adapter->scsi_host; |
591 | if (!shost) | 326 | if (!shost) |
592 | return; | 327 | return; |
328 | |||
593 | read_lock_irq(&zfcp_data.config_lock); | 329 | read_lock_irq(&zfcp_data.config_lock); |
594 | list_for_each_entry(port, &adapter->port_list_head, list) | 330 | list_for_each_entry(port, &adapter->port_list_head, list) |
595 | if (port->rport) | 331 | if (port->rport) |
596 | port->rport = NULL; | 332 | port->rport = NULL; |
333 | |||
597 | read_unlock_irq(&zfcp_data.config_lock); | 334 | read_unlock_irq(&zfcp_data.config_lock); |
598 | fc_remove_host(shost); | 335 | fc_remove_host(shost); |
599 | scsi_remove_host(shost); | 336 | scsi_remove_host(shost); |
@@ -604,9 +341,6 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) | |||
604 | return; | 341 | return; |
605 | } | 342 | } |
606 | 343 | ||
607 | /* | ||
608 | * Support functions for FC transport class | ||
609 | */ | ||
610 | static struct fc_host_statistics* | 344 | static struct fc_host_statistics* |
611 | zfcp_init_fc_host_stats(struct zfcp_adapter *adapter) | 345 | zfcp_init_fc_host_stats(struct zfcp_adapter *adapter) |
612 | { | 346 | { |
@@ -622,13 +356,12 @@ zfcp_init_fc_host_stats(struct zfcp_adapter *adapter) | |||
622 | return adapter->fc_stats; | 356 | return adapter->fc_stats; |
623 | } | 357 | } |
624 | 358 | ||
625 | static void | 359 | static void zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, |
626 | zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, | 360 | struct fsf_qtcb_bottom_port *data, |
627 | struct fsf_qtcb_bottom_port *data, | 361 | struct fsf_qtcb_bottom_port *old) |
628 | struct fsf_qtcb_bottom_port *old) | ||
629 | { | 362 | { |
630 | fc_stats->seconds_since_last_reset = data->seconds_since_last_reset - | 363 | fc_stats->seconds_since_last_reset = |
631 | old->seconds_since_last_reset; | 364 | data->seconds_since_last_reset - old->seconds_since_last_reset; |
632 | fc_stats->tx_frames = data->tx_frames - old->tx_frames; | 365 | fc_stats->tx_frames = data->tx_frames - old->tx_frames; |
633 | fc_stats->tx_words = data->tx_words - old->tx_words; | 366 | fc_stats->tx_words = data->tx_words - old->tx_words; |
634 | fc_stats->rx_frames = data->rx_frames - old->rx_frames; | 367 | fc_stats->rx_frames = data->rx_frames - old->rx_frames; |
@@ -639,26 +372,25 @@ zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, | |||
639 | fc_stats->dumped_frames = data->dumped_frames - old->dumped_frames; | 372 | fc_stats->dumped_frames = data->dumped_frames - old->dumped_frames; |
640 | fc_stats->link_failure_count = data->link_failure - old->link_failure; | 373 | fc_stats->link_failure_count = data->link_failure - old->link_failure; |
641 | fc_stats->loss_of_sync_count = data->loss_of_sync - old->loss_of_sync; | 374 | fc_stats->loss_of_sync_count = data->loss_of_sync - old->loss_of_sync; |
642 | fc_stats->loss_of_signal_count = data->loss_of_signal - | 375 | fc_stats->loss_of_signal_count = |
643 | old->loss_of_signal; | 376 | data->loss_of_signal - old->loss_of_signal; |
644 | fc_stats->prim_seq_protocol_err_count = data->psp_error_counts - | 377 | fc_stats->prim_seq_protocol_err_count = |
645 | old->psp_error_counts; | 378 | data->psp_error_counts - old->psp_error_counts; |
646 | fc_stats->invalid_tx_word_count = data->invalid_tx_words - | 379 | fc_stats->invalid_tx_word_count = |
647 | old->invalid_tx_words; | 380 | data->invalid_tx_words - old->invalid_tx_words; |
648 | fc_stats->invalid_crc_count = data->invalid_crcs - old->invalid_crcs; | 381 | fc_stats->invalid_crc_count = data->invalid_crcs - old->invalid_crcs; |
649 | fc_stats->fcp_input_requests = data->input_requests - | 382 | fc_stats->fcp_input_requests = |
650 | old->input_requests; | 383 | data->input_requests - old->input_requests; |
651 | fc_stats->fcp_output_requests = data->output_requests - | 384 | fc_stats->fcp_output_requests = |
652 | old->output_requests; | 385 | data->output_requests - old->output_requests; |
653 | fc_stats->fcp_control_requests = data->control_requests - | 386 | fc_stats->fcp_control_requests = |
654 | old->control_requests; | 387 | data->control_requests - old->control_requests; |
655 | fc_stats->fcp_input_megabytes = data->input_mb - old->input_mb; | 388 | fc_stats->fcp_input_megabytes = data->input_mb - old->input_mb; |
656 | fc_stats->fcp_output_megabytes = data->output_mb - old->output_mb; | 389 | fc_stats->fcp_output_megabytes = data->output_mb - old->output_mb; |
657 | } | 390 | } |
658 | 391 | ||
659 | static void | 392 | static void zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats, |
660 | zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats, | 393 | struct fsf_qtcb_bottom_port *data) |
661 | struct fsf_qtcb_bottom_port *data) | ||
662 | { | 394 | { |
663 | fc_stats->seconds_since_last_reset = data->seconds_since_last_reset; | 395 | fc_stats->seconds_since_last_reset = data->seconds_since_last_reset; |
664 | fc_stats->tx_frames = data->tx_frames; | 396 | fc_stats->tx_frames = data->tx_frames; |
@@ -682,22 +414,14 @@ zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats, | |||
682 | fc_stats->fcp_output_megabytes = data->output_mb; | 414 | fc_stats->fcp_output_megabytes = data->output_mb; |
683 | } | 415 | } |
684 | 416 | ||
685 | /** | 417 | static struct fc_host_statistics *zfcp_get_fc_host_stats(struct Scsi_Host *host) |
686 | * zfcp_get_fc_host_stats - provide fc_host_statistics for scsi_transport_fc | ||
687 | * | ||
688 | * assumption: scsi_transport_fc synchronizes calls of | ||
689 | * get_fc_host_stats and reset_fc_host_stats | ||
690 | * (XXX to be checked otherwise introduce locking) | ||
691 | */ | ||
692 | static struct fc_host_statistics * | ||
693 | zfcp_get_fc_host_stats(struct Scsi_Host *shost) | ||
694 | { | 418 | { |
695 | struct zfcp_adapter *adapter; | 419 | struct zfcp_adapter *adapter; |
696 | struct fc_host_statistics *fc_stats; | 420 | struct fc_host_statistics *fc_stats; |
697 | struct fsf_qtcb_bottom_port *data; | 421 | struct fsf_qtcb_bottom_port *data; |
698 | int ret; | 422 | int ret; |
699 | 423 | ||
700 | adapter = (struct zfcp_adapter *)shost->hostdata[0]; | 424 | adapter = (struct zfcp_adapter *)host->hostdata[0]; |
701 | fc_stats = zfcp_init_fc_host_stats(adapter); | 425 | fc_stats = zfcp_init_fc_host_stats(adapter); |
702 | if (!fc_stats) | 426 | if (!fc_stats) |
703 | return NULL; | 427 | return NULL; |
@@ -709,26 +433,25 @@ zfcp_get_fc_host_stats(struct Scsi_Host *shost) | |||
709 | ret = zfcp_fsf_exchange_port_data_sync(adapter, data); | 433 | ret = zfcp_fsf_exchange_port_data_sync(adapter, data); |
710 | if (ret) { | 434 | if (ret) { |
711 | kfree(data); | 435 | kfree(data); |
712 | return NULL; /* XXX return zeroed fc_stats? */ | 436 | return NULL; |
713 | } | 437 | } |
714 | 438 | ||
715 | if (adapter->stats_reset && | 439 | if (adapter->stats_reset && |
716 | ((jiffies/HZ - adapter->stats_reset) < | 440 | ((jiffies/HZ - adapter->stats_reset) < |
717 | data->seconds_since_last_reset)) { | 441 | data->seconds_since_last_reset)) |
718 | zfcp_adjust_fc_host_stats(fc_stats, data, | 442 | zfcp_adjust_fc_host_stats(fc_stats, data, |
719 | adapter->stats_reset_data); | 443 | adapter->stats_reset_data); |
720 | } else | 444 | else |
721 | zfcp_set_fc_host_stats(fc_stats, data); | 445 | zfcp_set_fc_host_stats(fc_stats, data); |
722 | 446 | ||
723 | kfree(data); | 447 | kfree(data); |
724 | return fc_stats; | 448 | return fc_stats; |
725 | } | 449 | } |
726 | 450 | ||
727 | static void | 451 | static void zfcp_reset_fc_host_stats(struct Scsi_Host *shost) |
728 | zfcp_reset_fc_host_stats(struct Scsi_Host *shost) | ||
729 | { | 452 | { |
730 | struct zfcp_adapter *adapter; | 453 | struct zfcp_adapter *adapter; |
731 | struct fsf_qtcb_bottom_port *data, *old_data; | 454 | struct fsf_qtcb_bottom_port *data; |
732 | int ret; | 455 | int ret; |
733 | 456 | ||
734 | adapter = (struct zfcp_adapter *)shost->hostdata[0]; | 457 | adapter = (struct zfcp_adapter *)shost->hostdata[0]; |
@@ -737,17 +460,33 @@ zfcp_reset_fc_host_stats(struct Scsi_Host *shost) | |||
737 | return; | 460 | return; |
738 | 461 | ||
739 | ret = zfcp_fsf_exchange_port_data_sync(adapter, data); | 462 | ret = zfcp_fsf_exchange_port_data_sync(adapter, data); |
740 | if (ret) { | 463 | if (ret) |
741 | kfree(data); | 464 | kfree(data); |
742 | } else { | 465 | else { |
743 | adapter->stats_reset = jiffies/HZ; | 466 | adapter->stats_reset = jiffies/HZ; |
744 | old_data = adapter->stats_reset_data; | 467 | kfree(adapter->stats_reset_data); |
745 | adapter->stats_reset_data = data; /* finally freed in | 468 | adapter->stats_reset_data = data; /* finally freed in |
746 | adater_dequeue */ | 469 | adapter_dequeue */ |
747 | kfree(old_data); | ||
748 | } | 470 | } |
749 | } | 471 | } |
750 | 472 | ||
473 | static void zfcp_get_host_port_state(struct Scsi_Host *shost) | ||
474 | { | ||
475 | struct zfcp_adapter *adapter = | ||
476 | (struct zfcp_adapter *)shost->hostdata[0]; | ||
477 | int status = atomic_read(&adapter->status); | ||
478 | |||
479 | if ((status & ZFCP_STATUS_COMMON_RUNNING) && | ||
480 | !(status & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)) | ||
481 | fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; | ||
482 | else if (status & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) | ||
483 | fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; | ||
484 | else if (status & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
485 | fc_host_port_state(shost) = FC_PORTSTATE_ERROR; | ||
486 | else | ||
487 | fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; | ||
488 | } | ||
489 | |||
751 | static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) | 490 | static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) |
752 | { | 491 | { |
753 | rport->dev_loss_tmo = timeout; | 492 | rport->dev_loss_tmo = timeout; |
@@ -770,6 +509,8 @@ struct fc_function_template zfcp_transport_functions = { | |||
770 | .get_fc_host_stats = zfcp_get_fc_host_stats, | 509 | .get_fc_host_stats = zfcp_get_fc_host_stats, |
771 | .reset_fc_host_stats = zfcp_reset_fc_host_stats, | 510 | .reset_fc_host_stats = zfcp_reset_fc_host_stats, |
772 | .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, | 511 | .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, |
512 | .get_host_port_state = zfcp_get_host_port_state, | ||
513 | .show_host_port_state = 1, | ||
773 | /* no functions registered for following dynamic attributes but | 514 | /* no functions registered for following dynamic attributes but |
774 | directly set by LLDD */ | 515 | directly set by LLDD */ |
775 | .show_host_port_type = 1, | 516 | .show_host_port_type = 1, |
@@ -778,149 +519,26 @@ struct fc_function_template zfcp_transport_functions = { | |||
778 | .disable_target_scan = 1, | 519 | .disable_target_scan = 1, |
779 | }; | 520 | }; |
780 | 521 | ||
781 | /** | 522 | struct zfcp_data zfcp_data = { |
782 | * ZFCP_DEFINE_SCSI_ATTR | 523 | .scsi_host_template = { |
783 | * @_name: name of show attribute | 524 | .name = "zfcp", |
784 | * @_format: format string | 525 | .module = THIS_MODULE, |
785 | * @_value: value to print | 526 | .proc_name = "zfcp", |
786 | * | 527 | .slave_alloc = zfcp_scsi_slave_alloc, |
787 | * Generates attribute for a unit. | 528 | .slave_configure = zfcp_scsi_slave_configure, |
788 | */ | 529 | .slave_destroy = zfcp_scsi_slave_destroy, |
789 | #define ZFCP_DEFINE_SCSI_ATTR(_name, _format, _value) \ | 530 | .queuecommand = zfcp_scsi_queuecommand, |
790 | static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, struct device_attribute *attr, \ | 531 | .eh_abort_handler = zfcp_scsi_eh_abort_handler, |
791 | char *buf) \ | 532 | .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler, |
792 | { \ | 533 | .eh_target_reset_handler = zfcp_scsi_eh_target_reset_handler, |
793 | struct scsi_device *sdev; \ | 534 | .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler, |
794 | struct zfcp_unit *unit; \ | 535 | .can_queue = 4096, |
795 | \ | 536 | .this_id = -1, |
796 | sdev = to_scsi_device(dev); \ | 537 | .sg_tablesize = ZFCP_MAX_SBALES_PER_REQ, |
797 | unit = sdev->hostdata; \ | 538 | .cmd_per_lun = 1, |
798 | return sprintf(buf, _format, _value); \ | 539 | .use_clustering = 1, |
799 | } \ | 540 | .sdev_attrs = zfcp_sysfs_sdev_attrs, |
800 | \ | 541 | .max_sectors = (ZFCP_MAX_SBALES_PER_REQ * 8), |
801 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL); | 542 | .shost_attrs = zfcp_sysfs_shost_attrs, |
802 | 543 | }, | |
803 | ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n", zfcp_get_busid_by_unit(unit)); | ||
804 | ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", unit->port->wwpn); | ||
805 | ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", unit->fcp_lun); | ||
806 | |||
807 | static struct device_attribute *zfcp_sysfs_sdev_attrs[] = { | ||
808 | &dev_attr_fcp_lun, | ||
809 | &dev_attr_wwpn, | ||
810 | &dev_attr_hba_id, | ||
811 | NULL | ||
812 | }; | ||
813 | |||
814 | static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, | ||
815 | struct device_attribute *attr, | ||
816 | char *buf) | ||
817 | { | ||
818 | struct Scsi_Host *scsi_host = dev_to_shost(dev); | ||
819 | struct fsf_qtcb_bottom_port *qtcb_port; | ||
820 | int retval; | ||
821 | struct zfcp_adapter *adapter; | ||
822 | |||
823 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; | ||
824 | if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) | ||
825 | return -EOPNOTSUPP; | ||
826 | |||
827 | qtcb_port = kzalloc(sizeof(struct fsf_qtcb_bottom_port), GFP_KERNEL); | ||
828 | if (!qtcb_port) | ||
829 | return -ENOMEM; | ||
830 | |||
831 | retval = zfcp_fsf_exchange_port_data_sync(adapter, qtcb_port); | ||
832 | if (!retval) | ||
833 | retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util, | ||
834 | qtcb_port->cb_util, qtcb_port->a_util); | ||
835 | kfree(qtcb_port); | ||
836 | return retval; | ||
837 | } | ||
838 | |||
839 | static int zfcp_sysfs_adapter_ex_config(struct device *dev, | ||
840 | struct fsf_statistics_info *stat_inf) | ||
841 | { | ||
842 | int retval; | ||
843 | struct fsf_qtcb_bottom_config *qtcb_config; | ||
844 | struct Scsi_Host *scsi_host = dev_to_shost(dev); | ||
845 | struct zfcp_adapter *adapter; | ||
846 | |||
847 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; | ||
848 | if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) | ||
849 | return -EOPNOTSUPP; | ||
850 | |||
851 | qtcb_config = kzalloc(sizeof(struct fsf_qtcb_bottom_config), | ||
852 | GFP_KERNEL); | ||
853 | if (!qtcb_config) | ||
854 | return -ENOMEM; | ||
855 | |||
856 | retval = zfcp_fsf_exchange_config_data_sync(adapter, qtcb_config); | ||
857 | if (!retval) | ||
858 | *stat_inf = qtcb_config->stat_info; | ||
859 | |||
860 | kfree(qtcb_config); | ||
861 | return retval; | ||
862 | } | ||
863 | |||
864 | static ssize_t zfcp_sysfs_adapter_request_show(struct device *dev, | ||
865 | struct device_attribute *attr, | ||
866 | char *buf) | ||
867 | { | ||
868 | struct fsf_statistics_info stat_info; | ||
869 | int retval; | ||
870 | |||
871 | retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); | ||
872 | if (retval) | ||
873 | return retval; | ||
874 | |||
875 | return sprintf(buf, "%llu %llu %llu\n", | ||
876 | (unsigned long long) stat_info.input_req, | ||
877 | (unsigned long long) stat_info.output_req, | ||
878 | (unsigned long long) stat_info.control_req); | ||
879 | } | ||
880 | |||
881 | static ssize_t zfcp_sysfs_adapter_mb_show(struct device *dev, | ||
882 | struct device_attribute *attr, | ||
883 | char *buf) | ||
884 | { | ||
885 | struct fsf_statistics_info stat_info; | ||
886 | int retval; | ||
887 | |||
888 | retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); | ||
889 | if (retval) | ||
890 | return retval; | ||
891 | |||
892 | return sprintf(buf, "%llu %llu\n", | ||
893 | (unsigned long long) stat_info.input_mb, | ||
894 | (unsigned long long) stat_info.output_mb); | ||
895 | } | ||
896 | |||
897 | static ssize_t zfcp_sysfs_adapter_sec_active_show(struct device *dev, | ||
898 | struct device_attribute *attr, | ||
899 | char *buf) | ||
900 | { | ||
901 | struct fsf_statistics_info stat_info; | ||
902 | int retval; | ||
903 | |||
904 | retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); | ||
905 | if (retval) | ||
906 | return retval; | ||
907 | |||
908 | return sprintf(buf, "%llu\n", | ||
909 | (unsigned long long) stat_info.seconds_act); | ||
910 | } | ||
911 | |||
912 | static DEVICE_ATTR(utilization, S_IRUGO, zfcp_sysfs_adapter_util_show, NULL); | ||
913 | static DEVICE_ATTR(requests, S_IRUGO, zfcp_sysfs_adapter_request_show, NULL); | ||
914 | static DEVICE_ATTR(megabytes, S_IRUGO, zfcp_sysfs_adapter_mb_show, NULL); | ||
915 | static DEVICE_ATTR(seconds_active, S_IRUGO, | ||
916 | zfcp_sysfs_adapter_sec_active_show, NULL); | ||
917 | |||
918 | static struct device_attribute *zfcp_a_stats_attrs[] = { | ||
919 | &dev_attr_utilization, | ||
920 | &dev_attr_requests, | ||
921 | &dev_attr_megabytes, | ||
922 | &dev_attr_seconds_active, | ||
923 | NULL | ||
924 | }; | 544 | }; |
925 | |||
926 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c new file mode 100644 index 000000000000..2e85c6c49e7d --- /dev/null +++ b/drivers/s390/scsi/zfcp_sysfs.c | |||
@@ -0,0 +1,496 @@ | |||
1 | /* | ||
2 | * zfcp device driver | ||
3 | * | ||
4 | * sysfs attributes. | ||
5 | * | ||
6 | * Copyright IBM Corporation 2008 | ||
7 | */ | ||
8 | |||
9 | #include "zfcp_ext.h" | ||
10 | |||
11 | #define ZFCP_DEV_ATTR(_feat, _name, _mode, _show, _store) \ | ||
12 | struct device_attribute dev_attr_##_feat##_##_name = __ATTR(_name, _mode,\ | ||
13 | _show, _store) | ||
14 | #define ZFCP_DEFINE_ATTR(_feat_def, _feat, _name, _format, _value) \ | ||
15 | static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \ | ||
16 | struct device_attribute *at,\ | ||
17 | char *buf) \ | ||
18 | { \ | ||
19 | struct _feat_def *_feat = dev_get_drvdata(dev); \ | ||
20 | \ | ||
21 | return sprintf(buf, _format, _value); \ | ||
22 | } \ | ||
23 | static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \ | ||
24 | zfcp_sysfs_##_feat##_##_name##_show, NULL); | ||
25 | |||
26 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, status, "0x%08x\n", | ||
27 | atomic_read(&adapter->status)); | ||
28 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwnn, "0x%016llx\n", | ||
29 | adapter->peer_wwnn); | ||
30 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwpn, "0x%016llx\n", | ||
31 | adapter->peer_wwpn); | ||
32 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_d_id, "0x%06x\n", | ||
33 | adapter->peer_d_id); | ||
34 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, card_version, "0x%04x\n", | ||
35 | adapter->hydra_version); | ||
36 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, lic_version, "0x%08x\n", | ||
37 | adapter->fsf_lic_version); | ||
38 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, hardware_version, "0x%08x\n", | ||
39 | adapter->hardware_version); | ||
40 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, in_recovery, "%d\n", | ||
41 | (atomic_read(&adapter->status) & | ||
42 | ZFCP_STATUS_COMMON_ERP_INUSE) != 0); | ||
43 | |||
44 | ZFCP_DEFINE_ATTR(zfcp_port, port, status, "0x%08x\n", | ||
45 | atomic_read(&port->status)); | ||
46 | ZFCP_DEFINE_ATTR(zfcp_port, port, in_recovery, "%d\n", | ||
47 | (atomic_read(&port->status) & | ||
48 | ZFCP_STATUS_COMMON_ERP_INUSE) != 0); | ||
49 | ZFCP_DEFINE_ATTR(zfcp_port, port, access_denied, "%d\n", | ||
50 | (atomic_read(&port->status) & | ||
51 | ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0); | ||
52 | |||
53 | ZFCP_DEFINE_ATTR(zfcp_unit, unit, status, "0x%08x\n", | ||
54 | atomic_read(&unit->status)); | ||
55 | ZFCP_DEFINE_ATTR(zfcp_unit, unit, in_recovery, "%d\n", | ||
56 | (atomic_read(&unit->status) & | ||
57 | ZFCP_STATUS_COMMON_ERP_INUSE) != 0); | ||
58 | ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_denied, "%d\n", | ||
59 | (atomic_read(&unit->status) & | ||
60 | ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0); | ||
61 | ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_shared, "%d\n", | ||
62 | (atomic_read(&unit->status) & | ||
63 | ZFCP_STATUS_UNIT_SHARED) != 0); | ||
64 | ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_readonly, "%d\n", | ||
65 | (atomic_read(&unit->status) & | ||
66 | ZFCP_STATUS_UNIT_READONLY) != 0); | ||
67 | |||
68 | #define ZFCP_SYSFS_FAILED(_feat_def, _feat, _adapter, _mod_id, _reopen_id) \ | ||
69 | static ssize_t zfcp_sysfs_##_feat##_failed_show(struct device *dev, \ | ||
70 | struct device_attribute *attr, \ | ||
71 | char *buf) \ | ||
72 | { \ | ||
73 | struct _feat_def *_feat = dev_get_drvdata(dev); \ | ||
74 | \ | ||
75 | if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_ERP_FAILED) \ | ||
76 | return sprintf(buf, "1\n"); \ | ||
77 | else \ | ||
78 | return sprintf(buf, "0\n"); \ | ||
79 | } \ | ||
80 | static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ | ||
81 | struct device_attribute *attr,\ | ||
82 | const char *buf, size_t count)\ | ||
83 | { \ | ||
84 | struct _feat_def *_feat = dev_get_drvdata(dev); \ | ||
85 | unsigned long val; \ | ||
86 | int retval = 0; \ | ||
87 | \ | ||
88 | down(&zfcp_data.config_sema); \ | ||
89 | if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_REMOVE) { \ | ||
90 | retval = -EBUSY; \ | ||
91 | goto out; \ | ||
92 | } \ | ||
93 | \ | ||
94 | if (strict_strtoul(buf, 0, &val) || val != 0) { \ | ||
95 | retval = -EINVAL; \ | ||
96 | goto out; \ | ||
97 | } \ | ||
98 | \ | ||
99 | zfcp_erp_modify_##_feat##_status(_feat, _mod_id, NULL, \ | ||
100 | ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);\ | ||
101 | zfcp_erp_##_feat##_reopen(_feat, ZFCP_STATUS_COMMON_ERP_FAILED, \ | ||
102 | _reopen_id, NULL); \ | ||
103 | zfcp_erp_wait(_adapter); \ | ||
104 | out: \ | ||
105 | up(&zfcp_data.config_sema); \ | ||
106 | return retval ? retval : (ssize_t) count; \ | ||
107 | } \ | ||
108 | static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \ | ||
109 | zfcp_sysfs_##_feat##_failed_show, \ | ||
110 | zfcp_sysfs_##_feat##_failed_store); | ||
111 | |||
112 | ZFCP_SYSFS_FAILED(zfcp_adapter, adapter, adapter, 44, 93); | ||
113 | ZFCP_SYSFS_FAILED(zfcp_port, port, port->adapter, 45, 96); | ||
114 | ZFCP_SYSFS_FAILED(zfcp_unit, unit, unit->port->adapter, 46, 97); | ||
115 | |||
116 | static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, | ||
117 | struct device_attribute *attr, | ||
118 | const char *buf, size_t count) | ||
119 | { | ||
120 | struct zfcp_adapter *adapter = dev_get_drvdata(dev); | ||
121 | int ret; | ||
122 | |||
123 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) | ||
124 | return -EBUSY; | ||
125 | |||
126 | ret = zfcp_scan_ports(adapter); | ||
127 | return ret ? ret : (ssize_t) count; | ||
128 | } | ||
129 | static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, | ||
130 | zfcp_sysfs_port_rescan_store); | ||
131 | |||
132 | static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, | ||
133 | struct device_attribute *attr, | ||
134 | const char *buf, size_t count) | ||
135 | { | ||
136 | struct zfcp_adapter *adapter = dev_get_drvdata(dev); | ||
137 | struct zfcp_port *port; | ||
138 | wwn_t wwpn; | ||
139 | int retval = 0; | ||
140 | |||
141 | down(&zfcp_data.config_sema); | ||
142 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { | ||
143 | retval = -EBUSY; | ||
144 | goto out; | ||
145 | } | ||
146 | |||
147 | if (strict_strtoull(buf, 0, &wwpn)) { | ||
148 | retval = -EINVAL; | ||
149 | goto out; | ||
150 | } | ||
151 | |||
152 | write_lock_irq(&zfcp_data.config_lock); | ||
153 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | ||
154 | if (port && (atomic_read(&port->refcount) == 0)) { | ||
155 | zfcp_port_get(port); | ||
156 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | ||
157 | list_move(&port->list, &adapter->port_remove_lh); | ||
158 | } else | ||
159 | port = NULL; | ||
160 | write_unlock_irq(&zfcp_data.config_lock); | ||
161 | |||
162 | if (!port) { | ||
163 | retval = -ENXIO; | ||
164 | goto out; | ||
165 | } | ||
166 | |||
167 | zfcp_erp_port_shutdown(port, 0, 92, NULL); | ||
168 | zfcp_erp_wait(adapter); | ||
169 | zfcp_port_put(port); | ||
170 | zfcp_port_dequeue(port); | ||
171 | out: | ||
172 | up(&zfcp_data.config_sema); | ||
173 | return retval ? retval : (ssize_t) count; | ||
174 | } | ||
175 | static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL, | ||
176 | zfcp_sysfs_port_remove_store); | ||
177 | |||
178 | static struct attribute *zfcp_adapter_attrs[] = { | ||
179 | &dev_attr_adapter_failed.attr, | ||
180 | &dev_attr_adapter_in_recovery.attr, | ||
181 | &dev_attr_adapter_port_remove.attr, | ||
182 | &dev_attr_adapter_port_rescan.attr, | ||
183 | &dev_attr_adapter_peer_wwnn.attr, | ||
184 | &dev_attr_adapter_peer_wwpn.attr, | ||
185 | &dev_attr_adapter_peer_d_id.attr, | ||
186 | &dev_attr_adapter_card_version.attr, | ||
187 | &dev_attr_adapter_lic_version.attr, | ||
188 | &dev_attr_adapter_status.attr, | ||
189 | &dev_attr_adapter_hardware_version.attr, | ||
190 | NULL | ||
191 | }; | ||
192 | |||
193 | struct attribute_group zfcp_sysfs_adapter_attrs = { | ||
194 | .attrs = zfcp_adapter_attrs, | ||
195 | }; | ||
196 | |||
197 | static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, | ||
198 | struct device_attribute *attr, | ||
199 | const char *buf, size_t count) | ||
200 | { | ||
201 | struct zfcp_port *port = dev_get_drvdata(dev); | ||
202 | struct zfcp_unit *unit; | ||
203 | fcp_lun_t fcp_lun; | ||
204 | int retval = -EINVAL; | ||
205 | |||
206 | down(&zfcp_data.config_sema); | ||
207 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { | ||
208 | retval = -EBUSY; | ||
209 | goto out; | ||
210 | } | ||
211 | |||
212 | if (strict_strtoull(buf, 0, &fcp_lun)) | ||
213 | goto out; | ||
214 | |||
215 | unit = zfcp_unit_enqueue(port, fcp_lun); | ||
216 | if (IS_ERR(unit)) | ||
217 | goto out; | ||
218 | |||
219 | retval = 0; | ||
220 | |||
221 | zfcp_erp_unit_reopen(unit, 0, 94, NULL); | ||
222 | zfcp_erp_wait(unit->port->adapter); | ||
223 | zfcp_unit_put(unit); | ||
224 | out: | ||
225 | up(&zfcp_data.config_sema); | ||
226 | return retval ? retval : (ssize_t) count; | ||
227 | } | ||
228 | static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); | ||
229 | |||
230 | static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, | ||
231 | struct device_attribute *attr, | ||
232 | const char *buf, size_t count) | ||
233 | { | ||
234 | struct zfcp_port *port = dev_get_drvdata(dev); | ||
235 | struct zfcp_unit *unit; | ||
236 | fcp_lun_t fcp_lun; | ||
237 | int retval = 0; | ||
238 | |||
239 | down(&zfcp_data.config_sema); | ||
240 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { | ||
241 | retval = -EBUSY; | ||
242 | goto out; | ||
243 | } | ||
244 | |||
245 | if (strict_strtoull(buf, 0, &fcp_lun)) { | ||
246 | retval = -EINVAL; | ||
247 | goto out; | ||
248 | } | ||
249 | |||
250 | write_lock_irq(&zfcp_data.config_lock); | ||
251 | unit = zfcp_get_unit_by_lun(port, fcp_lun); | ||
252 | if (unit && (atomic_read(&unit->refcount) == 0)) { | ||
253 | zfcp_unit_get(unit); | ||
254 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | ||
255 | list_move(&unit->list, &port->unit_remove_lh); | ||
256 | } else | ||
257 | unit = NULL; | ||
258 | |||
259 | write_unlock_irq(&zfcp_data.config_lock); | ||
260 | |||
261 | if (!unit) { | ||
262 | retval = -ENXIO; | ||
263 | goto out; | ||
264 | } | ||
265 | |||
266 | zfcp_erp_unit_shutdown(unit, 0, 95, NULL); | ||
267 | zfcp_erp_wait(unit->port->adapter); | ||
268 | zfcp_unit_put(unit); | ||
269 | zfcp_unit_dequeue(unit); | ||
270 | out: | ||
271 | up(&zfcp_data.config_sema); | ||
272 | return retval ? retval : (ssize_t) count; | ||
273 | } | ||
274 | static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); | ||
275 | |||
276 | static struct attribute *zfcp_port_ns_attrs[] = { | ||
277 | &dev_attr_port_failed.attr, | ||
278 | &dev_attr_port_in_recovery.attr, | ||
279 | &dev_attr_port_status.attr, | ||
280 | &dev_attr_port_access_denied.attr, | ||
281 | NULL | ||
282 | }; | ||
283 | |||
284 | /** | ||
285 | * zfcp_sysfs_ns_port_attrs - sysfs attributes for nameserver | ||
286 | */ | ||
287 | struct attribute_group zfcp_sysfs_ns_port_attrs = { | ||
288 | .attrs = zfcp_port_ns_attrs, | ||
289 | }; | ||
290 | |||
291 | static struct attribute *zfcp_port_no_ns_attrs[] = { | ||
292 | &dev_attr_unit_add.attr, | ||
293 | &dev_attr_unit_remove.attr, | ||
294 | &dev_attr_port_failed.attr, | ||
295 | &dev_attr_port_in_recovery.attr, | ||
296 | &dev_attr_port_status.attr, | ||
297 | &dev_attr_port_access_denied.attr, | ||
298 | NULL | ||
299 | }; | ||
300 | |||
301 | /** | ||
302 | * zfcp_sysfs_port_attrs - sysfs attributes for all other ports | ||
303 | */ | ||
304 | struct attribute_group zfcp_sysfs_port_attrs = { | ||
305 | .attrs = zfcp_port_no_ns_attrs, | ||
306 | }; | ||
307 | |||
308 | static struct attribute *zfcp_unit_attrs[] = { | ||
309 | &dev_attr_unit_failed.attr, | ||
310 | &dev_attr_unit_in_recovery.attr, | ||
311 | &dev_attr_unit_status.attr, | ||
312 | &dev_attr_unit_access_denied.attr, | ||
313 | &dev_attr_unit_access_shared.attr, | ||
314 | &dev_attr_unit_access_readonly.attr, | ||
315 | NULL | ||
316 | }; | ||
317 | |||
318 | struct attribute_group zfcp_sysfs_unit_attrs = { | ||
319 | .attrs = zfcp_unit_attrs, | ||
320 | }; | ||
321 | |||
322 | #define ZFCP_DEFINE_LATENCY_ATTR(_name) \ | ||
323 | static ssize_t \ | ||
324 | zfcp_sysfs_unit_##_name##_latency_show(struct device *dev, \ | ||
325 | struct device_attribute *attr, \ | ||
326 | char *buf) { \ | ||
327 | struct scsi_device *sdev = to_scsi_device(dev); \ | ||
328 | struct zfcp_unit *unit = sdev->hostdata; \ | ||
329 | struct zfcp_latencies *lat = &unit->latencies; \ | ||
330 | struct zfcp_adapter *adapter = unit->port->adapter; \ | ||
331 | unsigned long flags; \ | ||
332 | unsigned long long fsum, fmin, fmax, csum, cmin, cmax, cc; \ | ||
333 | \ | ||
334 | spin_lock_irqsave(&lat->lock, flags); \ | ||
335 | fsum = lat->_name.fabric.sum * adapter->timer_ticks; \ | ||
336 | fmin = lat->_name.fabric.min * adapter->timer_ticks; \ | ||
337 | fmax = lat->_name.fabric.max * adapter->timer_ticks; \ | ||
338 | csum = lat->_name.channel.sum * adapter->timer_ticks; \ | ||
339 | cmin = lat->_name.channel.min * adapter->timer_ticks; \ | ||
340 | cmax = lat->_name.channel.max * adapter->timer_ticks; \ | ||
341 | cc = lat->_name.counter; \ | ||
342 | spin_unlock_irqrestore(&lat->lock, flags); \ | ||
343 | \ | ||
344 | do_div(fsum, 1000); \ | ||
345 | do_div(fmin, 1000); \ | ||
346 | do_div(fmax, 1000); \ | ||
347 | do_div(csum, 1000); \ | ||
348 | do_div(cmin, 1000); \ | ||
349 | do_div(cmax, 1000); \ | ||
350 | \ | ||
351 | return sprintf(buf, "%llu %llu %llu %llu %llu %llu %llu\n", \ | ||
352 | fmin, fmax, fsum, cmin, cmax, csum, cc); \ | ||
353 | } \ | ||
354 | static ssize_t \ | ||
355 | zfcp_sysfs_unit_##_name##_latency_store(struct device *dev, \ | ||
356 | struct device_attribute *attr, \ | ||
357 | const char *buf, size_t count) \ | ||
358 | { \ | ||
359 | struct scsi_device *sdev = to_scsi_device(dev); \ | ||
360 | struct zfcp_unit *unit = sdev->hostdata; \ | ||
361 | struct zfcp_latencies *lat = &unit->latencies; \ | ||
362 | unsigned long flags; \ | ||
363 | \ | ||
364 | spin_lock_irqsave(&lat->lock, flags); \ | ||
365 | lat->_name.fabric.sum = 0; \ | ||
366 | lat->_name.fabric.min = 0xFFFFFFFF; \ | ||
367 | lat->_name.fabric.max = 0; \ | ||
368 | lat->_name.channel.sum = 0; \ | ||
369 | lat->_name.channel.min = 0xFFFFFFFF; \ | ||
370 | lat->_name.channel.max = 0; \ | ||
371 | lat->_name.counter = 0; \ | ||
372 | spin_unlock_irqrestore(&lat->lock, flags); \ | ||
373 | \ | ||
374 | return (ssize_t) count; \ | ||
375 | } \ | ||
376 | static DEVICE_ATTR(_name##_latency, S_IWUSR | S_IRUGO, \ | ||
377 | zfcp_sysfs_unit_##_name##_latency_show, \ | ||
378 | zfcp_sysfs_unit_##_name##_latency_store); | ||
379 | |||
380 | ZFCP_DEFINE_LATENCY_ATTR(read); | ||
381 | ZFCP_DEFINE_LATENCY_ATTR(write); | ||
382 | ZFCP_DEFINE_LATENCY_ATTR(cmd); | ||
383 | |||
384 | #define ZFCP_DEFINE_SCSI_ATTR(_name, _format, _value) \ | ||
385 | static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, \ | ||
386 | struct device_attribute *attr,\ | ||
387 | char *buf) \ | ||
388 | { \ | ||
389 | struct scsi_device *sdev = to_scsi_device(dev); \ | ||
390 | struct zfcp_unit *unit = sdev->hostdata; \ | ||
391 | \ | ||
392 | return sprintf(buf, _format, _value); \ | ||
393 | } \ | ||
394 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL); | ||
395 | |||
396 | ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n", | ||
397 | unit->port->adapter->ccw_device->dev.bus_id); | ||
398 | ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", unit->port->wwpn); | ||
399 | ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", unit->fcp_lun); | ||
400 | |||
401 | struct device_attribute *zfcp_sysfs_sdev_attrs[] = { | ||
402 | &dev_attr_fcp_lun, | ||
403 | &dev_attr_wwpn, | ||
404 | &dev_attr_hba_id, | ||
405 | &dev_attr_read_latency, | ||
406 | &dev_attr_write_latency, | ||
407 | &dev_attr_cmd_latency, | ||
408 | NULL | ||
409 | }; | ||
410 | |||
411 | static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, | ||
412 | struct device_attribute *attr, | ||
413 | char *buf) | ||
414 | { | ||
415 | struct Scsi_Host *scsi_host = dev_to_shost(dev); | ||
416 | struct fsf_qtcb_bottom_port *qtcb_port; | ||
417 | struct zfcp_adapter *adapter; | ||
418 | int retval; | ||
419 | |||
420 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; | ||
421 | if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) | ||
422 | return -EOPNOTSUPP; | ||
423 | |||
424 | qtcb_port = kzalloc(sizeof(struct fsf_qtcb_bottom_port), GFP_KERNEL); | ||
425 | if (!qtcb_port) | ||
426 | return -ENOMEM; | ||
427 | |||
428 | retval = zfcp_fsf_exchange_port_data_sync(adapter, qtcb_port); | ||
429 | if (!retval) | ||
430 | retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util, | ||
431 | qtcb_port->cb_util, qtcb_port->a_util); | ||
432 | kfree(qtcb_port); | ||
433 | return retval; | ||
434 | } | ||
435 | static DEVICE_ATTR(utilization, S_IRUGO, zfcp_sysfs_adapter_util_show, NULL); | ||
436 | |||
437 | static int zfcp_sysfs_adapter_ex_config(struct device *dev, | ||
438 | struct fsf_statistics_info *stat_inf) | ||
439 | { | ||
440 | struct Scsi_Host *scsi_host = dev_to_shost(dev); | ||
441 | struct fsf_qtcb_bottom_config *qtcb_config; | ||
442 | struct zfcp_adapter *adapter; | ||
443 | int retval; | ||
444 | |||
445 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; | ||
446 | if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) | ||
447 | return -EOPNOTSUPP; | ||
448 | |||
449 | qtcb_config = kzalloc(sizeof(struct fsf_qtcb_bottom_config), | ||
450 | GFP_KERNEL); | ||
451 | if (!qtcb_config) | ||
452 | return -ENOMEM; | ||
453 | |||
454 | retval = zfcp_fsf_exchange_config_data_sync(adapter, qtcb_config); | ||
455 | if (!retval) | ||
456 | *stat_inf = qtcb_config->stat_info; | ||
457 | |||
458 | kfree(qtcb_config); | ||
459 | return retval; | ||
460 | } | ||
461 | |||
462 | #define ZFCP_SHOST_ATTR(_name, _format, _arg...) \ | ||
463 | static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, \ | ||
464 | struct device_attribute *attr,\ | ||
465 | char *buf) \ | ||
466 | { \ | ||
467 | struct fsf_statistics_info stat_info; \ | ||
468 | int retval; \ | ||
469 | \ | ||
470 | retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); \ | ||
471 | if (retval) \ | ||
472 | return retval; \ | ||
473 | \ | ||
474 | return sprintf(buf, _format, ## _arg); \ | ||
475 | } \ | ||
476 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_adapter_##_name##_show, NULL); | ||
477 | |||
478 | ZFCP_SHOST_ATTR(requests, "%llu %llu %llu\n", | ||
479 | (unsigned long long) stat_info.input_req, | ||
480 | (unsigned long long) stat_info.output_req, | ||
481 | (unsigned long long) stat_info.control_req); | ||
482 | |||
483 | ZFCP_SHOST_ATTR(megabytes, "%llu %llu\n", | ||
484 | (unsigned long long) stat_info.input_mb, | ||
485 | (unsigned long long) stat_info.output_mb); | ||
486 | |||
487 | ZFCP_SHOST_ATTR(seconds_active, "%llu\n", | ||
488 | (unsigned long long) stat_info.seconds_act); | ||
489 | |||
490 | struct device_attribute *zfcp_sysfs_shost_attrs[] = { | ||
491 | &dev_attr_utilization, | ||
492 | &dev_attr_requests, | ||
493 | &dev_attr_megabytes, | ||
494 | &dev_attr_seconds_active, | ||
495 | NULL | ||
496 | }; | ||
diff --git a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c deleted file mode 100644 index ccbba4dd3a77..000000000000 --- a/drivers/s390/scsi/zfcp_sysfs_adapter.c +++ /dev/null | |||
@@ -1,270 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of the zfcp device driver for | ||
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | ||
5 | * (C) Copyright IBM Corp. 2002, 2006 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include "zfcp_ext.h" | ||
23 | |||
24 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG | ||
25 | |||
26 | /** | ||
27 | * ZFCP_DEFINE_ADAPTER_ATTR | ||
28 | * @_name: name of show attribute | ||
29 | * @_format: format string | ||
30 | * @_value: value to print | ||
31 | * | ||
32 | * Generates attributes for an adapter. | ||
33 | */ | ||
34 | #define ZFCP_DEFINE_ADAPTER_ATTR(_name, _format, _value) \ | ||
35 | static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, struct device_attribute *attr, \ | ||
36 | char *buf) \ | ||
37 | { \ | ||
38 | struct zfcp_adapter *adapter; \ | ||
39 | \ | ||
40 | adapter = dev_get_drvdata(dev); \ | ||
41 | return sprintf(buf, _format, _value); \ | ||
42 | } \ | ||
43 | \ | ||
44 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_adapter_##_name##_show, NULL); | ||
45 | |||
46 | ZFCP_DEFINE_ADAPTER_ATTR(status, "0x%08x\n", atomic_read(&adapter->status)); | ||
47 | ZFCP_DEFINE_ADAPTER_ATTR(peer_wwnn, "0x%016llx\n", adapter->peer_wwnn); | ||
48 | ZFCP_DEFINE_ADAPTER_ATTR(peer_wwpn, "0x%016llx\n", adapter->peer_wwpn); | ||
49 | ZFCP_DEFINE_ADAPTER_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id); | ||
50 | ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version); | ||
51 | ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version); | ||
52 | ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n", | ||
53 | adapter->hardware_version); | ||
54 | ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask | ||
55 | (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)); | ||
56 | |||
57 | /** | ||
58 | * zfcp_sysfs_port_add_store - add a port to sysfs tree | ||
59 | * @dev: pointer to belonging device | ||
60 | * @buf: pointer to input buffer | ||
61 | * @count: number of bytes in buffer | ||
62 | * | ||
63 | * Store function of the "port_add" attribute of an adapter. | ||
64 | */ | ||
65 | static ssize_t | ||
66 | zfcp_sysfs_port_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
67 | { | ||
68 | wwn_t wwpn; | ||
69 | char *endp; | ||
70 | struct zfcp_adapter *adapter; | ||
71 | struct zfcp_port *port; | ||
72 | int retval = -EINVAL; | ||
73 | |||
74 | down(&zfcp_data.config_sema); | ||
75 | |||
76 | adapter = dev_get_drvdata(dev); | ||
77 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { | ||
78 | retval = -EBUSY; | ||
79 | goto out; | ||
80 | } | ||
81 | |||
82 | wwpn = simple_strtoull(buf, &endp, 0); | ||
83 | if ((endp + 1) < (buf + count)) | ||
84 | goto out; | ||
85 | |||
86 | port = zfcp_port_enqueue(adapter, wwpn, 0, 0); | ||
87 | if (!port) | ||
88 | goto out; | ||
89 | |||
90 | retval = 0; | ||
91 | |||
92 | zfcp_erp_port_reopen(port, 0, 91, NULL); | ||
93 | zfcp_erp_wait(port->adapter); | ||
94 | zfcp_port_put(port); | ||
95 | out: | ||
96 | up(&zfcp_data.config_sema); | ||
97 | return retval ? retval : (ssize_t) count; | ||
98 | } | ||
99 | |||
100 | static DEVICE_ATTR(port_add, S_IWUSR, NULL, zfcp_sysfs_port_add_store); | ||
101 | |||
102 | /** | ||
103 | * zfcp_sysfs_port_remove_store - remove a port from sysfs tree | ||
104 | * @dev: pointer to belonging device | ||
105 | * @buf: pointer to input buffer | ||
106 | * @count: number of bytes in buffer | ||
107 | * | ||
108 | * Store function of the "port_remove" attribute of an adapter. | ||
109 | */ | ||
110 | static ssize_t | ||
111 | zfcp_sysfs_port_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
112 | { | ||
113 | struct zfcp_adapter *adapter; | ||
114 | struct zfcp_port *port; | ||
115 | wwn_t wwpn; | ||
116 | char *endp; | ||
117 | int retval = 0; | ||
118 | |||
119 | down(&zfcp_data.config_sema); | ||
120 | |||
121 | adapter = dev_get_drvdata(dev); | ||
122 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { | ||
123 | retval = -EBUSY; | ||
124 | goto out; | ||
125 | } | ||
126 | |||
127 | wwpn = simple_strtoull(buf, &endp, 0); | ||
128 | if ((endp + 1) < (buf + count)) { | ||
129 | retval = -EINVAL; | ||
130 | goto out; | ||
131 | } | ||
132 | |||
133 | write_lock_irq(&zfcp_data.config_lock); | ||
134 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | ||
135 | if (port && (atomic_read(&port->refcount) == 0)) { | ||
136 | zfcp_port_get(port); | ||
137 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | ||
138 | list_move(&port->list, &adapter->port_remove_lh); | ||
139 | } | ||
140 | else { | ||
141 | port = NULL; | ||
142 | } | ||
143 | write_unlock_irq(&zfcp_data.config_lock); | ||
144 | |||
145 | if (!port) { | ||
146 | retval = -ENXIO; | ||
147 | goto out; | ||
148 | } | ||
149 | |||
150 | zfcp_erp_port_shutdown(port, 0, 92, NULL); | ||
151 | zfcp_erp_wait(adapter); | ||
152 | zfcp_port_put(port); | ||
153 | zfcp_port_dequeue(port); | ||
154 | out: | ||
155 | up(&zfcp_data.config_sema); | ||
156 | return retval ? retval : (ssize_t) count; | ||
157 | } | ||
158 | |||
159 | static DEVICE_ATTR(port_remove, S_IWUSR, NULL, zfcp_sysfs_port_remove_store); | ||
160 | |||
161 | /** | ||
162 | * zfcp_sysfs_adapter_failed_store - failed state of adapter | ||
163 | * @dev: pointer to belonging device | ||
164 | * @buf: pointer to input buffer | ||
165 | * @count: number of bytes in buffer | ||
166 | * | ||
167 | * Store function of the "failed" attribute of an adapter. | ||
168 | * If a "0" gets written to "failed", error recovery will be | ||
169 | * started for the belonging adapter. | ||
170 | */ | ||
171 | static ssize_t | ||
172 | zfcp_sysfs_adapter_failed_store(struct device *dev, struct device_attribute *attr, | ||
173 | const char *buf, size_t count) | ||
174 | { | ||
175 | struct zfcp_adapter *adapter; | ||
176 | unsigned int val; | ||
177 | char *endp; | ||
178 | int retval = 0; | ||
179 | |||
180 | down(&zfcp_data.config_sema); | ||
181 | |||
182 | adapter = dev_get_drvdata(dev); | ||
183 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { | ||
184 | retval = -EBUSY; | ||
185 | goto out; | ||
186 | } | ||
187 | |||
188 | val = simple_strtoul(buf, &endp, 0); | ||
189 | if (((endp + 1) < (buf + count)) || (val != 0)) { | ||
190 | retval = -EINVAL; | ||
191 | goto out; | ||
192 | } | ||
193 | |||
194 | zfcp_erp_modify_adapter_status(adapter, 44, NULL, | ||
195 | ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); | ||
196 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 93, | ||
197 | NULL); | ||
198 | zfcp_erp_wait(adapter); | ||
199 | out: | ||
200 | up(&zfcp_data.config_sema); | ||
201 | return retval ? retval : (ssize_t) count; | ||
202 | } | ||
203 | |||
204 | /** | ||
205 | * zfcp_sysfs_adapter_failed_show - failed state of adapter | ||
206 | * @dev: pointer to belonging device | ||
207 | * @buf: pointer to input buffer | ||
208 | * | ||
209 | * Show function of "failed" attribute of adapter. Will be | ||
210 | * "0" if adapter is working, otherwise "1". | ||
211 | */ | ||
212 | static ssize_t | ||
213 | zfcp_sysfs_adapter_failed_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
214 | { | ||
215 | struct zfcp_adapter *adapter; | ||
216 | |||
217 | adapter = dev_get_drvdata(dev); | ||
218 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) | ||
219 | return sprintf(buf, "1\n"); | ||
220 | else | ||
221 | return sprintf(buf, "0\n"); | ||
222 | } | ||
223 | |||
224 | static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_adapter_failed_show, | ||
225 | zfcp_sysfs_adapter_failed_store); | ||
226 | |||
227 | static struct attribute *zfcp_adapter_attrs[] = { | ||
228 | &dev_attr_failed.attr, | ||
229 | &dev_attr_in_recovery.attr, | ||
230 | &dev_attr_port_remove.attr, | ||
231 | &dev_attr_port_add.attr, | ||
232 | &dev_attr_peer_wwnn.attr, | ||
233 | &dev_attr_peer_wwpn.attr, | ||
234 | &dev_attr_peer_d_id.attr, | ||
235 | &dev_attr_card_version.attr, | ||
236 | &dev_attr_lic_version.attr, | ||
237 | &dev_attr_status.attr, | ||
238 | &dev_attr_hardware_version.attr, | ||
239 | NULL | ||
240 | }; | ||
241 | |||
242 | static struct attribute_group zfcp_adapter_attr_group = { | ||
243 | .attrs = zfcp_adapter_attrs, | ||
244 | }; | ||
245 | |||
246 | /** | ||
247 | * zfcp_sysfs_create_adapter_files - create sysfs adapter files | ||
248 | * @dev: pointer to belonging device | ||
249 | * | ||
250 | * Create all attributes of the sysfs representation of an adapter. | ||
251 | */ | ||
252 | int | ||
253 | zfcp_sysfs_adapter_create_files(struct device *dev) | ||
254 | { | ||
255 | return sysfs_create_group(&dev->kobj, &zfcp_adapter_attr_group); | ||
256 | } | ||
257 | |||
258 | /** | ||
259 | * zfcp_sysfs_remove_adapter_files - remove sysfs adapter files | ||
260 | * @dev: pointer to belonging device | ||
261 | * | ||
262 | * Remove all attributes of the sysfs representation of an adapter. | ||
263 | */ | ||
264 | void | ||
265 | zfcp_sysfs_adapter_remove_files(struct device *dev) | ||
266 | { | ||
267 | sysfs_remove_group(&dev->kobj, &zfcp_adapter_attr_group); | ||
268 | } | ||
269 | |||
270 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_sysfs_driver.c b/drivers/s390/scsi/zfcp_sysfs_driver.c deleted file mode 100644 index 651edd58906a..000000000000 --- a/drivers/s390/scsi/zfcp_sysfs_driver.c +++ /dev/null | |||
@@ -1,106 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of the zfcp device driver for | ||
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | ||
5 | * (C) Copyright IBM Corp. 2002, 2006 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include "zfcp_ext.h" | ||
23 | |||
24 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG | ||
25 | |||
26 | /** | ||
27 | * ZFCP_DEFINE_DRIVER_ATTR - define for all loglevels sysfs attributes | ||
28 | * @_name: name of attribute | ||
29 | * @_define: name of ZFCP loglevel define | ||
30 | * | ||
31 | * Generates store function for a sysfs loglevel attribute of zfcp driver. | ||
32 | */ | ||
33 | #define ZFCP_DEFINE_DRIVER_ATTR(_name, _define) \ | ||
34 | static ssize_t zfcp_sysfs_loglevel_##_name##_store(struct device_driver *drv, \ | ||
35 | const char *buf, \ | ||
36 | size_t count) \ | ||
37 | { \ | ||
38 | unsigned int loglevel; \ | ||
39 | unsigned int new_loglevel; \ | ||
40 | char *endp; \ | ||
41 | \ | ||
42 | new_loglevel = simple_strtoul(buf, &endp, 0); \ | ||
43 | if ((endp + 1) < (buf + count)) \ | ||
44 | return -EINVAL; \ | ||
45 | if (new_loglevel > 3) \ | ||
46 | return -EINVAL; \ | ||
47 | down(&zfcp_data.config_sema); \ | ||
48 | loglevel = atomic_read(&zfcp_data.loglevel); \ | ||
49 | loglevel &= ~((unsigned int) 0xf << (ZFCP_LOG_AREA_##_define << 2)); \ | ||
50 | loglevel |= new_loglevel << (ZFCP_LOG_AREA_##_define << 2); \ | ||
51 | atomic_set(&zfcp_data.loglevel, loglevel); \ | ||
52 | up(&zfcp_data.config_sema); \ | ||
53 | return count; \ | ||
54 | } \ | ||
55 | \ | ||
56 | static ssize_t zfcp_sysfs_loglevel_##_name##_show(struct device_driver *dev, \ | ||
57 | char *buf) \ | ||
58 | { \ | ||
59 | return sprintf(buf,"%d\n", (unsigned int) \ | ||
60 | ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA_##_define)); \ | ||
61 | } \ | ||
62 | \ | ||
63 | static DRIVER_ATTR(loglevel_##_name, S_IWUSR | S_IRUGO, \ | ||
64 | zfcp_sysfs_loglevel_##_name##_show, \ | ||
65 | zfcp_sysfs_loglevel_##_name##_store); | ||
66 | |||
67 | ZFCP_DEFINE_DRIVER_ATTR(other, OTHER); | ||
68 | ZFCP_DEFINE_DRIVER_ATTR(scsi, SCSI); | ||
69 | ZFCP_DEFINE_DRIVER_ATTR(fsf, FSF); | ||
70 | ZFCP_DEFINE_DRIVER_ATTR(config, CONFIG); | ||
71 | ZFCP_DEFINE_DRIVER_ATTR(cio, CIO); | ||
72 | ZFCP_DEFINE_DRIVER_ATTR(qdio, QDIO); | ||
73 | ZFCP_DEFINE_DRIVER_ATTR(erp, ERP); | ||
74 | ZFCP_DEFINE_DRIVER_ATTR(fc, FC); | ||
75 | |||
76 | static ssize_t zfcp_sysfs_version_show(struct device_driver *dev, | ||
77 | char *buf) | ||
78 | { | ||
79 | return sprintf(buf, "%s\n", zfcp_data.driver_version); | ||
80 | } | ||
81 | |||
82 | static DRIVER_ATTR(version, S_IRUGO, zfcp_sysfs_version_show, NULL); | ||
83 | |||
84 | static struct attribute *zfcp_driver_attrs[] = { | ||
85 | &driver_attr_loglevel_other.attr, | ||
86 | &driver_attr_loglevel_scsi.attr, | ||
87 | &driver_attr_loglevel_fsf.attr, | ||
88 | &driver_attr_loglevel_config.attr, | ||
89 | &driver_attr_loglevel_cio.attr, | ||
90 | &driver_attr_loglevel_qdio.attr, | ||
91 | &driver_attr_loglevel_erp.attr, | ||
92 | &driver_attr_loglevel_fc.attr, | ||
93 | &driver_attr_version.attr, | ||
94 | NULL | ||
95 | }; | ||
96 | |||
97 | static struct attribute_group zfcp_driver_attr_group = { | ||
98 | .attrs = zfcp_driver_attrs, | ||
99 | }; | ||
100 | |||
101 | struct attribute_group *zfcp_driver_attr_groups[] = { | ||
102 | &zfcp_driver_attr_group, | ||
103 | NULL, | ||
104 | }; | ||
105 | |||
106 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_sysfs_port.c b/drivers/s390/scsi/zfcp_sysfs_port.c deleted file mode 100644 index 703c1b5cb602..000000000000 --- a/drivers/s390/scsi/zfcp_sysfs_port.c +++ /dev/null | |||
@@ -1,295 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of the zfcp device driver for | ||
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | ||
5 | * (C) Copyright IBM Corp. 2002, 2006 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include "zfcp_ext.h" | ||
23 | |||
24 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG | ||
25 | |||
26 | /** | ||
27 | * zfcp_sysfs_port_release - gets called when a struct device port is released | ||
28 | * @dev: pointer to belonging device | ||
29 | */ | ||
30 | void | ||
31 | zfcp_sysfs_port_release(struct device *dev) | ||
32 | { | ||
33 | kfree(dev); | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * ZFCP_DEFINE_PORT_ATTR | ||
38 | * @_name: name of show attribute | ||
39 | * @_format: format string | ||
40 | * @_value: value to print | ||
41 | * | ||
42 | * Generates attributes for a port. | ||
43 | */ | ||
44 | #define ZFCP_DEFINE_PORT_ATTR(_name, _format, _value) \ | ||
45 | static ssize_t zfcp_sysfs_port_##_name##_show(struct device *dev, struct device_attribute *attr, \ | ||
46 | char *buf) \ | ||
47 | { \ | ||
48 | struct zfcp_port *port; \ | ||
49 | \ | ||
50 | port = dev_get_drvdata(dev); \ | ||
51 | return sprintf(buf, _format, _value); \ | ||
52 | } \ | ||
53 | \ | ||
54 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_port_##_name##_show, NULL); | ||
55 | |||
56 | ZFCP_DEFINE_PORT_ATTR(status, "0x%08x\n", atomic_read(&port->status)); | ||
57 | ZFCP_DEFINE_PORT_ATTR(in_recovery, "%d\n", atomic_test_mask | ||
58 | (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)); | ||
59 | ZFCP_DEFINE_PORT_ATTR(access_denied, "%d\n", atomic_test_mask | ||
60 | (ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status)); | ||
61 | |||
62 | /** | ||
63 | * zfcp_sysfs_unit_add_store - add a unit to sysfs tree | ||
64 | * @dev: pointer to belonging device | ||
65 | * @buf: pointer to input buffer | ||
66 | * @count: number of bytes in buffer | ||
67 | * | ||
68 | * Store function of the "unit_add" attribute of a port. | ||
69 | */ | ||
70 | static ssize_t | ||
71 | zfcp_sysfs_unit_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
72 | { | ||
73 | fcp_lun_t fcp_lun; | ||
74 | char *endp; | ||
75 | struct zfcp_port *port; | ||
76 | struct zfcp_unit *unit; | ||
77 | int retval = -EINVAL; | ||
78 | |||
79 | down(&zfcp_data.config_sema); | ||
80 | |||
81 | port = dev_get_drvdata(dev); | ||
82 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { | ||
83 | retval = -EBUSY; | ||
84 | goto out; | ||
85 | } | ||
86 | |||
87 | fcp_lun = simple_strtoull(buf, &endp, 0); | ||
88 | if ((endp + 1) < (buf + count)) | ||
89 | goto out; | ||
90 | |||
91 | unit = zfcp_unit_enqueue(port, fcp_lun); | ||
92 | if (!unit) | ||
93 | goto out; | ||
94 | |||
95 | retval = 0; | ||
96 | |||
97 | zfcp_erp_unit_reopen(unit, 0, 94, NULL); | ||
98 | zfcp_erp_wait(unit->port->adapter); | ||
99 | zfcp_unit_put(unit); | ||
100 | out: | ||
101 | up(&zfcp_data.config_sema); | ||
102 | return retval ? retval : (ssize_t) count; | ||
103 | } | ||
104 | |||
105 | static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); | ||
106 | |||
107 | /** | ||
108 | * zfcp_sysfs_unit_remove_store - remove a unit from sysfs tree | ||
109 | * @dev: pointer to belonging device | ||
110 | * @buf: pointer to input buffer | ||
111 | * @count: number of bytes in buffer | ||
112 | */ | ||
113 | static ssize_t | ||
114 | zfcp_sysfs_unit_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
115 | { | ||
116 | struct zfcp_port *port; | ||
117 | struct zfcp_unit *unit; | ||
118 | fcp_lun_t fcp_lun; | ||
119 | char *endp; | ||
120 | int retval = 0; | ||
121 | |||
122 | down(&zfcp_data.config_sema); | ||
123 | |||
124 | port = dev_get_drvdata(dev); | ||
125 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { | ||
126 | retval = -EBUSY; | ||
127 | goto out; | ||
128 | } | ||
129 | |||
130 | fcp_lun = simple_strtoull(buf, &endp, 0); | ||
131 | if ((endp + 1) < (buf + count)) { | ||
132 | retval = -EINVAL; | ||
133 | goto out; | ||
134 | } | ||
135 | |||
136 | write_lock_irq(&zfcp_data.config_lock); | ||
137 | unit = zfcp_get_unit_by_lun(port, fcp_lun); | ||
138 | if (unit && (atomic_read(&unit->refcount) == 0)) { | ||
139 | zfcp_unit_get(unit); | ||
140 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | ||
141 | list_move(&unit->list, &port->unit_remove_lh); | ||
142 | } | ||
143 | else { | ||
144 | unit = NULL; | ||
145 | } | ||
146 | write_unlock_irq(&zfcp_data.config_lock); | ||
147 | |||
148 | if (!unit) { | ||
149 | retval = -ENXIO; | ||
150 | goto out; | ||
151 | } | ||
152 | |||
153 | zfcp_erp_unit_shutdown(unit, 0, 95, NULL); | ||
154 | zfcp_erp_wait(unit->port->adapter); | ||
155 | zfcp_unit_put(unit); | ||
156 | zfcp_unit_dequeue(unit); | ||
157 | out: | ||
158 | up(&zfcp_data.config_sema); | ||
159 | return retval ? retval : (ssize_t) count; | ||
160 | } | ||
161 | |||
162 | static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); | ||
163 | |||
164 | /** | ||
165 | * zfcp_sysfs_port_failed_store - failed state of port | ||
166 | * @dev: pointer to belonging device | ||
167 | * @buf: pointer to input buffer | ||
168 | * @count: number of bytes in buffer | ||
169 | * | ||
170 | * Store function of the "failed" attribute of a port. | ||
171 | * If a "0" gets written to "failed", error recovery will be | ||
172 | * started for the belonging port. | ||
173 | */ | ||
174 | static ssize_t | ||
175 | zfcp_sysfs_port_failed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
176 | { | ||
177 | struct zfcp_port *port; | ||
178 | unsigned int val; | ||
179 | char *endp; | ||
180 | int retval = 0; | ||
181 | |||
182 | down(&zfcp_data.config_sema); | ||
183 | |||
184 | port = dev_get_drvdata(dev); | ||
185 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { | ||
186 | retval = -EBUSY; | ||
187 | goto out; | ||
188 | } | ||
189 | |||
190 | val = simple_strtoul(buf, &endp, 0); | ||
191 | if (((endp + 1) < (buf + count)) || (val != 0)) { | ||
192 | retval = -EINVAL; | ||
193 | goto out; | ||
194 | } | ||
195 | |||
196 | zfcp_erp_modify_port_status(port, 45, NULL, | ||
197 | ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); | ||
198 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, 96, NULL); | ||
199 | zfcp_erp_wait(port->adapter); | ||
200 | out: | ||
201 | up(&zfcp_data.config_sema); | ||
202 | return retval ? retval : (ssize_t) count; | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * zfcp_sysfs_port_failed_show - failed state of port | ||
207 | * @dev: pointer to belonging device | ||
208 | * @buf: pointer to input buffer | ||
209 | * | ||
210 | * Show function of "failed" attribute of port. Will be | ||
211 | * "0" if port is working, otherwise "1". | ||
212 | */ | ||
213 | static ssize_t | ||
214 | zfcp_sysfs_port_failed_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
215 | { | ||
216 | struct zfcp_port *port; | ||
217 | |||
218 | port = dev_get_drvdata(dev); | ||
219 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) | ||
220 | return sprintf(buf, "1\n"); | ||
221 | else | ||
222 | return sprintf(buf, "0\n"); | ||
223 | } | ||
224 | |||
225 | static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_port_failed_show, | ||
226 | zfcp_sysfs_port_failed_store); | ||
227 | |||
228 | /** | ||
229 | * zfcp_port_common_attrs | ||
230 | * sysfs attributes that are common for all kind of fc ports. | ||
231 | */ | ||
232 | static struct attribute *zfcp_port_common_attrs[] = { | ||
233 | &dev_attr_failed.attr, | ||
234 | &dev_attr_in_recovery.attr, | ||
235 | &dev_attr_status.attr, | ||
236 | &dev_attr_access_denied.attr, | ||
237 | NULL | ||
238 | }; | ||
239 | |||
240 | static struct attribute_group zfcp_port_common_attr_group = { | ||
241 | .attrs = zfcp_port_common_attrs, | ||
242 | }; | ||
243 | |||
244 | /** | ||
245 | * zfcp_port_no_ns_attrs | ||
246 | * sysfs attributes not to be used for nameserver ports. | ||
247 | */ | ||
248 | static struct attribute *zfcp_port_no_ns_attrs[] = { | ||
249 | &dev_attr_unit_add.attr, | ||
250 | &dev_attr_unit_remove.attr, | ||
251 | NULL | ||
252 | }; | ||
253 | |||
254 | static struct attribute_group zfcp_port_no_ns_attr_group = { | ||
255 | .attrs = zfcp_port_no_ns_attrs, | ||
256 | }; | ||
257 | |||
258 | /** | ||
259 | * zfcp_sysfs_port_create_files - create sysfs port files | ||
260 | * @dev: pointer to belonging device | ||
261 | * | ||
262 | * Create all attributes of the sysfs representation of a port. | ||
263 | */ | ||
264 | int | ||
265 | zfcp_sysfs_port_create_files(struct device *dev, u32 flags) | ||
266 | { | ||
267 | int retval; | ||
268 | |||
269 | retval = sysfs_create_group(&dev->kobj, &zfcp_port_common_attr_group); | ||
270 | |||
271 | if ((flags & ZFCP_STATUS_PORT_WKA) || retval) | ||
272 | return retval; | ||
273 | |||
274 | retval = sysfs_create_group(&dev->kobj, &zfcp_port_no_ns_attr_group); | ||
275 | if (retval) | ||
276 | sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group); | ||
277 | |||
278 | return retval; | ||
279 | } | ||
280 | |||
281 | /** | ||
282 | * zfcp_sysfs_port_remove_files - remove sysfs port files | ||
283 | * @dev: pointer to belonging device | ||
284 | * | ||
285 | * Remove all attributes of the sysfs representation of a port. | ||
286 | */ | ||
287 | void | ||
288 | zfcp_sysfs_port_remove_files(struct device *dev, u32 flags) | ||
289 | { | ||
290 | sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group); | ||
291 | if (!(flags & ZFCP_STATUS_PORT_WKA)) | ||
292 | sysfs_remove_group(&dev->kobj, &zfcp_port_no_ns_attr_group); | ||
293 | } | ||
294 | |||
295 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_sysfs_unit.c b/drivers/s390/scsi/zfcp_sysfs_unit.c deleted file mode 100644 index 80fb2c2cf48a..000000000000 --- a/drivers/s390/scsi/zfcp_sysfs_unit.c +++ /dev/null | |||
@@ -1,167 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of the zfcp device driver for | ||
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | ||
5 | * (C) Copyright IBM Corp. 2002, 2006 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include "zfcp_ext.h" | ||
23 | |||
24 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG | ||
25 | |||
26 | /** | ||
27 | * zfcp_sysfs_unit_release - gets called when a struct device unit is released | ||
28 | * @dev: pointer to belonging device | ||
29 | */ | ||
30 | void | ||
31 | zfcp_sysfs_unit_release(struct device *dev) | ||
32 | { | ||
33 | kfree(dev); | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * ZFCP_DEFINE_UNIT_ATTR | ||
38 | * @_name: name of show attribute | ||
39 | * @_format: format string | ||
40 | * @_value: value to print | ||
41 | * | ||
42 | * Generates attribute for a unit. | ||
43 | */ | ||
44 | #define ZFCP_DEFINE_UNIT_ATTR(_name, _format, _value) \ | ||
45 | static ssize_t zfcp_sysfs_unit_##_name##_show(struct device *dev, struct device_attribute *attr, \ | ||
46 | char *buf) \ | ||
47 | { \ | ||
48 | struct zfcp_unit *unit; \ | ||
49 | \ | ||
50 | unit = dev_get_drvdata(dev); \ | ||
51 | return sprintf(buf, _format, _value); \ | ||
52 | } \ | ||
53 | \ | ||
54 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_unit_##_name##_show, NULL); | ||
55 | |||
56 | ZFCP_DEFINE_UNIT_ATTR(status, "0x%08x\n", atomic_read(&unit->status)); | ||
57 | ZFCP_DEFINE_UNIT_ATTR(in_recovery, "%d\n", atomic_test_mask | ||
58 | (ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)); | ||
59 | ZFCP_DEFINE_UNIT_ATTR(access_denied, "%d\n", atomic_test_mask | ||
60 | (ZFCP_STATUS_COMMON_ACCESS_DENIED, &unit->status)); | ||
61 | ZFCP_DEFINE_UNIT_ATTR(access_shared, "%d\n", atomic_test_mask | ||
62 | (ZFCP_STATUS_UNIT_SHARED, &unit->status)); | ||
63 | ZFCP_DEFINE_UNIT_ATTR(access_readonly, "%d\n", atomic_test_mask | ||
64 | (ZFCP_STATUS_UNIT_READONLY, &unit->status)); | ||
65 | |||
66 | /** | ||
67 | * zfcp_sysfs_unit_failed_store - failed state of unit | ||
68 | * @dev: pointer to belonging device | ||
69 | * @buf: pointer to input buffer | ||
70 | * @count: number of bytes in buffer | ||
71 | * | ||
72 | * Store function of the "failed" attribute of a unit. | ||
73 | * If a "0" gets written to "failed", error recovery will be | ||
74 | * started for the belonging unit. | ||
75 | */ | ||
76 | static ssize_t | ||
77 | zfcp_sysfs_unit_failed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
78 | { | ||
79 | struct zfcp_unit *unit; | ||
80 | unsigned int val; | ||
81 | char *endp; | ||
82 | int retval = 0; | ||
83 | |||
84 | down(&zfcp_data.config_sema); | ||
85 | unit = dev_get_drvdata(dev); | ||
86 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status)) { | ||
87 | retval = -EBUSY; | ||
88 | goto out; | ||
89 | } | ||
90 | |||
91 | val = simple_strtoul(buf, &endp, 0); | ||
92 | if (((endp + 1) < (buf + count)) || (val != 0)) { | ||
93 | retval = -EINVAL; | ||
94 | goto out; | ||
95 | } | ||
96 | |||
97 | zfcp_erp_modify_unit_status(unit, 46, NULL, | ||
98 | ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); | ||
99 | zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, 97, NULL); | ||
100 | zfcp_erp_wait(unit->port->adapter); | ||
101 | out: | ||
102 | up(&zfcp_data.config_sema); | ||
103 | return retval ? retval : (ssize_t) count; | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * zfcp_sysfs_unit_failed_show - failed state of unit | ||
108 | * @dev: pointer to belonging device | ||
109 | * @buf: pointer to input buffer | ||
110 | * | ||
111 | * Show function of "failed" attribute of unit. Will be | ||
112 | * "0" if unit is working, otherwise "1". | ||
113 | */ | ||
114 | static ssize_t | ||
115 | zfcp_sysfs_unit_failed_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
116 | { | ||
117 | struct zfcp_unit *unit; | ||
118 | |||
119 | unit = dev_get_drvdata(dev); | ||
120 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) | ||
121 | return sprintf(buf, "1\n"); | ||
122 | else | ||
123 | return sprintf(buf, "0\n"); | ||
124 | } | ||
125 | |||
126 | static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_unit_failed_show, | ||
127 | zfcp_sysfs_unit_failed_store); | ||
128 | |||
129 | static struct attribute *zfcp_unit_attrs[] = { | ||
130 | &dev_attr_failed.attr, | ||
131 | &dev_attr_in_recovery.attr, | ||
132 | &dev_attr_status.attr, | ||
133 | &dev_attr_access_denied.attr, | ||
134 | &dev_attr_access_shared.attr, | ||
135 | &dev_attr_access_readonly.attr, | ||
136 | NULL | ||
137 | }; | ||
138 | |||
139 | static struct attribute_group zfcp_unit_attr_group = { | ||
140 | .attrs = zfcp_unit_attrs, | ||
141 | }; | ||
142 | |||
143 | /** | ||
144 | * zfcp_sysfs_create_unit_files - create sysfs unit files | ||
145 | * @dev: pointer to belonging device | ||
146 | * | ||
147 | * Create all attributes of the sysfs representation of a unit. | ||
148 | */ | ||
149 | int | ||
150 | zfcp_sysfs_unit_create_files(struct device *dev) | ||
151 | { | ||
152 | return sysfs_create_group(&dev->kobj, &zfcp_unit_attr_group); | ||
153 | } | ||
154 | |||
155 | /** | ||
156 | * zfcp_sysfs_remove_unit_files - remove sysfs unit files | ||
157 | * @dev: pointer to belonging device | ||
158 | * | ||
159 | * Remove all attributes of the sysfs representation of a unit. | ||
160 | */ | ||
161 | void | ||
162 | zfcp_sysfs_unit_remove_files(struct device *dev) | ||
163 | { | ||
164 | sysfs_remove_group(&dev->kobj, &zfcp_unit_attr_group); | ||
165 | } | ||
166 | |||
167 | #undef ZFCP_LOG_AREA | ||