1 | /* |
2 | * linux/drivers/scsi/esas2r/esas2r_main.c |
3 | * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers |
4 | * |
5 | * Copyright (c) 2001-2013 ATTO Technology, Inc. |
6 | * (mailto:linuxdrivers@attotech.com) |
7 | * |
8 | * This program is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU General Public License |
10 | * as published by the Free Software Foundation; either version 2 |
11 | * of the License, or (at your option) any later version. |
12 | * |
13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. |
17 | * |
18 | * NO WARRANTY |
19 | * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR |
20 | * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT |
21 | * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, |
22 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is |
23 | * solely responsible for determining the appropriateness of using and |
24 | * distributing the Program and assumes all risks associated with its |
25 | * exercise of rights under this Agreement, including but not limited to |
26 | * the risks and costs of program errors, damage to or loss of data, |
27 | * programs or equipment, and unavailability or interruption of operations. |
28 | * |
29 | * DISCLAIMER OF LIABILITY |
30 | * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY |
31 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
32 | * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND |
33 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR |
34 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
35 | * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED |
36 | * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES |
37 | * |
38 | * You should have received a copy of the GNU General Public License |
39 | * along with this program; if not, write to the Free Software |
40 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, |
41 | * USA. |
42 | */ |
43 | |
44 | #include "esas2r.h" |
45 | |
46 | MODULE_DESCRIPTION(ESAS2R_DRVR_NAME ": " ESAS2R_LONGNAME " driver" ); |
47 | MODULE_AUTHOR("ATTO Technology, Inc." ); |
48 | MODULE_LICENSE("GPL" ); |
49 | MODULE_VERSION(ESAS2R_VERSION_STR); |
50 | |
51 | /* global definitions */ |
52 | |
53 | static int found_adapters; |
54 | struct esas2r_adapter *esas2r_adapters[MAX_ADAPTERS]; |
55 | |
56 | #define ESAS2R_VDA_EVENT_PORT1 54414 |
57 | #define ESAS2R_VDA_EVENT_PORT2 54415 |
58 | #define ESAS2R_VDA_EVENT_SOCK_COUNT 2 |
59 | |
60 | static struct esas2r_adapter *esas2r_adapter_from_kobj(struct kobject *kobj) |
61 | { |
62 | struct device *dev = container_of(kobj, struct device, kobj); |
63 | struct Scsi_Host *host = class_to_shost(dev); |
64 | |
65 | return (struct esas2r_adapter *)host->hostdata; |
66 | } |
67 | |
68 | static ssize_t read_fw(struct file *file, struct kobject *kobj, |
69 | struct bin_attribute *attr, |
70 | char *buf, loff_t off, size_t count) |
71 | { |
72 | struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj); |
73 | |
74 | return esas2r_read_fw(a, buf, off, count); |
75 | } |
76 | |
77 | static ssize_t write_fw(struct file *file, struct kobject *kobj, |
78 | struct bin_attribute *attr, |
79 | char *buf, loff_t off, size_t count) |
80 | { |
81 | struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj); |
82 | |
83 | return esas2r_write_fw(a, buf, off, count); |
84 | } |
85 | |
86 | static ssize_t read_fs(struct file *file, struct kobject *kobj, |
87 | struct bin_attribute *attr, |
88 | char *buf, loff_t off, size_t count) |
89 | { |
90 | struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj); |
91 | |
92 | return esas2r_read_fs(a, buf, off, count); |
93 | } |
94 | |
95 | static ssize_t write_fs(struct file *file, struct kobject *kobj, |
96 | struct bin_attribute *attr, |
97 | char *buf, loff_t off, size_t count) |
98 | { |
99 | struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj); |
100 | int length = min(sizeof(struct esas2r_ioctl_fs), count); |
101 | int result = 0; |
102 | |
103 | result = esas2r_write_fs(a, buf, off, count); |
104 | |
105 | if (result < 0) |
106 | result = 0; |
107 | |
108 | return length; |
109 | } |
110 | |
111 | static ssize_t read_vda(struct file *file, struct kobject *kobj, |
112 | struct bin_attribute *attr, |
113 | char *buf, loff_t off, size_t count) |
114 | { |
115 | struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj); |
116 | |
117 | return esas2r_read_vda(a, buf, off, count); |
118 | } |
119 | |
120 | static ssize_t write_vda(struct file *file, struct kobject *kobj, |
121 | struct bin_attribute *attr, |
122 | char *buf, loff_t off, size_t count) |
123 | { |
124 | struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj); |
125 | |
126 | return esas2r_write_vda(a, buf, off, count); |
127 | } |
128 | |
129 | static ssize_t read_live_nvram(struct file *file, struct kobject *kobj, |
130 | struct bin_attribute *attr, |
131 | char *buf, loff_t off, size_t count) |
132 | { |
133 | struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj); |
134 | int length = min_t(size_t, sizeof(struct esas2r_sas_nvram), PAGE_SIZE); |
135 | |
136 | memcpy(buf, a->nvram, length); |
137 | return length; |
138 | } |
139 | |
140 | static ssize_t write_live_nvram(struct file *file, struct kobject *kobj, |
141 | struct bin_attribute *attr, |
142 | char *buf, loff_t off, size_t count) |
143 | { |
144 | struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj); |
145 | struct esas2r_request *rq; |
146 | int result = -EFAULT; |
147 | |
148 | rq = esas2r_alloc_request(a); |
149 | if (rq == NULL) |
150 | return -ENOMEM; |
151 | |
152 | if (esas2r_write_params(a, rq, data: (struct esas2r_sas_nvram *)buf)) |
153 | result = count; |
154 | |
155 | esas2r_free_request(a, rq); |
156 | |
157 | return result; |
158 | } |
159 | |
160 | static ssize_t read_default_nvram(struct file *file, struct kobject *kobj, |
161 | struct bin_attribute *attr, |
162 | char *buf, loff_t off, size_t count) |
163 | { |
164 | struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj); |
165 | |
166 | esas2r_nvram_get_defaults(a, nvram: (struct esas2r_sas_nvram *)buf); |
167 | |
168 | return sizeof(struct esas2r_sas_nvram); |
169 | } |
170 | |
171 | static ssize_t read_hw(struct file *file, struct kobject *kobj, |
172 | struct bin_attribute *attr, |
173 | char *buf, loff_t off, size_t count) |
174 | { |
175 | struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj); |
176 | int length = min_t(size_t, sizeof(struct atto_ioctl), PAGE_SIZE); |
177 | |
178 | if (!a->local_atto_ioctl) |
179 | return -ENOMEM; |
180 | |
181 | if (handle_hba_ioctl(a, ioctl_hba: a->local_atto_ioctl) != IOCTL_SUCCESS) |
182 | return -ENOMEM; |
183 | |
184 | memcpy(buf, a->local_atto_ioctl, length); |
185 | |
186 | return length; |
187 | } |
188 | |
189 | static ssize_t write_hw(struct file *file, struct kobject *kobj, |
190 | struct bin_attribute *attr, |
191 | char *buf, loff_t off, size_t count) |
192 | { |
193 | struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj); |
194 | int length = min(sizeof(struct atto_ioctl), count); |
195 | |
196 | if (!a->local_atto_ioctl) { |
197 | a->local_atto_ioctl = kmalloc(size: sizeof(struct atto_ioctl), |
198 | GFP_KERNEL); |
199 | if (a->local_atto_ioctl == NULL) { |
200 | esas2r_log(level: ESAS2R_LOG_WARN, |
201 | format: "write_hw kzalloc failed for %zu bytes" , |
202 | sizeof(struct atto_ioctl)); |
203 | return -ENOMEM; |
204 | } |
205 | } |
206 | |
207 | memset(a->local_atto_ioctl, 0, sizeof(struct atto_ioctl)); |
208 | memcpy(a->local_atto_ioctl, buf, length); |
209 | |
210 | return length; |
211 | } |
212 | |
213 | #define ESAS2R_RW_BIN_ATTR(_name) \ |
214 | struct bin_attribute bin_attr_ ## _name = { \ |
215 | .attr = \ |
216 | { .name = __stringify(_name), .mode = S_IRUSR | S_IWUSR }, \ |
217 | .size = 0, \ |
218 | .read = read_ ## _name, \ |
219 | .write = write_ ## _name } |
220 | |
221 | ESAS2R_RW_BIN_ATTR(fw); |
222 | ESAS2R_RW_BIN_ATTR(fs); |
223 | ESAS2R_RW_BIN_ATTR(vda); |
224 | ESAS2R_RW_BIN_ATTR(hw); |
225 | ESAS2R_RW_BIN_ATTR(live_nvram); |
226 | |
227 | struct bin_attribute bin_attr_default_nvram = { |
228 | .attr = { .name = "default_nvram" , .mode = S_IRUGO }, |
229 | .size = 0, |
230 | .read = read_default_nvram, |
231 | .write = NULL |
232 | }; |
233 | |
234 | static const struct scsi_host_template driver_template = { |
235 | .module = THIS_MODULE, |
236 | .show_info = esas2r_show_info, |
237 | .name = ESAS2R_LONGNAME, |
238 | .info = esas2r_info, |
239 | .ioctl = esas2r_ioctl, |
240 | .queuecommand = esas2r_queuecommand, |
241 | .eh_abort_handler = esas2r_eh_abort, |
242 | .eh_device_reset_handler = esas2r_device_reset, |
243 | .eh_bus_reset_handler = esas2r_bus_reset, |
244 | .eh_host_reset_handler = esas2r_host_reset, |
245 | .eh_target_reset_handler = esas2r_target_reset, |
246 | .can_queue = 128, |
247 | .this_id = -1, |
248 | .sg_tablesize = SG_CHUNK_SIZE, |
249 | .cmd_per_lun = |
250 | ESAS2R_DEFAULT_CMD_PER_LUN, |
251 | .proc_name = ESAS2R_DRVR_NAME, |
252 | .change_queue_depth = scsi_change_queue_depth, |
253 | .max_sectors = 0xFFFF, |
254 | }; |
255 | |
256 | int sgl_page_size = 512; |
257 | module_param(sgl_page_size, int, 0); |
258 | MODULE_PARM_DESC(sgl_page_size, |
259 | "Scatter/gather list (SGL) page size in number of S/G " |
260 | "entries. If your application is doing a lot of very large " |
261 | "transfers, you may want to increase the SGL page size. " |
262 | "Default 512." ); |
263 | |
264 | int num_sg_lists = 1024; |
265 | module_param(num_sg_lists, int, 0); |
266 | MODULE_PARM_DESC(num_sg_lists, |
267 | "Number of scatter/gather lists. Default 1024." ); |
268 | |
269 | int sg_tablesize = SG_CHUNK_SIZE; |
270 | module_param(sg_tablesize, int, 0); |
271 | MODULE_PARM_DESC(sg_tablesize, |
272 | "Maximum number of entries in a scatter/gather table." ); |
273 | |
274 | int num_requests = 256; |
275 | module_param(num_requests, int, 0); |
276 | MODULE_PARM_DESC(num_requests, |
277 | "Number of requests. Default 256." ); |
278 | |
279 | int num_ae_requests = 4; |
280 | module_param(num_ae_requests, int, 0); |
281 | MODULE_PARM_DESC(num_ae_requests, |
282 | "Number of VDA asynchronous event requests. Default 4." ); |
283 | |
284 | int cmd_per_lun = ESAS2R_DEFAULT_CMD_PER_LUN; |
285 | module_param(cmd_per_lun, int, 0); |
286 | MODULE_PARM_DESC(cmd_per_lun, |
287 | "Maximum number of commands per LUN. Default " |
288 | DEFINED_NUM_TO_STR(ESAS2R_DEFAULT_CMD_PER_LUN) "." ); |
289 | |
290 | int can_queue = 128; |
291 | module_param(can_queue, int, 0); |
292 | MODULE_PARM_DESC(can_queue, |
293 | "Maximum number of commands per adapter. Default 128." ); |
294 | |
295 | int esas2r_max_sectors = 0xFFFF; |
296 | module_param(esas2r_max_sectors, int, 0); |
297 | MODULE_PARM_DESC(esas2r_max_sectors, |
298 | "Maximum number of disk sectors in a single data transfer. " |
299 | "Default 65535 (largest possible setting)." ); |
300 | |
301 | int interrupt_mode = 1; |
302 | module_param(interrupt_mode, int, 0); |
303 | MODULE_PARM_DESC(interrupt_mode, |
304 | "Defines the interrupt mode to use. 0 for legacy" |
305 | ", 1 for MSI. Default is MSI (1)." ); |
306 | |
307 | static const struct pci_device_id |
308 | esas2r_pci_table[] = { |
309 | { ATTO_VENDOR_ID, 0x0049, ATTO_VENDOR_ID, 0x0049, |
310 | 0, |
311 | 0, 0 }, |
312 | { ATTO_VENDOR_ID, 0x0049, ATTO_VENDOR_ID, 0x004A, |
313 | 0, |
314 | 0, 0 }, |
315 | { ATTO_VENDOR_ID, 0x0049, ATTO_VENDOR_ID, 0x004B, |
316 | 0, |
317 | 0, 0 }, |
318 | { ATTO_VENDOR_ID, 0x0049, ATTO_VENDOR_ID, 0x004C, |
319 | 0, |
320 | 0, 0 }, |
321 | { ATTO_VENDOR_ID, 0x0049, ATTO_VENDOR_ID, 0x004D, |
322 | 0, |
323 | 0, 0 }, |
324 | { ATTO_VENDOR_ID, 0x0049, ATTO_VENDOR_ID, 0x004E, |
325 | 0, |
326 | 0, 0 }, |
327 | { 0, 0, 0, 0, |
328 | 0, |
329 | 0, 0 } |
330 | }; |
331 | |
332 | MODULE_DEVICE_TABLE(pci, esas2r_pci_table); |
333 | |
334 | static int |
335 | esas2r_probe(struct pci_dev *pcid, const struct pci_device_id *id); |
336 | |
337 | static void |
338 | esas2r_remove(struct pci_dev *pcid); |
339 | |
340 | static struct pci_driver |
341 | esas2r_pci_driver = { |
342 | .name = ESAS2R_DRVR_NAME, |
343 | .id_table = esas2r_pci_table, |
344 | .probe = esas2r_probe, |
345 | .remove = esas2r_remove, |
346 | .driver.pm = &esas2r_pm_ops, |
347 | }; |
348 | |
349 | static int esas2r_probe(struct pci_dev *pcid, |
350 | const struct pci_device_id *id) |
351 | { |
352 | struct Scsi_Host *host = NULL; |
353 | struct esas2r_adapter *a; |
354 | int err; |
355 | |
356 | size_t host_alloc_size = sizeof(struct esas2r_adapter) |
357 | + ((num_requests) + |
358 | 1) * sizeof(struct esas2r_request); |
359 | |
360 | esas2r_log_dev(level: ESAS2R_LOG_DEBG, dev: &(pcid->dev), |
361 | format: "esas2r_probe() 0x%02x 0x%02x 0x%02x 0x%02x" , |
362 | pcid->vendor, |
363 | pcid->device, |
364 | pcid->subsystem_vendor, |
365 | pcid->subsystem_device); |
366 | |
367 | esas2r_log_dev(level: ESAS2R_LOG_INFO, dev: &(pcid->dev), |
368 | format: "before pci_enable_device() " |
369 | "enable_cnt: %d" , |
370 | pcid->enable_cnt.counter); |
371 | |
372 | err = pci_enable_device(dev: pcid); |
373 | if (err != 0) { |
374 | esas2r_log_dev(level: ESAS2R_LOG_CRIT, dev: &(pcid->dev), |
375 | format: "pci_enable_device() FAIL (%d)" , |
376 | err); |
377 | return -ENODEV; |
378 | } |
379 | |
380 | esas2r_log_dev(level: ESAS2R_LOG_INFO, dev: &(pcid->dev), |
381 | format: "pci_enable_device() OK" ); |
382 | esas2r_log_dev(level: ESAS2R_LOG_INFO, dev: &(pcid->dev), |
383 | format: "after pci_enable_device() enable_cnt: %d" , |
384 | pcid->enable_cnt.counter); |
385 | |
386 | host = scsi_host_alloc(&driver_template, host_alloc_size); |
387 | if (host == NULL) { |
388 | esas2r_log(level: ESAS2R_LOG_CRIT, format: "scsi_host_alloc() FAIL" ); |
389 | return -ENODEV; |
390 | } |
391 | |
392 | memset(host->hostdata, 0, host_alloc_size); |
393 | |
394 | a = (struct esas2r_adapter *)host->hostdata; |
395 | |
396 | esas2r_log(level: ESAS2R_LOG_INFO, format: "scsi_host_alloc() OK host: %p" , host); |
397 | |
398 | /* override max LUN and max target id */ |
399 | |
400 | host->max_id = ESAS2R_MAX_ID + 1; |
401 | host->max_lun = 255; |
402 | |
403 | /* we can handle 16-byte CDbs */ |
404 | |
405 | host->max_cmd_len = 16; |
406 | |
407 | host->can_queue = can_queue; |
408 | host->cmd_per_lun = cmd_per_lun; |
409 | host->this_id = host->max_id + 1; |
410 | host->max_channel = 0; |
411 | host->unique_id = found_adapters; |
412 | host->sg_tablesize = sg_tablesize; |
413 | host->max_sectors = esas2r_max_sectors; |
414 | |
415 | /* set to bus master for BIOses that don't do it for us */ |
416 | |
417 | esas2r_log(level: ESAS2R_LOG_INFO, format: "pci_set_master() called" ); |
418 | |
419 | pci_set_master(dev: pcid); |
420 | |
421 | if (!esas2r_init_adapter(host, pcid, index: found_adapters)) { |
422 | esas2r_log(level: ESAS2R_LOG_CRIT, |
423 | format: "unable to initialize device at PCI bus %x:%x" , |
424 | pcid->bus->number, |
425 | pcid->devfn); |
426 | |
427 | esas2r_log_dev(level: ESAS2R_LOG_INFO, dev: &(host->shost_gendev), |
428 | format: "scsi_host_put() called" ); |
429 | |
430 | scsi_host_put(t: host); |
431 | |
432 | return 0; |
433 | |
434 | } |
435 | |
436 | esas2r_log(level: ESAS2R_LOG_INFO, format: "pci_set_drvdata(%p, %p) called" , pcid, |
437 | host->hostdata); |
438 | |
439 | pci_set_drvdata(pdev: pcid, data: host); |
440 | |
441 | esas2r_log(level: ESAS2R_LOG_INFO, format: "scsi_add_host() called" ); |
442 | |
443 | err = scsi_add_host(host, dev: &pcid->dev); |
444 | |
445 | if (err) { |
446 | esas2r_log(level: ESAS2R_LOG_CRIT, format: "scsi_add_host returned %d" , err); |
447 | esas2r_log_dev(level: ESAS2R_LOG_CRIT, dev: &(host->shost_gendev), |
448 | format: "scsi_add_host() FAIL" ); |
449 | |
450 | esas2r_log_dev(level: ESAS2R_LOG_INFO, dev: &(host->shost_gendev), |
451 | format: "scsi_host_put() called" ); |
452 | |
453 | scsi_host_put(t: host); |
454 | |
455 | esas2r_log_dev(level: ESAS2R_LOG_INFO, dev: &(host->shost_gendev), |
456 | format: "pci_set_drvdata(%p, NULL) called" , |
457 | pcid); |
458 | |
459 | pci_set_drvdata(pdev: pcid, NULL); |
460 | |
461 | return -ENODEV; |
462 | } |
463 | |
464 | |
465 | esas2r_fw_event_on(a); |
466 | |
467 | esas2r_log_dev(level: ESAS2R_LOG_INFO, dev: &(host->shost_gendev), |
468 | format: "scsi_scan_host() called" ); |
469 | |
470 | scsi_scan_host(host); |
471 | |
472 | /* Add sysfs binary files */ |
473 | if (sysfs_create_bin_file(kobj: &host->shost_dev.kobj, attr: &bin_attr_fw)) |
474 | esas2r_log_dev(level: ESAS2R_LOG_WARN, dev: &(host->shost_gendev), |
475 | format: "Failed to create sysfs binary file: fw" ); |
476 | else |
477 | a->sysfs_fw_created = 1; |
478 | |
479 | if (sysfs_create_bin_file(kobj: &host->shost_dev.kobj, attr: &bin_attr_fs)) |
480 | esas2r_log_dev(level: ESAS2R_LOG_WARN, dev: &(host->shost_gendev), |
481 | format: "Failed to create sysfs binary file: fs" ); |
482 | else |
483 | a->sysfs_fs_created = 1; |
484 | |
485 | if (sysfs_create_bin_file(kobj: &host->shost_dev.kobj, attr: &bin_attr_vda)) |
486 | esas2r_log_dev(level: ESAS2R_LOG_WARN, dev: &(host->shost_gendev), |
487 | format: "Failed to create sysfs binary file: vda" ); |
488 | else |
489 | a->sysfs_vda_created = 1; |
490 | |
491 | if (sysfs_create_bin_file(kobj: &host->shost_dev.kobj, attr: &bin_attr_hw)) |
492 | esas2r_log_dev(level: ESAS2R_LOG_WARN, dev: &(host->shost_gendev), |
493 | format: "Failed to create sysfs binary file: hw" ); |
494 | else |
495 | a->sysfs_hw_created = 1; |
496 | |
497 | if (sysfs_create_bin_file(kobj: &host->shost_dev.kobj, attr: &bin_attr_live_nvram)) |
498 | esas2r_log_dev(level: ESAS2R_LOG_WARN, dev: &(host->shost_gendev), |
499 | format: "Failed to create sysfs binary file: live_nvram" ); |
500 | else |
501 | a->sysfs_live_nvram_created = 1; |
502 | |
503 | if (sysfs_create_bin_file(kobj: &host->shost_dev.kobj, |
504 | attr: &bin_attr_default_nvram)) |
505 | esas2r_log_dev(level: ESAS2R_LOG_WARN, dev: &(host->shost_gendev), |
506 | format: "Failed to create sysfs binary file: default_nvram" ); |
507 | else |
508 | a->sysfs_default_nvram_created = 1; |
509 | |
510 | found_adapters++; |
511 | |
512 | return 0; |
513 | } |
514 | |
515 | static void esas2r_remove(struct pci_dev *pdev) |
516 | { |
517 | struct Scsi_Host *host = pci_get_drvdata(pdev); |
518 | struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata; |
519 | |
520 | esas2r_log_dev(level: ESAS2R_LOG_INFO, dev: &(pdev->dev), |
521 | format: "esas2r_remove(%p) called; " |
522 | "host:%p" , pdev, |
523 | host); |
524 | |
525 | esas2r_kill_adapter(i: a->index); |
526 | found_adapters--; |
527 | } |
528 | |
529 | static int __init esas2r_init(void) |
530 | { |
531 | int i; |
532 | |
533 | esas2r_log(level: ESAS2R_LOG_INFO, format: "%s called" , __func__); |
534 | |
535 | /* verify valid parameters */ |
536 | |
537 | if (can_queue < 1) { |
538 | esas2r_log(level: ESAS2R_LOG_WARN, |
539 | format: "warning: can_queue must be at least 1, value " |
540 | "forced." ); |
541 | can_queue = 1; |
542 | } else if (can_queue > 2048) { |
543 | esas2r_log(level: ESAS2R_LOG_WARN, |
544 | format: "warning: can_queue must be no larger than 2048, " |
545 | "value forced." ); |
546 | can_queue = 2048; |
547 | } |
548 | |
549 | if (cmd_per_lun < 1) { |
550 | esas2r_log(level: ESAS2R_LOG_WARN, |
551 | format: "warning: cmd_per_lun must be at least 1, value " |
552 | "forced." ); |
553 | cmd_per_lun = 1; |
554 | } else if (cmd_per_lun > 2048) { |
555 | esas2r_log(level: ESAS2R_LOG_WARN, |
556 | format: "warning: cmd_per_lun must be no larger than " |
557 | "2048, value forced." ); |
558 | cmd_per_lun = 2048; |
559 | } |
560 | |
561 | if (sg_tablesize < 32) { |
562 | esas2r_log(level: ESAS2R_LOG_WARN, |
563 | format: "warning: sg_tablesize must be at least 32, " |
564 | "value forced." ); |
565 | sg_tablesize = 32; |
566 | } |
567 | |
568 | if (esas2r_max_sectors < 1) { |
569 | esas2r_log(level: ESAS2R_LOG_WARN, |
570 | format: "warning: esas2r_max_sectors must be at least " |
571 | "1, value forced." ); |
572 | esas2r_max_sectors = 1; |
573 | } else if (esas2r_max_sectors > 0xffff) { |
574 | esas2r_log(level: ESAS2R_LOG_WARN, |
575 | format: "warning: esas2r_max_sectors must be no larger " |
576 | "than 0xffff, value forced." ); |
577 | esas2r_max_sectors = 0xffff; |
578 | } |
579 | |
580 | sgl_page_size &= ~(ESAS2R_SGL_ALIGN - 1); |
581 | |
582 | if (sgl_page_size < SGL_PG_SZ_MIN) |
583 | sgl_page_size = SGL_PG_SZ_MIN; |
584 | else if (sgl_page_size > SGL_PG_SZ_MAX) |
585 | sgl_page_size = SGL_PG_SZ_MAX; |
586 | |
587 | if (num_sg_lists < NUM_SGL_MIN) |
588 | num_sg_lists = NUM_SGL_MIN; |
589 | else if (num_sg_lists > NUM_SGL_MAX) |
590 | num_sg_lists = NUM_SGL_MAX; |
591 | |
592 | if (num_requests < NUM_REQ_MIN) |
593 | num_requests = NUM_REQ_MIN; |
594 | else if (num_requests > NUM_REQ_MAX) |
595 | num_requests = NUM_REQ_MAX; |
596 | |
597 | if (num_ae_requests < NUM_AE_MIN) |
598 | num_ae_requests = NUM_AE_MIN; |
599 | else if (num_ae_requests > NUM_AE_MAX) |
600 | num_ae_requests = NUM_AE_MAX; |
601 | |
602 | /* set up other globals */ |
603 | |
604 | for (i = 0; i < MAX_ADAPTERS; i++) |
605 | esas2r_adapters[i] = NULL; |
606 | |
607 | return pci_register_driver(&esas2r_pci_driver); |
608 | } |
609 | |
610 | /* Handle ioctl calls to "/proc/scsi/esas2r/ATTOnode" */ |
611 | static const struct file_operations esas2r_proc_fops = { |
612 | .compat_ioctl = compat_ptr_ioctl, |
613 | .unlocked_ioctl = esas2r_proc_ioctl, |
614 | }; |
615 | |
616 | static const struct proc_ops esas2r_proc_ops = { |
617 | .proc_lseek = default_llseek, |
618 | .proc_ioctl = esas2r_proc_ioctl, |
619 | #ifdef CONFIG_COMPAT |
620 | .proc_compat_ioctl = compat_ptr_ioctl, |
621 | #endif |
622 | }; |
623 | |
624 | static struct Scsi_Host *esas2r_proc_host; |
625 | static int esas2r_proc_major; |
626 | |
627 | long esas2r_proc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) |
628 | { |
629 | return esas2r_ioctl_handler(hostdata: esas2r_proc_host->hostdata, |
630 | cmd, arg: (void __user *)arg); |
631 | } |
632 | |
633 | static void __exit esas2r_exit(void) |
634 | { |
635 | esas2r_log(level: ESAS2R_LOG_INFO, format: "%s called" , __func__); |
636 | |
637 | if (esas2r_proc_major > 0) { |
638 | struct proc_dir_entry *proc_dir; |
639 | |
640 | esas2r_log(level: ESAS2R_LOG_INFO, format: "unregister proc" ); |
641 | |
642 | proc_dir = scsi_template_proc_dir(sht: esas2r_proc_host->hostt); |
643 | if (proc_dir) |
644 | remove_proc_entry(ATTONODE_NAME, proc_dir); |
645 | unregister_chrdev(major: esas2r_proc_major, ESAS2R_DRVR_NAME); |
646 | |
647 | esas2r_proc_major = 0; |
648 | } |
649 | |
650 | esas2r_log(level: ESAS2R_LOG_INFO, format: "pci_unregister_driver() called" ); |
651 | |
652 | pci_unregister_driver(dev: &esas2r_pci_driver); |
653 | } |
654 | |
655 | int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh) |
656 | { |
657 | struct esas2r_adapter *a = (struct esas2r_adapter *)sh->hostdata; |
658 | |
659 | struct esas2r_target *t; |
660 | int dev_count = 0; |
661 | |
662 | esas2r_log(level: ESAS2R_LOG_DEBG, format: "esas2r_show_info (%p,%d)" , m, sh->host_no); |
663 | |
664 | seq_printf(m, ESAS2R_LONGNAME "\n" |
665 | "Driver version: " ESAS2R_VERSION_STR "\n" |
666 | "Flash version: %s\n" |
667 | "Firmware version: %s\n" |
668 | "Copyright " ESAS2R_COPYRIGHT_YEARS "\n" |
669 | "http://www.attotech.com\n" |
670 | "\n" , |
671 | a->flash_rev, |
672 | a->fw_rev[0] ? a->fw_rev : "(none)" ); |
673 | |
674 | |
675 | seq_printf(m, fmt: "Adapter information:\n" |
676 | "--------------------\n" |
677 | "Model: %s\n" |
678 | "SAS address: %02X%02X%02X%02X:%02X%02X%02X%02X\n" , |
679 | esas2r_get_model_name(a), |
680 | a->nvram->sas_addr[0], |
681 | a->nvram->sas_addr[1], |
682 | a->nvram->sas_addr[2], |
683 | a->nvram->sas_addr[3], |
684 | a->nvram->sas_addr[4], |
685 | a->nvram->sas_addr[5], |
686 | a->nvram->sas_addr[6], |
687 | a->nvram->sas_addr[7]); |
688 | |
689 | seq_puts(m, s: "\n" |
690 | "Discovered devices:\n" |
691 | "\n" |
692 | " # Target ID\n" |
693 | "---------------\n" ); |
694 | |
695 | for (t = a->targetdb; t < a->targetdb_end; t++) |
696 | if (t->buffered_target_state == TS_PRESENT) { |
697 | seq_printf(m, fmt: " %3d %3d\n" , |
698 | ++dev_count, |
699 | (u16)(uintptr_t)(t - a->targetdb)); |
700 | } |
701 | |
702 | if (dev_count == 0) |
703 | seq_puts(m, s: "none\n" ); |
704 | |
705 | seq_putc(m, c: '\n'); |
706 | return 0; |
707 | |
708 | } |
709 | |
710 | const char *esas2r_info(struct Scsi_Host *sh) |
711 | { |
712 | struct esas2r_adapter *a = (struct esas2r_adapter *)sh->hostdata; |
713 | static char esas2r_info_str[512]; |
714 | |
715 | esas2r_log_dev(level: ESAS2R_LOG_INFO, dev: &(sh->shost_gendev), |
716 | format: "esas2r_info() called" ); |
717 | |
718 | /* |
719 | * if we haven't done so already, register as a char driver |
720 | * and stick a node under "/proc/scsi/esas2r/ATTOnode" |
721 | */ |
722 | |
723 | if (esas2r_proc_major <= 0) { |
724 | esas2r_proc_host = sh; |
725 | |
726 | esas2r_proc_major = register_chrdev(major: 0, ESAS2R_DRVR_NAME, |
727 | fops: &esas2r_proc_fops); |
728 | |
729 | esas2r_log_dev(level: ESAS2R_LOG_DEBG, dev: &(sh->shost_gendev), |
730 | format: "register_chrdev (major %d)" , |
731 | esas2r_proc_major); |
732 | |
733 | if (esas2r_proc_major > 0) { |
734 | struct proc_dir_entry *proc_dir; |
735 | struct proc_dir_entry *pde = NULL; |
736 | |
737 | proc_dir = scsi_template_proc_dir(sht: sh->hostt); |
738 | if (proc_dir) |
739 | pde = proc_create(ATTONODE_NAME, mode: 0, parent: proc_dir, |
740 | proc_ops: &esas2r_proc_ops); |
741 | |
742 | if (!pde) { |
743 | esas2r_log_dev(level: ESAS2R_LOG_WARN, |
744 | dev: &(sh->shost_gendev), |
745 | format: "failed to create_proc_entry" ); |
746 | esas2r_proc_major = -1; |
747 | } |
748 | } |
749 | } |
750 | |
751 | sprintf(buf: esas2r_info_str, |
752 | ESAS2R_LONGNAME " (bus 0x%02X, device 0x%02X, IRQ 0x%02X)" |
753 | " driver version: " ESAS2R_VERSION_STR " firmware version: " |
754 | "%s\n" , |
755 | a->pcid->bus->number, a->pcid->devfn, a->pcid->irq, |
756 | a->fw_rev[0] ? a->fw_rev : "(none)" ); |
757 | |
758 | return esas2r_info_str; |
759 | } |
760 | |
761 | /* Callback for building a request scatter/gather list */ |
762 | static u32 get_physaddr_from_sgc(struct esas2r_sg_context *sgc, u64 *addr) |
763 | { |
764 | u32 len; |
765 | |
766 | if (likely(sgc->cur_offset == sgc->exp_offset)) { |
767 | /* |
768 | * the normal case: caller used all bytes from previous call, so |
769 | * expected offset is the same as the current offset. |
770 | */ |
771 | |
772 | if (sgc->sgel_count < sgc->num_sgel) { |
773 | /* retrieve next segment, except for first time */ |
774 | if (sgc->exp_offset > (u8 *)0) { |
775 | /* advance current segment */ |
776 | sgc->cur_sgel = sg_next(sgc->cur_sgel); |
777 | ++(sgc->sgel_count); |
778 | } |
779 | |
780 | |
781 | len = sg_dma_len(sgc->cur_sgel); |
782 | (*addr) = sg_dma_address(sgc->cur_sgel); |
783 | |
784 | /* save the total # bytes returned to caller so far */ |
785 | sgc->exp_offset += len; |
786 | |
787 | } else { |
788 | len = 0; |
789 | } |
790 | } else if (sgc->cur_offset < sgc->exp_offset) { |
791 | /* |
792 | * caller did not use all bytes from previous call. need to |
793 | * compute the address based on current segment. |
794 | */ |
795 | |
796 | len = sg_dma_len(sgc->cur_sgel); |
797 | (*addr) = sg_dma_address(sgc->cur_sgel); |
798 | |
799 | sgc->exp_offset -= len; |
800 | |
801 | /* calculate PA based on prev segment address and offsets */ |
802 | *addr = *addr + |
803 | (sgc->cur_offset - sgc->exp_offset); |
804 | |
805 | sgc->exp_offset += len; |
806 | |
807 | /* re-calculate length based on offset */ |
808 | len = lower_32_bits( |
809 | sgc->exp_offset - sgc->cur_offset); |
810 | } else { /* if ( sgc->cur_offset > sgc->exp_offset ) */ |
811 | /* |
812 | * we don't expect the caller to skip ahead. |
813 | * cur_offset will never exceed the len we return |
814 | */ |
815 | len = 0; |
816 | } |
817 | |
818 | return len; |
819 | } |
820 | |
821 | int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) |
822 | { |
823 | struct esas2r_adapter *a = |
824 | (struct esas2r_adapter *)cmd->device->host->hostdata; |
825 | struct esas2r_request *rq; |
826 | struct esas2r_sg_context sgc; |
827 | unsigned bufflen; |
828 | |
829 | /* Assume success, if it fails we will fix the result later. */ |
830 | cmd->result = DID_OK << 16; |
831 | |
832 | if (unlikely(test_bit(AF_DEGRADED_MODE, &a->flags))) { |
833 | cmd->result = DID_NO_CONNECT << 16; |
834 | scsi_done(cmd); |
835 | return 0; |
836 | } |
837 | |
838 | rq = esas2r_alloc_request(a); |
839 | if (unlikely(rq == NULL)) { |
840 | esas2r_debug("esas2r_alloc_request failed" ); |
841 | return SCSI_MLQUEUE_HOST_BUSY; |
842 | } |
843 | |
844 | rq->cmd = cmd; |
845 | bufflen = scsi_bufflen(cmd); |
846 | |
847 | if (likely(bufflen != 0)) { |
848 | if (cmd->sc_data_direction == DMA_TO_DEVICE) |
849 | rq->vrq->scsi.flags |= cpu_to_le32(FCP_CMND_WRD); |
850 | else if (cmd->sc_data_direction == DMA_FROM_DEVICE) |
851 | rq->vrq->scsi.flags |= cpu_to_le32(FCP_CMND_RDD); |
852 | } |
853 | |
854 | memcpy(rq->vrq->scsi.cdb, cmd->cmnd, cmd->cmd_len); |
855 | rq->vrq->scsi.length = cpu_to_le32(bufflen); |
856 | rq->target_id = cmd->device->id; |
857 | rq->vrq->scsi.flags |= cpu_to_le32(cmd->device->lun); |
858 | rq->sense_buf = cmd->sense_buffer; |
859 | rq->sense_len = SCSI_SENSE_BUFFERSIZE; |
860 | |
861 | esas2r_sgc_init(sgc: &sgc, a, rq, NULL); |
862 | |
863 | sgc.length = bufflen; |
864 | sgc.cur_offset = NULL; |
865 | |
866 | sgc.cur_sgel = scsi_sglist(cmd); |
867 | sgc.exp_offset = NULL; |
868 | sgc.num_sgel = scsi_dma_map(cmd); |
869 | sgc.sgel_count = 0; |
870 | |
871 | if (unlikely(sgc.num_sgel < 0)) { |
872 | esas2r_free_request(a, rq); |
873 | return SCSI_MLQUEUE_HOST_BUSY; |
874 | } |
875 | |
876 | sgc.get_phys_addr = (PGETPHYSADDR)get_physaddr_from_sgc; |
877 | |
878 | if (unlikely(!esas2r_build_sg_list(a, rq, &sgc))) { |
879 | scsi_dma_unmap(cmd); |
880 | esas2r_free_request(a, rq); |
881 | return SCSI_MLQUEUE_HOST_BUSY; |
882 | } |
883 | |
884 | esas2r_debug("start request %p to %d:%d\n" , rq, (int)cmd->device->id, |
885 | (int)cmd->device->lun); |
886 | |
887 | esas2r_start_request(a, rq); |
888 | |
889 | return 0; |
890 | } |
891 | |
892 | static void complete_task_management_request(struct esas2r_adapter *a, |
893 | struct esas2r_request *rq) |
894 | { |
895 | (*rq->task_management_status_ptr) = rq->req_stat; |
896 | esas2r_free_request(a, rq); |
897 | } |
898 | |
899 | /* |
900 | * Searches the specified queue for the specified queue for the command |
901 | * to abort. |
902 | * |
903 | * Return 0 on failure, 1 if command was not found, 2 if command was found |
904 | */ |
905 | static int esas2r_check_active_queue(struct esas2r_adapter *a, |
906 | struct esas2r_request **abort_request, |
907 | struct scsi_cmnd *cmd, |
908 | struct list_head *queue) |
909 | { |
910 | bool found = false; |
911 | struct esas2r_request *ar = *abort_request; |
912 | struct esas2r_request *rq; |
913 | struct list_head *element, *next; |
914 | |
915 | list_for_each_safe(element, next, queue) { |
916 | |
917 | rq = list_entry(element, struct esas2r_request, req_list); |
918 | |
919 | if (rq->cmd == cmd) { |
920 | |
921 | /* Found the request. See what to do with it. */ |
922 | if (queue == &a->active_list) { |
923 | /* |
924 | * We are searching the active queue, which |
925 | * means that we need to send an abort request |
926 | * to the firmware. |
927 | */ |
928 | ar = esas2r_alloc_request(a); |
929 | if (ar == NULL) { |
930 | esas2r_log_dev(level: ESAS2R_LOG_WARN, |
931 | dev: &(a->host->shost_gendev), |
932 | format: "unable to allocate an abort request for cmd %p" , |
933 | cmd); |
934 | return 0; /* Failure */ |
935 | } |
936 | |
937 | /* |
938 | * Task management request must be formatted |
939 | * with a lock held. |
940 | */ |
941 | ar->sense_len = 0; |
942 | ar->vrq->scsi.length = 0; |
943 | ar->target_id = rq->target_id; |
944 | ar->vrq->scsi.flags |= cpu_to_le32( |
945 | (u8)le32_to_cpu(rq->vrq->scsi.flags)); |
946 | |
947 | memset(ar->vrq->scsi.cdb, 0, |
948 | sizeof(ar->vrq->scsi.cdb)); |
949 | |
950 | ar->vrq->scsi.flags |= cpu_to_le32( |
951 | FCP_CMND_TRM); |
952 | ar->vrq->scsi.u.abort_handle = |
953 | rq->vrq->scsi.handle; |
954 | } else { |
955 | /* |
956 | * The request is pending but not active on |
957 | * the firmware. Just free it now and we'll |
958 | * report the successful abort below. |
959 | */ |
960 | list_del_init(entry: &rq->req_list); |
961 | esas2r_free_request(a, rq); |
962 | } |
963 | |
964 | found = true; |
965 | break; |
966 | } |
967 | |
968 | } |
969 | |
970 | if (!found) |
971 | return 1; /* Not found */ |
972 | |
973 | return 2; /* found */ |
974 | |
975 | |
976 | } |
977 | |
978 | int esas2r_eh_abort(struct scsi_cmnd *cmd) |
979 | { |
980 | struct esas2r_adapter *a = |
981 | (struct esas2r_adapter *)cmd->device->host->hostdata; |
982 | struct esas2r_request *abort_request = NULL; |
983 | unsigned long flags; |
984 | struct list_head *queue; |
985 | int result; |
986 | |
987 | esas2r_log(level: ESAS2R_LOG_INFO, format: "eh_abort (%p)" , cmd); |
988 | |
989 | if (test_bit(AF_DEGRADED_MODE, &a->flags)) { |
990 | cmd->result = DID_ABORT << 16; |
991 | |
992 | scsi_set_resid(cmd, resid: 0); |
993 | |
994 | scsi_done(cmd); |
995 | |
996 | return SUCCESS; |
997 | } |
998 | |
999 | spin_lock_irqsave(&a->queue_lock, flags); |
1000 | |
1001 | /* |
1002 | * Run through the defer and active queues looking for the request |
1003 | * to abort. |
1004 | */ |
1005 | |
1006 | queue = &a->defer_list; |
1007 | |
1008 | check_active_queue: |
1009 | |
1010 | result = esas2r_check_active_queue(a, abort_request: &abort_request, cmd, queue); |
1011 | |
1012 | if (!result) { |
1013 | spin_unlock_irqrestore(lock: &a->queue_lock, flags); |
1014 | return FAILED; |
1015 | } else if (result == 2 && (queue == &a->defer_list)) { |
1016 | queue = &a->active_list; |
1017 | goto check_active_queue; |
1018 | } |
1019 | |
1020 | spin_unlock_irqrestore(lock: &a->queue_lock, flags); |
1021 | |
1022 | if (abort_request) { |
1023 | u8 task_management_status = RS_PENDING; |
1024 | |
1025 | /* |
1026 | * the request is already active, so we need to tell |
1027 | * the firmware to abort it and wait for the response. |
1028 | */ |
1029 | |
1030 | abort_request->comp_cb = complete_task_management_request; |
1031 | abort_request->task_management_status_ptr = |
1032 | &task_management_status; |
1033 | |
1034 | esas2r_start_request(a, rq: abort_request); |
1035 | |
1036 | if (atomic_read(v: &a->disable_cnt) == 0) |
1037 | esas2r_do_deferred_processes(a); |
1038 | |
1039 | while (task_management_status == RS_PENDING) |
1040 | msleep(msecs: 10); |
1041 | |
1042 | /* |
1043 | * Once we get here, the original request will have been |
1044 | * completed by the firmware and the abort request will have |
1045 | * been cleaned up. we're done! |
1046 | */ |
1047 | |
1048 | return SUCCESS; |
1049 | } |
1050 | |
1051 | /* |
1052 | * If we get here, either we found the inactive request and |
1053 | * freed it, or we didn't find it at all. Either way, success! |
1054 | */ |
1055 | |
1056 | cmd->result = DID_ABORT << 16; |
1057 | |
1058 | scsi_set_resid(cmd, resid: 0); |
1059 | |
1060 | scsi_done(cmd); |
1061 | |
1062 | return SUCCESS; |
1063 | } |
1064 | |
1065 | static int esas2r_host_bus_reset(struct scsi_cmnd *cmd, bool host_reset) |
1066 | { |
1067 | struct esas2r_adapter *a = |
1068 | (struct esas2r_adapter *)cmd->device->host->hostdata; |
1069 | |
1070 | if (test_bit(AF_DEGRADED_MODE, &a->flags)) |
1071 | return FAILED; |
1072 | |
1073 | if (host_reset) |
1074 | esas2r_reset_adapter(a); |
1075 | else |
1076 | esas2r_reset_bus(a); |
1077 | |
1078 | /* above call sets the AF_OS_RESET flag. wait for it to clear. */ |
1079 | |
1080 | while (test_bit(AF_OS_RESET, &a->flags)) { |
1081 | msleep(msecs: 10); |
1082 | |
1083 | if (test_bit(AF_DEGRADED_MODE, &a->flags)) |
1084 | return FAILED; |
1085 | } |
1086 | |
1087 | if (test_bit(AF_DEGRADED_MODE, &a->flags)) |
1088 | return FAILED; |
1089 | |
1090 | return SUCCESS; |
1091 | } |
1092 | |
1093 | int esas2r_host_reset(struct scsi_cmnd *cmd) |
1094 | { |
1095 | esas2r_log(level: ESAS2R_LOG_INFO, format: "host_reset (%p)" , cmd); |
1096 | |
1097 | return esas2r_host_bus_reset(cmd, host_reset: true); |
1098 | } |
1099 | |
1100 | int esas2r_bus_reset(struct scsi_cmnd *cmd) |
1101 | { |
1102 | esas2r_log(level: ESAS2R_LOG_INFO, format: "bus_reset (%p)" , cmd); |
1103 | |
1104 | return esas2r_host_bus_reset(cmd, host_reset: false); |
1105 | } |
1106 | |
1107 | static int esas2r_dev_targ_reset(struct scsi_cmnd *cmd, bool target_reset) |
1108 | { |
1109 | struct esas2r_adapter *a = |
1110 | (struct esas2r_adapter *)cmd->device->host->hostdata; |
1111 | struct esas2r_request *rq; |
1112 | u8 task_management_status = RS_PENDING; |
1113 | bool completed; |
1114 | |
1115 | if (test_bit(AF_DEGRADED_MODE, &a->flags)) |
1116 | return FAILED; |
1117 | |
1118 | retry: |
1119 | rq = esas2r_alloc_request(a); |
1120 | if (rq == NULL) { |
1121 | if (target_reset) { |
1122 | esas2r_log(level: ESAS2R_LOG_CRIT, |
1123 | format: "unable to allocate a request for a " |
1124 | "target reset (%d)!" , |
1125 | cmd->device->id); |
1126 | } else { |
1127 | esas2r_log(level: ESAS2R_LOG_CRIT, |
1128 | format: "unable to allocate a request for a " |
1129 | "device reset (%d:%llu)!" , |
1130 | cmd->device->id, |
1131 | cmd->device->lun); |
1132 | } |
1133 | |
1134 | |
1135 | return FAILED; |
1136 | } |
1137 | |
1138 | rq->target_id = cmd->device->id; |
1139 | rq->vrq->scsi.flags |= cpu_to_le32(cmd->device->lun); |
1140 | rq->req_stat = RS_PENDING; |
1141 | |
1142 | rq->comp_cb = complete_task_management_request; |
1143 | rq->task_management_status_ptr = &task_management_status; |
1144 | |
1145 | if (target_reset) { |
1146 | esas2r_debug("issuing target reset (%p) to id %d" , rq, |
1147 | cmd->device->id); |
1148 | completed = esas2r_send_task_mgmt(a, rqaux: rq, task_mgt_func: 0x20); |
1149 | } else { |
1150 | esas2r_debug("issuing device reset (%p) to id %d lun %d" , rq, |
1151 | cmd->device->id, cmd->device->lun); |
1152 | completed = esas2r_send_task_mgmt(a, rqaux: rq, task_mgt_func: 0x10); |
1153 | } |
1154 | |
1155 | if (completed) { |
1156 | /* Task management cmd completed right away, need to free it. */ |
1157 | |
1158 | esas2r_free_request(a, rq); |
1159 | } else { |
1160 | /* |
1161 | * Wait for firmware to complete the request. Completion |
1162 | * callback will free it. |
1163 | */ |
1164 | while (task_management_status == RS_PENDING) |
1165 | msleep(msecs: 10); |
1166 | } |
1167 | |
1168 | if (test_bit(AF_DEGRADED_MODE, &a->flags)) |
1169 | return FAILED; |
1170 | |
1171 | if (task_management_status == RS_BUSY) { |
1172 | /* |
1173 | * Busy, probably because we are flashing. Wait a bit and |
1174 | * try again. |
1175 | */ |
1176 | msleep(msecs: 100); |
1177 | goto retry; |
1178 | } |
1179 | |
1180 | return SUCCESS; |
1181 | } |
1182 | |
1183 | int esas2r_device_reset(struct scsi_cmnd *cmd) |
1184 | { |
1185 | esas2r_log(level: ESAS2R_LOG_INFO, format: "device_reset (%p)" , cmd); |
1186 | |
1187 | return esas2r_dev_targ_reset(cmd, target_reset: false); |
1188 | |
1189 | } |
1190 | |
1191 | int esas2r_target_reset(struct scsi_cmnd *cmd) |
1192 | { |
1193 | esas2r_log(level: ESAS2R_LOG_INFO, format: "target_reset (%p)" , cmd); |
1194 | |
1195 | return esas2r_dev_targ_reset(cmd, target_reset: true); |
1196 | } |
1197 | |
1198 | void esas2r_log_request_failure(struct esas2r_adapter *a, |
1199 | struct esas2r_request *rq) |
1200 | { |
1201 | u8 reqstatus = rq->req_stat; |
1202 | |
1203 | if (reqstatus == RS_SUCCESS) |
1204 | return; |
1205 | |
1206 | if (rq->vrq->scsi.function == VDA_FUNC_SCSI) { |
1207 | if (reqstatus == RS_SCSI_ERROR) { |
1208 | if (rq->func_rsp.scsi_rsp.sense_len >= 13) { |
1209 | esas2r_log(level: ESAS2R_LOG_WARN, |
1210 | format: "request failure - SCSI error %x ASC:%x ASCQ:%x CDB:%x" , |
1211 | rq->sense_buf[2], rq->sense_buf[12], |
1212 | rq->sense_buf[13], |
1213 | rq->vrq->scsi.cdb[0]); |
1214 | } else { |
1215 | esas2r_log(level: ESAS2R_LOG_WARN, |
1216 | format: "request failure - SCSI error CDB:%x\n" , |
1217 | rq->vrq->scsi.cdb[0]); |
1218 | } |
1219 | } else if ((rq->vrq->scsi.cdb[0] != INQUIRY |
1220 | && rq->vrq->scsi.cdb[0] != REPORT_LUNS) |
1221 | || (reqstatus != RS_SEL |
1222 | && reqstatus != RS_SEL2)) { |
1223 | if ((reqstatus == RS_UNDERRUN) && |
1224 | (rq->vrq->scsi.cdb[0] == INQUIRY)) { |
1225 | /* Don't log inquiry underruns */ |
1226 | } else { |
1227 | esas2r_log(level: ESAS2R_LOG_WARN, |
1228 | format: "request failure - cdb:%x reqstatus:%d target:%d" , |
1229 | rq->vrq->scsi.cdb[0], reqstatus, |
1230 | rq->target_id); |
1231 | } |
1232 | } |
1233 | } |
1234 | } |
1235 | |
1236 | void esas2r_wait_request(struct esas2r_adapter *a, struct esas2r_request *rq) |
1237 | { |
1238 | u32 starttime; |
1239 | u32 timeout; |
1240 | |
1241 | starttime = jiffies_to_msecs(j: jiffies); |
1242 | timeout = rq->timeout ? rq->timeout : 5000; |
1243 | |
1244 | while (true) { |
1245 | esas2r_polled_interrupt(a); |
1246 | |
1247 | if (rq->req_stat != RS_STARTED) |
1248 | break; |
1249 | |
1250 | schedule_timeout_interruptible(timeout: msecs_to_jiffies(m: 100)); |
1251 | |
1252 | if ((jiffies_to_msecs(j: jiffies) - starttime) > timeout) { |
1253 | esas2r_hdebug("request TMO" ); |
1254 | esas2r_bugon(); |
1255 | |
1256 | rq->req_stat = RS_TIMEOUT; |
1257 | |
1258 | esas2r_local_reset_adapter(a); |
1259 | return; |
1260 | } |
1261 | } |
1262 | } |
1263 | |
1264 | u32 esas2r_map_data_window(struct esas2r_adapter *a, u32 addr_lo) |
1265 | { |
1266 | u32 offset = addr_lo & (MW_DATA_WINDOW_SIZE - 1); |
1267 | u32 base = addr_lo & -(signed int)MW_DATA_WINDOW_SIZE; |
1268 | |
1269 | if (a->window_base != base) { |
1270 | esas2r_write_register_dword(a, MVR_PCI_WIN1_REMAP, |
1271 | base | MVRPW1R_ENABLE); |
1272 | esas2r_flush_register_dword(a, MVR_PCI_WIN1_REMAP); |
1273 | a->window_base = base; |
1274 | } |
1275 | |
1276 | return offset; |
1277 | } |
1278 | |
1279 | /* Read a block of data from chip memory */ |
1280 | bool esas2r_read_mem_block(struct esas2r_adapter *a, |
1281 | void *to, |
1282 | u32 from, |
1283 | u32 size) |
1284 | { |
1285 | u8 *end = (u8 *)to; |
1286 | |
1287 | while (size) { |
1288 | u32 len; |
1289 | u32 offset; |
1290 | u32 iatvr; |
1291 | |
1292 | iatvr = (from & -(signed int)MW_DATA_WINDOW_SIZE); |
1293 | |
1294 | esas2r_map_data_window(a, addr_lo: iatvr); |
1295 | |
1296 | offset = from & (MW_DATA_WINDOW_SIZE - 1); |
1297 | len = size; |
1298 | |
1299 | if (len > MW_DATA_WINDOW_SIZE - offset) |
1300 | len = MW_DATA_WINDOW_SIZE - offset; |
1301 | |
1302 | from += len; |
1303 | size -= len; |
1304 | |
1305 | while (len--) { |
1306 | *end++ = esas2r_read_data_byte(a, offset); |
1307 | offset++; |
1308 | } |
1309 | } |
1310 | |
1311 | return true; |
1312 | } |
1313 | |
1314 | void esas2r_nuxi_mgt_data(u8 function, void *data) |
1315 | { |
1316 | struct atto_vda_grp_info *g; |
1317 | struct atto_vda_devinfo *d; |
1318 | struct atto_vdapart_info *p; |
1319 | struct atto_vda_dh_info *h; |
1320 | struct atto_vda_metrics_info *m; |
1321 | struct atto_vda_schedule_info *s; |
1322 | struct atto_vda_buzzer_info *b; |
1323 | u8 i; |
1324 | |
1325 | switch (function) { |
1326 | case VDAMGT_BUZZER_INFO: |
1327 | case VDAMGT_BUZZER_SET: |
1328 | |
1329 | b = (struct atto_vda_buzzer_info *)data; |
1330 | |
1331 | b->duration = le32_to_cpu(b->duration); |
1332 | break; |
1333 | |
1334 | case VDAMGT_SCHEDULE_INFO: |
1335 | case VDAMGT_SCHEDULE_EVENT: |
1336 | |
1337 | s = (struct atto_vda_schedule_info *)data; |
1338 | |
1339 | s->id = le32_to_cpu(s->id); |
1340 | |
1341 | break; |
1342 | |
1343 | case VDAMGT_DEV_INFO: |
1344 | case VDAMGT_DEV_CLEAN: |
1345 | case VDAMGT_DEV_PT_INFO: |
1346 | case VDAMGT_DEV_FEATURES: |
1347 | case VDAMGT_DEV_PT_FEATURES: |
1348 | case VDAMGT_DEV_OPERATION: |
1349 | |
1350 | d = (struct atto_vda_devinfo *)data; |
1351 | |
1352 | d->capacity = le64_to_cpu(d->capacity); |
1353 | d->block_size = le32_to_cpu(d->block_size); |
1354 | d->ses_dev_index = le16_to_cpu(d->ses_dev_index); |
1355 | d->target_id = le16_to_cpu(d->target_id); |
1356 | d->lun = le16_to_cpu(d->lun); |
1357 | d->features = le16_to_cpu(d->features); |
1358 | break; |
1359 | |
1360 | case VDAMGT_GRP_INFO: |
1361 | case VDAMGT_GRP_CREATE: |
1362 | case VDAMGT_GRP_DELETE: |
1363 | case VDAMGT_ADD_STORAGE: |
1364 | case VDAMGT_MEMBER_ADD: |
1365 | case VDAMGT_GRP_COMMIT: |
1366 | case VDAMGT_GRP_REBUILD: |
1367 | case VDAMGT_GRP_COMMIT_INIT: |
1368 | case VDAMGT_QUICK_RAID: |
1369 | case VDAMGT_GRP_FEATURES: |
1370 | case VDAMGT_GRP_COMMIT_INIT_AUTOMAP: |
1371 | case VDAMGT_QUICK_RAID_INIT_AUTOMAP: |
1372 | case VDAMGT_SPARE_LIST: |
1373 | case VDAMGT_SPARE_ADD: |
1374 | case VDAMGT_SPARE_REMOVE: |
1375 | case VDAMGT_LOCAL_SPARE_ADD: |
1376 | case VDAMGT_GRP_OPERATION: |
1377 | |
1378 | g = (struct atto_vda_grp_info *)data; |
1379 | |
1380 | g->capacity = le64_to_cpu(g->capacity); |
1381 | g->block_size = le32_to_cpu(g->block_size); |
1382 | g->interleave = le32_to_cpu(g->interleave); |
1383 | g->features = le16_to_cpu(g->features); |
1384 | |
1385 | for (i = 0; i < 32; i++) |
1386 | g->members[i] = le16_to_cpu(g->members[i]); |
1387 | |
1388 | break; |
1389 | |
1390 | case VDAMGT_PART_INFO: |
1391 | case VDAMGT_PART_MAP: |
1392 | case VDAMGT_PART_UNMAP: |
1393 | case VDAMGT_PART_AUTOMAP: |
1394 | case VDAMGT_PART_SPLIT: |
1395 | case VDAMGT_PART_MERGE: |
1396 | |
1397 | p = (struct atto_vdapart_info *)data; |
1398 | |
1399 | p->part_size = le64_to_cpu(p->part_size); |
1400 | p->start_lba = le32_to_cpu(p->start_lba); |
1401 | p->block_size = le32_to_cpu(p->block_size); |
1402 | p->target_id = le16_to_cpu(p->target_id); |
1403 | break; |
1404 | |
1405 | case VDAMGT_DEV_HEALTH_REQ: |
1406 | |
1407 | h = (struct atto_vda_dh_info *)data; |
1408 | |
1409 | h->med_defect_cnt = le32_to_cpu(h->med_defect_cnt); |
1410 | h->info_exc_cnt = le32_to_cpu(h->info_exc_cnt); |
1411 | break; |
1412 | |
1413 | case VDAMGT_DEV_METRICS: |
1414 | |
1415 | m = (struct atto_vda_metrics_info *)data; |
1416 | |
1417 | for (i = 0; i < 32; i++) |
1418 | m->dev_indexes[i] = le16_to_cpu(m->dev_indexes[i]); |
1419 | |
1420 | break; |
1421 | |
1422 | default: |
1423 | break; |
1424 | } |
1425 | } |
1426 | |
1427 | void esas2r_nuxi_cfg_data(u8 function, void *data) |
1428 | { |
1429 | struct atto_vda_cfg_init *ci; |
1430 | |
1431 | switch (function) { |
1432 | case VDA_CFG_INIT: |
1433 | case VDA_CFG_GET_INIT: |
1434 | case VDA_CFG_GET_INIT2: |
1435 | |
1436 | ci = (struct atto_vda_cfg_init *)data; |
1437 | |
1438 | ci->date_time.year = le16_to_cpu(ci->date_time.year); |
1439 | ci->sgl_page_size = le32_to_cpu(ci->sgl_page_size); |
1440 | ci->vda_version = le32_to_cpu(ci->vda_version); |
1441 | ci->epoch_time = le32_to_cpu(ci->epoch_time); |
1442 | ci->ioctl_tunnel = le32_to_cpu(ci->ioctl_tunnel); |
1443 | ci->num_targets_backend = le32_to_cpu(ci->num_targets_backend); |
1444 | break; |
1445 | |
1446 | default: |
1447 | break; |
1448 | } |
1449 | } |
1450 | |
1451 | void esas2r_nuxi_ae_data(union atto_vda_ae *ae) |
1452 | { |
1453 | struct atto_vda_ae_raid *r = &ae->raid; |
1454 | struct atto_vda_ae_lu *l = &ae->lu; |
1455 | |
1456 | switch (ae->hdr.bytype) { |
1457 | case VDAAE_HDR_TYPE_RAID: |
1458 | |
1459 | r->dwflags = le32_to_cpu(r->dwflags); |
1460 | break; |
1461 | |
1462 | case VDAAE_HDR_TYPE_LU: |
1463 | |
1464 | l->dwevent = le32_to_cpu(l->dwevent); |
1465 | l->wphys_target_id = le16_to_cpu(l->wphys_target_id); |
1466 | l->id.tgtlun.wtarget_id = le16_to_cpu(l->id.tgtlun.wtarget_id); |
1467 | |
1468 | if (l->hdr.bylength >= offsetof(struct atto_vda_ae_lu, id) |
1469 | + sizeof(struct atto_vda_ae_lu_tgt_lun_raid)) { |
1470 | l->id.tgtlun_raid.dwinterleave |
1471 | = le32_to_cpu(l->id.tgtlun_raid.dwinterleave); |
1472 | l->id.tgtlun_raid.dwblock_size |
1473 | = le32_to_cpu(l->id.tgtlun_raid.dwblock_size); |
1474 | } |
1475 | |
1476 | break; |
1477 | |
1478 | case VDAAE_HDR_TYPE_DISK: |
1479 | default: |
1480 | break; |
1481 | } |
1482 | } |
1483 | |
1484 | void esas2r_free_request(struct esas2r_adapter *a, struct esas2r_request *rq) |
1485 | { |
1486 | unsigned long flags; |
1487 | |
1488 | esas2r_rq_destroy_request(rq, a); |
1489 | spin_lock_irqsave(&a->request_lock, flags); |
1490 | list_add(new: &rq->comp_list, head: &a->avail_request); |
1491 | spin_unlock_irqrestore(lock: &a->request_lock, flags); |
1492 | } |
1493 | |
1494 | struct esas2r_request *esas2r_alloc_request(struct esas2r_adapter *a) |
1495 | { |
1496 | struct esas2r_request *rq; |
1497 | unsigned long flags; |
1498 | |
1499 | spin_lock_irqsave(&a->request_lock, flags); |
1500 | |
1501 | if (unlikely(list_empty(&a->avail_request))) { |
1502 | spin_unlock_irqrestore(lock: &a->request_lock, flags); |
1503 | return NULL; |
1504 | } |
1505 | |
1506 | rq = list_first_entry(&a->avail_request, struct esas2r_request, |
1507 | comp_list); |
1508 | list_del(entry: &rq->comp_list); |
1509 | spin_unlock_irqrestore(lock: &a->request_lock, flags); |
1510 | esas2r_rq_init_request(rq, a); |
1511 | |
1512 | return rq; |
1513 | |
1514 | } |
1515 | |
1516 | void esas2r_complete_request_cb(struct esas2r_adapter *a, |
1517 | struct esas2r_request *rq) |
1518 | { |
1519 | esas2r_debug("completing request %p\n" , rq); |
1520 | |
1521 | scsi_dma_unmap(cmd: rq->cmd); |
1522 | |
1523 | if (unlikely(rq->req_stat != RS_SUCCESS)) { |
1524 | esas2r_debug("[%x STATUS %x:%x (%x)]" , rq->target_id, |
1525 | rq->req_stat, |
1526 | rq->func_rsp.scsi_rsp.scsi_stat, |
1527 | rq->cmd); |
1528 | |
1529 | rq->cmd->result = |
1530 | ((esas2r_req_status_to_error(req_stat: rq->req_stat) << 16) |
1531 | | rq->func_rsp.scsi_rsp.scsi_stat); |
1532 | |
1533 | if (rq->req_stat == RS_UNDERRUN) |
1534 | scsi_set_resid(cmd: rq->cmd, |
1535 | le32_to_cpu(rq->func_rsp.scsi_rsp. |
1536 | residual_length)); |
1537 | else |
1538 | scsi_set_resid(cmd: rq->cmd, resid: 0); |
1539 | } |
1540 | |
1541 | scsi_done(cmd: rq->cmd); |
1542 | |
1543 | esas2r_free_request(a, rq); |
1544 | } |
1545 | |
1546 | /* Run tasklet to handle stuff outside of interrupt context. */ |
1547 | void esas2r_adapter_tasklet(unsigned long context) |
1548 | { |
1549 | struct esas2r_adapter *a = (struct esas2r_adapter *)context; |
1550 | |
1551 | if (unlikely(test_bit(AF2_TIMER_TICK, &a->flags2))) { |
1552 | clear_bit(AF2_TIMER_TICK, addr: &a->flags2); |
1553 | esas2r_timer_tick(a); |
1554 | } |
1555 | |
1556 | if (likely(test_bit(AF2_INT_PENDING, &a->flags2))) { |
1557 | clear_bit(AF2_INT_PENDING, addr: &a->flags2); |
1558 | esas2r_adapter_interrupt(a); |
1559 | } |
1560 | |
1561 | if (esas2r_is_tasklet_pending(a)) |
1562 | esas2r_do_tasklet_tasks(a); |
1563 | |
1564 | if (esas2r_is_tasklet_pending(a) |
1565 | || (test_bit(AF2_INT_PENDING, &a->flags2)) |
1566 | || (test_bit(AF2_TIMER_TICK, &a->flags2))) { |
1567 | clear_bit(AF_TASKLET_SCHEDULED, addr: &a->flags); |
1568 | esas2r_schedule_tasklet(a); |
1569 | } else { |
1570 | clear_bit(AF_TASKLET_SCHEDULED, addr: &a->flags); |
1571 | } |
1572 | } |
1573 | |
1574 | static void esas2r_timer_callback(struct timer_list *t); |
1575 | |
1576 | void esas2r_kickoff_timer(struct esas2r_adapter *a) |
1577 | { |
1578 | timer_setup(&a->timer, esas2r_timer_callback, 0); |
1579 | |
1580 | a->timer.expires = jiffies + |
1581 | msecs_to_jiffies(m: 100); |
1582 | |
1583 | add_timer(timer: &a->timer); |
1584 | } |
1585 | |
1586 | static void esas2r_timer_callback(struct timer_list *t) |
1587 | { |
1588 | struct esas2r_adapter *a = from_timer(a, t, timer); |
1589 | |
1590 | set_bit(AF2_TIMER_TICK, addr: &a->flags2); |
1591 | |
1592 | esas2r_schedule_tasklet(a); |
1593 | |
1594 | esas2r_kickoff_timer(a); |
1595 | } |
1596 | |
1597 | /* |
1598 | * Firmware events need to be handled outside of interrupt context |
1599 | * so we schedule a delayed_work to handle them. |
1600 | */ |
1601 | |
1602 | static void |
1603 | esas2r_free_fw_event(struct esas2r_fw_event_work *fw_event) |
1604 | { |
1605 | unsigned long flags; |
1606 | struct esas2r_adapter *a = fw_event->a; |
1607 | |
1608 | spin_lock_irqsave(&a->fw_event_lock, flags); |
1609 | list_del(entry: &fw_event->list); |
1610 | kfree(objp: fw_event); |
1611 | spin_unlock_irqrestore(lock: &a->fw_event_lock, flags); |
1612 | } |
1613 | |
1614 | void |
1615 | esas2r_fw_event_off(struct esas2r_adapter *a) |
1616 | { |
1617 | unsigned long flags; |
1618 | |
1619 | spin_lock_irqsave(&a->fw_event_lock, flags); |
1620 | a->fw_events_off = 1; |
1621 | spin_unlock_irqrestore(lock: &a->fw_event_lock, flags); |
1622 | } |
1623 | |
1624 | void |
1625 | esas2r_fw_event_on(struct esas2r_adapter *a) |
1626 | { |
1627 | unsigned long flags; |
1628 | |
1629 | spin_lock_irqsave(&a->fw_event_lock, flags); |
1630 | a->fw_events_off = 0; |
1631 | spin_unlock_irqrestore(lock: &a->fw_event_lock, flags); |
1632 | } |
1633 | |
1634 | static void esas2r_add_device(struct esas2r_adapter *a, u16 target_id) |
1635 | { |
1636 | int ret; |
1637 | struct scsi_device *scsi_dev; |
1638 | |
1639 | scsi_dev = scsi_device_lookup(a->host, 0, target_id, 0); |
1640 | |
1641 | if (scsi_dev) { |
1642 | esas2r_log_dev( |
1643 | level: ESAS2R_LOG_WARN, |
1644 | dev: &(scsi_dev-> |
1645 | sdev_gendev), |
1646 | format: "scsi device already exists at id %d" , target_id); |
1647 | |
1648 | scsi_device_put(scsi_dev); |
1649 | } else { |
1650 | esas2r_log_dev( |
1651 | level: ESAS2R_LOG_INFO, |
1652 | dev: &(a->host-> |
1653 | shost_gendev), |
1654 | format: "scsi_add_device() called for 0:%d:0" , |
1655 | target_id); |
1656 | |
1657 | ret = scsi_add_device(host: a->host, channel: 0, target: target_id, lun: 0); |
1658 | if (ret) { |
1659 | esas2r_log_dev( |
1660 | level: ESAS2R_LOG_CRIT, |
1661 | dev: &(a->host-> |
1662 | shost_gendev), |
1663 | format: "scsi_add_device failed with %d for id %d" , |
1664 | ret, target_id); |
1665 | } |
1666 | } |
1667 | } |
1668 | |
1669 | static void esas2r_remove_device(struct esas2r_adapter *a, u16 target_id) |
1670 | { |
1671 | struct scsi_device *scsi_dev; |
1672 | |
1673 | scsi_dev = scsi_device_lookup(a->host, 0, target_id, 0); |
1674 | |
1675 | if (scsi_dev) { |
1676 | scsi_device_set_state(sdev: scsi_dev, state: SDEV_OFFLINE); |
1677 | |
1678 | esas2r_log_dev( |
1679 | level: ESAS2R_LOG_INFO, |
1680 | dev: &(scsi_dev-> |
1681 | sdev_gendev), |
1682 | format: "scsi_remove_device() called for 0:%d:0" , |
1683 | target_id); |
1684 | |
1685 | scsi_remove_device(scsi_dev); |
1686 | |
1687 | esas2r_log_dev( |
1688 | level: ESAS2R_LOG_INFO, |
1689 | dev: &(scsi_dev-> |
1690 | sdev_gendev), |
1691 | format: "scsi_device_put() called" ); |
1692 | |
1693 | scsi_device_put(scsi_dev); |
1694 | } else { |
1695 | esas2r_log_dev( |
1696 | level: ESAS2R_LOG_WARN, |
1697 | dev: &(a->host->shost_gendev), |
1698 | format: "no target found at id %d" , |
1699 | target_id); |
1700 | } |
1701 | } |
1702 | |
1703 | /* |
1704 | * Sends a firmware asynchronous event to anyone who happens to be |
1705 | * listening on the defined ATTO VDA event ports. |
1706 | */ |
1707 | static void esas2r_send_ae_event(struct esas2r_fw_event_work *fw_event) |
1708 | { |
1709 | struct esas2r_vda_ae *ae = (struct esas2r_vda_ae *)fw_event->data; |
1710 | char *type; |
1711 | |
1712 | switch (ae->vda_ae.hdr.bytype) { |
1713 | case VDAAE_HDR_TYPE_RAID: |
1714 | type = "RAID group state change" ; |
1715 | break; |
1716 | |
1717 | case VDAAE_HDR_TYPE_LU: |
1718 | type = "Mapped destination LU change" ; |
1719 | break; |
1720 | |
1721 | case VDAAE_HDR_TYPE_DISK: |
1722 | type = "Physical disk inventory change" ; |
1723 | break; |
1724 | |
1725 | case VDAAE_HDR_TYPE_RESET: |
1726 | type = "Firmware reset" ; |
1727 | break; |
1728 | |
1729 | case VDAAE_HDR_TYPE_LOG_INFO: |
1730 | type = "Event Log message (INFO level)" ; |
1731 | break; |
1732 | |
1733 | case VDAAE_HDR_TYPE_LOG_WARN: |
1734 | type = "Event Log message (WARN level)" ; |
1735 | break; |
1736 | |
1737 | case VDAAE_HDR_TYPE_LOG_CRIT: |
1738 | type = "Event Log message (CRIT level)" ; |
1739 | break; |
1740 | |
1741 | case VDAAE_HDR_TYPE_LOG_FAIL: |
1742 | type = "Event Log message (FAIL level)" ; |
1743 | break; |
1744 | |
1745 | case VDAAE_HDR_TYPE_NVC: |
1746 | type = "NVCache change" ; |
1747 | break; |
1748 | |
1749 | case VDAAE_HDR_TYPE_TLG_INFO: |
1750 | type = "Time stamped log message (INFO level)" ; |
1751 | break; |
1752 | |
1753 | case VDAAE_HDR_TYPE_TLG_WARN: |
1754 | type = "Time stamped log message (WARN level)" ; |
1755 | break; |
1756 | |
1757 | case VDAAE_HDR_TYPE_TLG_CRIT: |
1758 | type = "Time stamped log message (CRIT level)" ; |
1759 | break; |
1760 | |
1761 | case VDAAE_HDR_TYPE_PWRMGT: |
1762 | type = "Power management" ; |
1763 | break; |
1764 | |
1765 | case VDAAE_HDR_TYPE_MUTE: |
1766 | type = "Mute button pressed" ; |
1767 | break; |
1768 | |
1769 | case VDAAE_HDR_TYPE_DEV: |
1770 | type = "Device attribute change" ; |
1771 | break; |
1772 | |
1773 | default: |
1774 | type = "Unknown" ; |
1775 | break; |
1776 | } |
1777 | |
1778 | esas2r_log(level: ESAS2R_LOG_WARN, |
1779 | format: "An async event of type \"%s\" was received from the firmware. The event contents are:" , |
1780 | type); |
1781 | esas2r_log_hexdump(level: ESAS2R_LOG_WARN, buf: &ae->vda_ae, |
1782 | len: ae->vda_ae.hdr.bylength); |
1783 | |
1784 | } |
1785 | |
1786 | static void |
1787 | esas2r_firmware_event_work(struct work_struct *work) |
1788 | { |
1789 | struct esas2r_fw_event_work *fw_event = |
1790 | container_of(work, struct esas2r_fw_event_work, work.work); |
1791 | |
1792 | struct esas2r_adapter *a = fw_event->a; |
1793 | |
1794 | u16 target_id = *(u16 *)&fw_event->data[0]; |
1795 | |
1796 | if (a->fw_events_off) |
1797 | goto done; |
1798 | |
1799 | switch (fw_event->type) { |
1800 | case fw_event_null: |
1801 | break; /* do nothing */ |
1802 | |
1803 | case fw_event_lun_change: |
1804 | esas2r_remove_device(a, target_id); |
1805 | esas2r_add_device(a, target_id); |
1806 | break; |
1807 | |
1808 | case fw_event_present: |
1809 | esas2r_add_device(a, target_id); |
1810 | break; |
1811 | |
1812 | case fw_event_not_present: |
1813 | esas2r_remove_device(a, target_id); |
1814 | break; |
1815 | |
1816 | case fw_event_vda_ae: |
1817 | esas2r_send_ae_event(fw_event); |
1818 | break; |
1819 | } |
1820 | |
1821 | done: |
1822 | esas2r_free_fw_event(fw_event); |
1823 | } |
1824 | |
1825 | void esas2r_queue_fw_event(struct esas2r_adapter *a, |
1826 | enum fw_event_type type, |
1827 | void *data, |
1828 | int data_sz) |
1829 | { |
1830 | struct esas2r_fw_event_work *fw_event; |
1831 | unsigned long flags; |
1832 | |
1833 | fw_event = kzalloc(size: sizeof(struct esas2r_fw_event_work), GFP_ATOMIC); |
1834 | if (!fw_event) { |
1835 | esas2r_log(level: ESAS2R_LOG_WARN, |
1836 | format: "esas2r_queue_fw_event failed to alloc" ); |
1837 | return; |
1838 | } |
1839 | |
1840 | if (type == fw_event_vda_ae) { |
1841 | struct esas2r_vda_ae *ae = |
1842 | (struct esas2r_vda_ae *)fw_event->data; |
1843 | |
1844 | ae->signature = ESAS2R_VDA_EVENT_SIG; |
1845 | ae->bus_number = a->pcid->bus->number; |
1846 | ae->devfn = a->pcid->devfn; |
1847 | memcpy(&ae->vda_ae, data, sizeof(ae->vda_ae)); |
1848 | } else { |
1849 | memcpy(fw_event->data, data, data_sz); |
1850 | } |
1851 | |
1852 | fw_event->type = type; |
1853 | fw_event->a = a; |
1854 | |
1855 | spin_lock_irqsave(&a->fw_event_lock, flags); |
1856 | list_add_tail(new: &fw_event->list, head: &a->fw_event_list); |
1857 | INIT_DELAYED_WORK(&fw_event->work, esas2r_firmware_event_work); |
1858 | queue_delayed_work_on( |
1859 | smp_processor_id(), wq: a->fw_event_q, work: &fw_event->work, |
1860 | delay: msecs_to_jiffies(m: 1)); |
1861 | spin_unlock_irqrestore(lock: &a->fw_event_lock, flags); |
1862 | } |
1863 | |
1864 | void esas2r_target_state_changed(struct esas2r_adapter *a, u16 targ_id, |
1865 | u8 state) |
1866 | { |
1867 | if (state == TS_LUN_CHANGE) |
1868 | esas2r_queue_fw_event(a, type: fw_event_lun_change, data: &targ_id, |
1869 | data_sz: sizeof(targ_id)); |
1870 | else if (state == TS_PRESENT) |
1871 | esas2r_queue_fw_event(a, type: fw_event_present, data: &targ_id, |
1872 | data_sz: sizeof(targ_id)); |
1873 | else if (state == TS_NOT_PRESENT) |
1874 | esas2r_queue_fw_event(a, type: fw_event_not_present, data: &targ_id, |
1875 | data_sz: sizeof(targ_id)); |
1876 | } |
1877 | |
1878 | /* Translate status to a Linux SCSI mid-layer error code */ |
1879 | int esas2r_req_status_to_error(u8 req_stat) |
1880 | { |
1881 | switch (req_stat) { |
1882 | case RS_OVERRUN: |
1883 | case RS_UNDERRUN: |
1884 | case RS_SUCCESS: |
1885 | /* |
1886 | * NOTE: SCSI mid-layer wants a good status for a SCSI error, because |
1887 | * it will check the scsi_stat value in the completion anyway. |
1888 | */ |
1889 | case RS_SCSI_ERROR: |
1890 | return DID_OK; |
1891 | |
1892 | case RS_SEL: |
1893 | case RS_SEL2: |
1894 | return DID_NO_CONNECT; |
1895 | |
1896 | case RS_RESET: |
1897 | return DID_RESET; |
1898 | |
1899 | case RS_ABORTED: |
1900 | return DID_ABORT; |
1901 | |
1902 | case RS_BUSY: |
1903 | return DID_BUS_BUSY; |
1904 | } |
1905 | |
1906 | /* everything else is just an error. */ |
1907 | |
1908 | return DID_ERROR; |
1909 | } |
1910 | |
1911 | module_init(esas2r_init); |
1912 | module_exit(esas2r_exit); |
1913 | |