1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. |
4 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. |
5 | */ |
6 | #include <linux/module.h> |
7 | #include <linux/mempool.h> |
8 | #include <linux/string.h> |
9 | #include <linux/slab.h> |
10 | #include <linux/errno.h> |
11 | #include <linux/init.h> |
12 | #include <linux/pci.h> |
13 | #include <linux/skbuff.h> |
14 | #include <linux/interrupt.h> |
15 | #include <linux/irq.h> |
16 | #include <linux/spinlock.h> |
17 | #include <linux/workqueue.h> |
18 | #include <linux/if_ether.h> |
19 | #include <linux/blk-mq-pci.h> |
20 | #include <scsi/fc/fc_fip.h> |
21 | #include <scsi/scsi_host.h> |
22 | #include <scsi/scsi_transport.h> |
23 | #include <scsi/scsi_transport_fc.h> |
24 | #include <scsi/scsi_tcq.h> |
25 | #include <scsi/libfc.h> |
26 | #include <scsi/fc_frame.h> |
27 | |
28 | #include "vnic_dev.h" |
29 | #include "vnic_intr.h" |
30 | #include "vnic_stats.h" |
31 | #include "fnic_io.h" |
32 | #include "fnic_fip.h" |
33 | #include "fnic.h" |
34 | |
35 | #define PCI_DEVICE_ID_CISCO_FNIC 0x0045 |
36 | |
37 | /* Timer to poll notification area for events. Used for MSI interrupts */ |
38 | #define FNIC_NOTIFY_TIMER_PERIOD (2 * HZ) |
39 | |
40 | static struct kmem_cache *fnic_sgl_cache[FNIC_SGL_NUM_CACHES]; |
41 | static struct kmem_cache *fnic_io_req_cache; |
42 | static LIST_HEAD(fnic_list); |
43 | static DEFINE_SPINLOCK(fnic_list_lock); |
44 | static DEFINE_IDA(fnic_ida); |
45 | |
46 | /* Supported devices by fnic module */ |
47 | static struct pci_device_id fnic_id_table[] = { |
48 | { PCI_DEVICE(PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_CISCO_FNIC) }, |
49 | { 0, } |
50 | }; |
51 | |
52 | MODULE_DESCRIPTION(DRV_DESCRIPTION); |
53 | MODULE_AUTHOR("Abhijeet Joglekar <abjoglek@cisco.com>, " |
54 | "Joseph R. Eykholt <jeykholt@cisco.com>" ); |
55 | MODULE_LICENSE("GPL v2" ); |
56 | MODULE_VERSION(DRV_VERSION); |
57 | MODULE_DEVICE_TABLE(pci, fnic_id_table); |
58 | |
59 | unsigned int fnic_log_level; |
60 | module_param(fnic_log_level, int, S_IRUGO|S_IWUSR); |
61 | MODULE_PARM_DESC(fnic_log_level, "bit mask of fnic logging levels" ); |
62 | |
63 | |
64 | unsigned int io_completions = FNIC_DFLT_IO_COMPLETIONS; |
65 | module_param(io_completions, int, S_IRUGO|S_IWUSR); |
66 | MODULE_PARM_DESC(io_completions, "Max CQ entries to process at a time" ); |
67 | |
68 | unsigned int fnic_trace_max_pages = 16; |
69 | module_param(fnic_trace_max_pages, uint, S_IRUGO|S_IWUSR); |
70 | MODULE_PARM_DESC(fnic_trace_max_pages, "Total allocated memory pages " |
71 | "for fnic trace buffer" ); |
72 | |
73 | unsigned int fnic_fc_trace_max_pages = 64; |
74 | module_param(fnic_fc_trace_max_pages, uint, S_IRUGO|S_IWUSR); |
75 | MODULE_PARM_DESC(fnic_fc_trace_max_pages, |
76 | "Total allocated memory pages for fc trace buffer" ); |
77 | |
78 | static unsigned int fnic_max_qdepth = FNIC_DFLT_QUEUE_DEPTH; |
79 | module_param(fnic_max_qdepth, uint, S_IRUGO|S_IWUSR); |
80 | MODULE_PARM_DESC(fnic_max_qdepth, "Queue depth to report for each LUN" ); |
81 | |
82 | static struct libfc_function_template fnic_transport_template = { |
83 | .frame_send = fnic_send, |
84 | .lport_set_port_id = fnic_set_port_id, |
85 | .fcp_abort_io = fnic_empty_scsi_cleanup, |
86 | .fcp_cleanup = fnic_empty_scsi_cleanup, |
87 | .exch_mgr_reset = fnic_exch_mgr_reset |
88 | }; |
89 | |
90 | static int fnic_slave_alloc(struct scsi_device *sdev) |
91 | { |
92 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); |
93 | |
94 | if (!rport || fc_remote_port_chkready(rport)) |
95 | return -ENXIO; |
96 | |
97 | scsi_change_queue_depth(sdev, fnic_max_qdepth); |
98 | return 0; |
99 | } |
100 | |
101 | static const struct scsi_host_template fnic_host_template = { |
102 | .module = THIS_MODULE, |
103 | .name = DRV_NAME, |
104 | .queuecommand = fnic_queuecommand, |
105 | .eh_timed_out = fc_eh_timed_out, |
106 | .eh_abort_handler = fnic_abort_cmd, |
107 | .eh_device_reset_handler = fnic_device_reset, |
108 | .eh_host_reset_handler = fnic_host_reset, |
109 | .slave_alloc = fnic_slave_alloc, |
110 | .change_queue_depth = scsi_change_queue_depth, |
111 | .this_id = -1, |
112 | .cmd_per_lun = 3, |
113 | .can_queue = FNIC_DFLT_IO_REQ, |
114 | .sg_tablesize = FNIC_MAX_SG_DESC_CNT, |
115 | .max_sectors = 0xffff, |
116 | .shost_groups = fnic_host_groups, |
117 | .track_queue_depth = 1, |
118 | .cmd_size = sizeof(struct fnic_cmd_priv), |
119 | .map_queues = fnic_mq_map_queues_cpus, |
120 | }; |
121 | |
122 | static void |
123 | fnic_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) |
124 | { |
125 | if (timeout) |
126 | rport->dev_loss_tmo = timeout; |
127 | else |
128 | rport->dev_loss_tmo = 1; |
129 | } |
130 | |
131 | static void fnic_get_host_speed(struct Scsi_Host *shost); |
132 | static struct scsi_transport_template *fnic_fc_transport; |
133 | static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *); |
134 | static void fnic_reset_host_stats(struct Scsi_Host *); |
135 | |
136 | static struct fc_function_template fnic_fc_functions = { |
137 | |
138 | .show_host_node_name = 1, |
139 | .show_host_port_name = 1, |
140 | .show_host_supported_classes = 1, |
141 | .show_host_supported_fc4s = 1, |
142 | .show_host_active_fc4s = 1, |
143 | .show_host_maxframe_size = 1, |
144 | .show_host_port_id = 1, |
145 | .show_host_supported_speeds = 1, |
146 | .get_host_speed = fnic_get_host_speed, |
147 | .show_host_speed = 1, |
148 | .show_host_port_type = 1, |
149 | .get_host_port_state = fc_get_host_port_state, |
150 | .show_host_port_state = 1, |
151 | .show_host_symbolic_name = 1, |
152 | .show_rport_maxframe_size = 1, |
153 | .show_rport_supported_classes = 1, |
154 | .show_host_fabric_name = 1, |
155 | .show_starget_node_name = 1, |
156 | .show_starget_port_name = 1, |
157 | .show_starget_port_id = 1, |
158 | .show_rport_dev_loss_tmo = 1, |
159 | .set_rport_dev_loss_tmo = fnic_set_rport_dev_loss_tmo, |
160 | .issue_fc_host_lip = fnic_reset, |
161 | .get_fc_host_stats = fnic_get_stats, |
162 | .reset_fc_host_stats = fnic_reset_host_stats, |
163 | .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), |
164 | .terminate_rport_io = fnic_terminate_rport_io, |
165 | .bsg_request = fc_lport_bsg_request, |
166 | }; |
167 | |
168 | static void fnic_get_host_speed(struct Scsi_Host *shost) |
169 | { |
170 | struct fc_lport *lp = shost_priv(shost); |
171 | struct fnic *fnic = lport_priv(lport: lp); |
172 | u32 port_speed = vnic_dev_port_speed(vdev: fnic->vdev); |
173 | |
174 | /* Add in other values as they get defined in fw */ |
175 | switch (port_speed) { |
176 | case DCEM_PORTSPEED_10G: |
177 | fc_host_speed(shost) = FC_PORTSPEED_10GBIT; |
178 | break; |
179 | case DCEM_PORTSPEED_20G: |
180 | fc_host_speed(shost) = FC_PORTSPEED_20GBIT; |
181 | break; |
182 | case DCEM_PORTSPEED_25G: |
183 | fc_host_speed(shost) = FC_PORTSPEED_25GBIT; |
184 | break; |
185 | case DCEM_PORTSPEED_40G: |
186 | case DCEM_PORTSPEED_4x10G: |
187 | fc_host_speed(shost) = FC_PORTSPEED_40GBIT; |
188 | break; |
189 | case DCEM_PORTSPEED_100G: |
190 | fc_host_speed(shost) = FC_PORTSPEED_100GBIT; |
191 | break; |
192 | default: |
193 | fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; |
194 | break; |
195 | } |
196 | } |
197 | |
198 | static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *host) |
199 | { |
200 | int ret; |
201 | struct fc_lport *lp = shost_priv(shost: host); |
202 | struct fnic *fnic = lport_priv(lport: lp); |
203 | struct fc_host_statistics *stats = &lp->host_stats; |
204 | struct vnic_stats *vs; |
205 | unsigned long flags; |
206 | |
207 | if (time_before(jiffies, fnic->stats_time + HZ / FNIC_STATS_RATE_LIMIT)) |
208 | return stats; |
209 | fnic->stats_time = jiffies; |
210 | |
211 | spin_lock_irqsave(&fnic->fnic_lock, flags); |
212 | ret = vnic_dev_stats_dump(vdev: fnic->vdev, stats: &fnic->stats); |
213 | spin_unlock_irqrestore(lock: &fnic->fnic_lock, flags); |
214 | |
215 | if (ret) { |
216 | FNIC_MAIN_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, |
217 | "fnic: Get vnic stats failed" |
218 | " 0x%x" , ret); |
219 | return stats; |
220 | } |
221 | vs = fnic->stats; |
222 | stats->tx_frames = vs->tx.tx_unicast_frames_ok; |
223 | stats->tx_words = vs->tx.tx_unicast_bytes_ok / 4; |
224 | stats->rx_frames = vs->rx.rx_unicast_frames_ok; |
225 | stats->rx_words = vs->rx.rx_unicast_bytes_ok / 4; |
226 | stats->error_frames = vs->tx.tx_errors + vs->rx.rx_errors; |
227 | stats->dumped_frames = vs->tx.tx_drops + vs->rx.rx_drop; |
228 | stats->invalid_crc_count = vs->rx.rx_crc_errors; |
229 | stats->seconds_since_last_reset = |
230 | (jiffies - fnic->stats_reset_time) / HZ; |
231 | stats->fcp_input_megabytes = div_u64(dividend: fnic->fcp_input_bytes, divisor: 1000000); |
232 | stats->fcp_output_megabytes = div_u64(dividend: fnic->fcp_output_bytes, divisor: 1000000); |
233 | |
234 | return stats; |
235 | } |
236 | |
237 | /* |
238 | * fnic_dump_fchost_stats |
239 | * note : dumps fc_statistics into system logs |
240 | */ |
241 | void fnic_dump_fchost_stats(struct Scsi_Host *host, |
242 | struct fc_host_statistics *stats) |
243 | { |
244 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
245 | "fnic: seconds since last reset = %llu\n" , |
246 | stats->seconds_since_last_reset); |
247 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
248 | "fnic: tx frames = %llu\n" , |
249 | stats->tx_frames); |
250 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
251 | "fnic: tx words = %llu\n" , |
252 | stats->tx_words); |
253 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
254 | "fnic: rx frames = %llu\n" , |
255 | stats->rx_frames); |
256 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
257 | "fnic: rx words = %llu\n" , |
258 | stats->rx_words); |
259 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
260 | "fnic: lip count = %llu\n" , |
261 | stats->lip_count); |
262 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
263 | "fnic: nos count = %llu\n" , |
264 | stats->nos_count); |
265 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
266 | "fnic: error frames = %llu\n" , |
267 | stats->error_frames); |
268 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
269 | "fnic: dumped frames = %llu\n" , |
270 | stats->dumped_frames); |
271 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
272 | "fnic: link failure count = %llu\n" , |
273 | stats->link_failure_count); |
274 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
275 | "fnic: loss of sync count = %llu\n" , |
276 | stats->loss_of_sync_count); |
277 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
278 | "fnic: loss of signal count = %llu\n" , |
279 | stats->loss_of_signal_count); |
280 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
281 | "fnic: prim seq protocol err count = %llu\n" , |
282 | stats->prim_seq_protocol_err_count); |
283 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
284 | "fnic: invalid tx word count= %llu\n" , |
285 | stats->invalid_tx_word_count); |
286 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
287 | "fnic: invalid crc count = %llu\n" , |
288 | stats->invalid_crc_count); |
289 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
290 | "fnic: fcp input requests = %llu\n" , |
291 | stats->fcp_input_requests); |
292 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
293 | "fnic: fcp output requests = %llu\n" , |
294 | stats->fcp_output_requests); |
295 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
296 | "fnic: fcp control requests = %llu\n" , |
297 | stats->fcp_control_requests); |
298 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
299 | "fnic: fcp input megabytes = %llu\n" , |
300 | stats->fcp_input_megabytes); |
301 | FNIC_MAIN_NOTE(KERN_NOTICE, host, |
302 | "fnic: fcp output megabytes = %llu\n" , |
303 | stats->fcp_output_megabytes); |
304 | return; |
305 | } |
306 | |
307 | /* |
308 | * fnic_reset_host_stats : clears host stats |
309 | * note : called when reset_statistics set under sysfs dir |
310 | */ |
311 | static void fnic_reset_host_stats(struct Scsi_Host *host) |
312 | { |
313 | int ret; |
314 | struct fc_lport *lp = shost_priv(shost: host); |
315 | struct fnic *fnic = lport_priv(lport: lp); |
316 | struct fc_host_statistics *stats; |
317 | unsigned long flags; |
318 | |
319 | /* dump current stats, before clearing them */ |
320 | stats = fnic_get_stats(host); |
321 | fnic_dump_fchost_stats(host, stats); |
322 | |
323 | spin_lock_irqsave(&fnic->fnic_lock, flags); |
324 | ret = vnic_dev_stats_clear(vdev: fnic->vdev); |
325 | spin_unlock_irqrestore(lock: &fnic->fnic_lock, flags); |
326 | |
327 | if (ret) { |
328 | FNIC_MAIN_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, |
329 | "fnic: Reset vnic stats failed" |
330 | " 0x%x" , ret); |
331 | return; |
332 | } |
333 | fnic->stats_reset_time = jiffies; |
334 | memset(stats, 0, sizeof(*stats)); |
335 | |
336 | return; |
337 | } |
338 | |
339 | void fnic_log_q_error(struct fnic *fnic) |
340 | { |
341 | unsigned int i; |
342 | u32 error_status; |
343 | |
344 | for (i = 0; i < fnic->raw_wq_count; i++) { |
345 | error_status = ioread32(&fnic->wq[i].ctrl->error_status); |
346 | if (error_status) |
347 | shost_printk(KERN_ERR, fnic->lport->host, |
348 | "WQ[%d] error_status" |
349 | " %d\n" , i, error_status); |
350 | } |
351 | |
352 | for (i = 0; i < fnic->rq_count; i++) { |
353 | error_status = ioread32(&fnic->rq[i].ctrl->error_status); |
354 | if (error_status) |
355 | shost_printk(KERN_ERR, fnic->lport->host, |
356 | "RQ[%d] error_status" |
357 | " %d\n" , i, error_status); |
358 | } |
359 | |
360 | for (i = 0; i < fnic->wq_copy_count; i++) { |
361 | error_status = ioread32(&fnic->hw_copy_wq[i].ctrl->error_status); |
362 | if (error_status) |
363 | shost_printk(KERN_ERR, fnic->lport->host, |
364 | "CWQ[%d] error_status" |
365 | " %d\n" , i, error_status); |
366 | } |
367 | } |
368 | |
369 | void fnic_handle_link_event(struct fnic *fnic) |
370 | { |
371 | unsigned long flags; |
372 | |
373 | spin_lock_irqsave(&fnic->fnic_lock, flags); |
374 | if (fnic->stop_rx_link_events) { |
375 | spin_unlock_irqrestore(lock: &fnic->fnic_lock, flags); |
376 | return; |
377 | } |
378 | spin_unlock_irqrestore(lock: &fnic->fnic_lock, flags); |
379 | |
380 | queue_work(wq: fnic_event_queue, work: &fnic->link_work); |
381 | |
382 | } |
383 | |
384 | static int fnic_notify_set(struct fnic *fnic) |
385 | { |
386 | int err; |
387 | |
388 | switch (vnic_dev_get_intr_mode(vdev: fnic->vdev)) { |
389 | case VNIC_DEV_INTR_MODE_INTX: |
390 | err = vnic_dev_notify_set(vdev: fnic->vdev, intr: FNIC_INTX_NOTIFY); |
391 | break; |
392 | case VNIC_DEV_INTR_MODE_MSI: |
393 | err = vnic_dev_notify_set(vdev: fnic->vdev, intr: -1); |
394 | break; |
395 | case VNIC_DEV_INTR_MODE_MSIX: |
396 | err = vnic_dev_notify_set(vdev: fnic->vdev, intr: fnic->wq_copy_count + fnic->copy_wq_base); |
397 | break; |
398 | default: |
399 | shost_printk(KERN_ERR, fnic->lport->host, |
400 | "Interrupt mode should be set up" |
401 | " before devcmd notify set %d\n" , |
402 | vnic_dev_get_intr_mode(fnic->vdev)); |
403 | err = -1; |
404 | break; |
405 | } |
406 | |
407 | return err; |
408 | } |
409 | |
410 | static void fnic_notify_timer(struct timer_list *t) |
411 | { |
412 | struct fnic *fnic = from_timer(fnic, t, notify_timer); |
413 | |
414 | fnic_handle_link_event(fnic); |
415 | mod_timer(timer: &fnic->notify_timer, |
416 | expires: round_jiffies(j: jiffies + FNIC_NOTIFY_TIMER_PERIOD)); |
417 | } |
418 | |
419 | static void fnic_fip_notify_timer(struct timer_list *t) |
420 | { |
421 | struct fnic *fnic = from_timer(fnic, t, fip_timer); |
422 | |
423 | fnic_handle_fip_timer(fnic); |
424 | } |
425 | |
426 | static void fnic_notify_timer_start(struct fnic *fnic) |
427 | { |
428 | switch (vnic_dev_get_intr_mode(vdev: fnic->vdev)) { |
429 | case VNIC_DEV_INTR_MODE_MSI: |
430 | /* |
431 | * Schedule first timeout immediately. The driver is |
432 | * initiatialized and ready to look for link up notification |
433 | */ |
434 | mod_timer(timer: &fnic->notify_timer, expires: jiffies); |
435 | break; |
436 | default: |
437 | /* Using intr for notification for INTx/MSI-X */ |
438 | break; |
439 | } |
440 | } |
441 | |
442 | static int fnic_dev_wait(struct vnic_dev *vdev, |
443 | int (*start)(struct vnic_dev *, int), |
444 | int (*finished)(struct vnic_dev *, int *), |
445 | int arg) |
446 | { |
447 | unsigned long time; |
448 | int done; |
449 | int err; |
450 | int count; |
451 | |
452 | count = 0; |
453 | |
454 | err = start(vdev, arg); |
455 | if (err) |
456 | return err; |
457 | |
458 | /* Wait for func to complete. |
459 | * Sometime schedule_timeout_uninterruptible take long time |
460 | * to wake up so we do not retry as we are only waiting for |
461 | * 2 seconds in while loop. By adding count, we make sure |
462 | * we try atleast three times before returning -ETIMEDOUT |
463 | */ |
464 | time = jiffies + (HZ * 2); |
465 | do { |
466 | err = finished(vdev, &done); |
467 | count++; |
468 | if (err) |
469 | return err; |
470 | if (done) |
471 | return 0; |
472 | schedule_timeout_uninterruptible(HZ / 10); |
473 | } while (time_after(time, jiffies) || (count < 3)); |
474 | |
475 | return -ETIMEDOUT; |
476 | } |
477 | |
478 | static int fnic_cleanup(struct fnic *fnic) |
479 | { |
480 | unsigned int i; |
481 | int err; |
482 | int raw_wq_rq_counts; |
483 | |
484 | vnic_dev_disable(vdev: fnic->vdev); |
485 | for (i = 0; i < fnic->intr_count; i++) |
486 | vnic_intr_mask(intr: &fnic->intr[i]); |
487 | |
488 | for (i = 0; i < fnic->rq_count; i++) { |
489 | err = vnic_rq_disable(rq: &fnic->rq[i]); |
490 | if (err) |
491 | return err; |
492 | } |
493 | for (i = 0; i < fnic->raw_wq_count; i++) { |
494 | err = vnic_wq_disable(wq: &fnic->wq[i]); |
495 | if (err) |
496 | return err; |
497 | } |
498 | for (i = 0; i < fnic->wq_copy_count; i++) { |
499 | err = vnic_wq_copy_disable(wq: &fnic->hw_copy_wq[i]); |
500 | if (err) |
501 | return err; |
502 | raw_wq_rq_counts = fnic->raw_wq_count + fnic->rq_count; |
503 | fnic_wq_copy_cmpl_handler(fnic, copy_work_to_do: -1, cq_index: i + raw_wq_rq_counts); |
504 | } |
505 | |
506 | /* Clean up completed IOs and FCS frames */ |
507 | fnic_wq_cmpl_handler(fnic, -1); |
508 | fnic_rq_cmpl_handler(fnic, -1); |
509 | |
510 | /* Clean up the IOs and FCS frames that have not completed */ |
511 | for (i = 0; i < fnic->raw_wq_count; i++) |
512 | vnic_wq_clean(wq: &fnic->wq[i], buf_clean: fnic_free_wq_buf); |
513 | for (i = 0; i < fnic->rq_count; i++) |
514 | vnic_rq_clean(rq: &fnic->rq[i], buf_clean: fnic_free_rq_buf); |
515 | for (i = 0; i < fnic->wq_copy_count; i++) |
516 | vnic_wq_copy_clean(wq: &fnic->hw_copy_wq[i], |
517 | q_clean: fnic_wq_copy_cleanup_handler); |
518 | |
519 | for (i = 0; i < fnic->cq_count; i++) |
520 | vnic_cq_clean(cq: &fnic->cq[i]); |
521 | for (i = 0; i < fnic->intr_count; i++) |
522 | vnic_intr_clean(intr: &fnic->intr[i]); |
523 | |
524 | mempool_destroy(pool: fnic->io_req_pool); |
525 | for (i = 0; i < FNIC_SGL_NUM_CACHES; i++) |
526 | mempool_destroy(pool: fnic->io_sgl_pool[i]); |
527 | |
528 | return 0; |
529 | } |
530 | |
531 | static void fnic_iounmap(struct fnic *fnic) |
532 | { |
533 | if (fnic->bar0.vaddr) |
534 | iounmap(addr: fnic->bar0.vaddr); |
535 | } |
536 | |
537 | /** |
538 | * fnic_get_mac() - get assigned data MAC address for FIP code. |
539 | * @lport: local port. |
540 | */ |
541 | static u8 *fnic_get_mac(struct fc_lport *lport) |
542 | { |
543 | struct fnic *fnic = lport_priv(lport); |
544 | |
545 | return fnic->data_src_addr; |
546 | } |
547 | |
548 | static void fnic_set_vlan(struct fnic *fnic, u16 vlan_id) |
549 | { |
550 | vnic_dev_set_default_vlan(vdev: fnic->vdev, new_default_vlan: vlan_id); |
551 | } |
552 | |
553 | static int fnic_scsi_drv_init(struct fnic *fnic) |
554 | { |
555 | struct Scsi_Host *host = fnic->lport->host; |
556 | |
557 | /* Configure maximum outstanding IO reqs*/ |
558 | if (fnic->config.io_throttle_count != FNIC_UCSM_DFLT_THROTTLE_CNT_BLD) |
559 | host->can_queue = min_t(u32, FNIC_MAX_IO_REQ, |
560 | max_t(u32, FNIC_MIN_IO_REQ, |
561 | fnic->config.io_throttle_count)); |
562 | |
563 | fnic->fnic_max_tag_id = host->can_queue; |
564 | host->max_lun = fnic->config.luns_per_tgt; |
565 | host->max_id = FNIC_MAX_FCP_TARGET; |
566 | host->max_cmd_len = FCOE_MAX_CMD_LEN; |
567 | |
568 | host->nr_hw_queues = fnic->wq_copy_count; |
569 | |
570 | shost_printk(KERN_INFO, host, |
571 | "fnic: can_queue: %d max_lun: %llu" , |
572 | host->can_queue, host->max_lun); |
573 | |
574 | shost_printk(KERN_INFO, host, |
575 | "fnic: max_id: %d max_cmd_len: %d nr_hw_queues: %d" , |
576 | host->max_id, host->max_cmd_len, host->nr_hw_queues); |
577 | |
578 | return 0; |
579 | } |
580 | |
581 | void fnic_mq_map_queues_cpus(struct Scsi_Host *host) |
582 | { |
583 | struct fc_lport *lp = shost_priv(shost: host); |
584 | struct fnic *fnic = lport_priv(lport: lp); |
585 | struct pci_dev *l_pdev = fnic->pdev; |
586 | int intr_mode = fnic->config.intr_mode; |
587 | struct blk_mq_queue_map *qmap = &host->tag_set.map[HCTX_TYPE_DEFAULT]; |
588 | |
589 | if (intr_mode == VNIC_DEV_INTR_MODE_MSI || intr_mode == VNIC_DEV_INTR_MODE_INTX) { |
590 | FNIC_MAIN_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, |
591 | "intr_mode is not msix\n" ); |
592 | return; |
593 | } |
594 | |
595 | FNIC_MAIN_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, |
596 | "qmap->nr_queues: %d\n" , qmap->nr_queues); |
597 | |
598 | if (l_pdev == NULL) { |
599 | FNIC_MAIN_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, |
600 | "l_pdev is null\n" ); |
601 | return; |
602 | } |
603 | |
604 | blk_mq_pci_map_queues(qmap, pdev: l_pdev, FNIC_PCI_OFFSET); |
605 | } |
606 | |
607 | static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
608 | { |
609 | struct Scsi_Host *host; |
610 | struct fc_lport *lp; |
611 | struct fnic *fnic; |
612 | mempool_t *pool; |
613 | int err = 0; |
614 | int fnic_id = 0; |
615 | int i; |
616 | unsigned long flags; |
617 | int hwq; |
618 | |
619 | /* |
620 | * Allocate SCSI Host and set up association between host, |
621 | * local port, and fnic |
622 | */ |
623 | lp = libfc_host_alloc(sht: &fnic_host_template, priv_size: sizeof(struct fnic)); |
624 | if (!lp) { |
625 | printk(KERN_ERR PFX "Unable to alloc libfc local port\n" ); |
626 | err = -ENOMEM; |
627 | goto err_out; |
628 | } |
629 | |
630 | host = lp->host; |
631 | fnic = lport_priv(lport: lp); |
632 | |
633 | fnic_id = ida_alloc(ida: &fnic_ida, GFP_KERNEL); |
634 | if (fnic_id < 0) { |
635 | pr_err("Unable to alloc fnic ID\n" ); |
636 | err = fnic_id; |
637 | goto err_out_ida_alloc; |
638 | } |
639 | fnic->lport = lp; |
640 | fnic->ctlr.lp = lp; |
641 | fnic->link_events = 0; |
642 | fnic->pdev = pdev; |
643 | |
644 | snprintf(buf: fnic->name, size: sizeof(fnic->name) - 1, fmt: "%s%d" , DRV_NAME, |
645 | host->host_no); |
646 | |
647 | host->transportt = fnic_fc_transport; |
648 | fnic->fnic_num = fnic_id; |
649 | fnic_stats_debugfs_init(fnic); |
650 | |
651 | err = pci_enable_device(dev: pdev); |
652 | if (err) { |
653 | shost_printk(KERN_ERR, fnic->lport->host, |
654 | "Cannot enable PCI device, aborting.\n" ); |
655 | goto err_out_free_hba; |
656 | } |
657 | |
658 | err = pci_request_regions(pdev, DRV_NAME); |
659 | if (err) { |
660 | shost_printk(KERN_ERR, fnic->lport->host, |
661 | "Cannot enable PCI resources, aborting\n" ); |
662 | goto err_out_disable_device; |
663 | } |
664 | |
665 | pci_set_master(dev: pdev); |
666 | |
667 | /* Query PCI controller on system for DMA addressing |
668 | * limitation for the device. Try 47-bit first, and |
669 | * fail to 32-bit. Cisco VIC supports 47 bits only. |
670 | */ |
671 | err = dma_set_mask_and_coherent(dev: &pdev->dev, DMA_BIT_MASK(47)); |
672 | if (err) { |
673 | err = dma_set_mask_and_coherent(dev: &pdev->dev, DMA_BIT_MASK(32)); |
674 | if (err) { |
675 | shost_printk(KERN_ERR, fnic->lport->host, |
676 | "No usable DMA configuration " |
677 | "aborting\n" ); |
678 | goto err_out_release_regions; |
679 | } |
680 | } |
681 | |
682 | /* Map vNIC resources from BAR0 */ |
683 | if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { |
684 | shost_printk(KERN_ERR, fnic->lport->host, |
685 | "BAR0 not memory-map'able, aborting.\n" ); |
686 | err = -ENODEV; |
687 | goto err_out_release_regions; |
688 | } |
689 | |
690 | fnic->bar0.vaddr = pci_iomap(dev: pdev, bar: 0, max: 0); |
691 | fnic->bar0.bus_addr = pci_resource_start(pdev, 0); |
692 | fnic->bar0.len = pci_resource_len(pdev, 0); |
693 | |
694 | if (!fnic->bar0.vaddr) { |
695 | shost_printk(KERN_ERR, fnic->lport->host, |
696 | "Cannot memory-map BAR0 res hdr, " |
697 | "aborting.\n" ); |
698 | err = -ENODEV; |
699 | goto err_out_release_regions; |
700 | } |
701 | |
702 | fnic->vdev = vnic_dev_register(NULL, priv: fnic, pdev, bar: &fnic->bar0); |
703 | if (!fnic->vdev) { |
704 | shost_printk(KERN_ERR, fnic->lport->host, |
705 | "vNIC registration failed, " |
706 | "aborting.\n" ); |
707 | err = -ENODEV; |
708 | goto err_out_iounmap; |
709 | } |
710 | |
711 | err = vnic_dev_cmd_init(vdev: fnic->vdev); |
712 | if (err) { |
713 | shost_printk(KERN_ERR, fnic->lport->host, |
714 | "vnic_dev_cmd_init() returns %d, aborting\n" , |
715 | err); |
716 | goto err_out_vnic_unregister; |
717 | } |
718 | |
719 | err = fnic_dev_wait(vdev: fnic->vdev, vnic_dev_open, |
720 | vnic_dev_open_done, CMD_OPENF_RQ_ENABLE_THEN_POST); |
721 | if (err) { |
722 | shost_printk(KERN_ERR, fnic->lport->host, |
723 | "vNIC dev open failed, aborting.\n" ); |
724 | goto err_out_dev_cmd_deinit; |
725 | } |
726 | |
727 | err = vnic_dev_init(vdev: fnic->vdev, arg: 0); |
728 | if (err) { |
729 | shost_printk(KERN_ERR, fnic->lport->host, |
730 | "vNIC dev init failed, aborting.\n" ); |
731 | goto err_out_dev_close; |
732 | } |
733 | |
734 | err = vnic_dev_mac_addr(vdev: fnic->vdev, mac_addr: fnic->ctlr.ctl_src_addr); |
735 | if (err) { |
736 | shost_printk(KERN_ERR, fnic->lport->host, |
737 | "vNIC get MAC addr failed \n" ); |
738 | goto err_out_dev_close; |
739 | } |
740 | /* set data_src for point-to-point mode and to keep it non-zero */ |
741 | memcpy(fnic->data_src_addr, fnic->ctlr.ctl_src_addr, ETH_ALEN); |
742 | |
743 | /* Get vNIC configuration */ |
744 | err = fnic_get_vnic_config(fnic); |
745 | if (err) { |
746 | shost_printk(KERN_ERR, fnic->lport->host, |
747 | "Get vNIC configuration failed, " |
748 | "aborting.\n" ); |
749 | goto err_out_dev_close; |
750 | } |
751 | |
752 | /* Setup PCI resources */ |
753 | pci_set_drvdata(pdev, data: fnic); |
754 | |
755 | fnic_get_res_counts(fnic); |
756 | |
757 | err = fnic_set_intr_mode(fnic); |
758 | if (err) { |
759 | shost_printk(KERN_ERR, fnic->lport->host, |
760 | "Failed to set intr mode, " |
761 | "aborting.\n" ); |
762 | goto err_out_dev_close; |
763 | } |
764 | |
765 | err = fnic_alloc_vnic_resources(fnic); |
766 | if (err) { |
767 | shost_printk(KERN_ERR, fnic->lport->host, |
768 | "Failed to alloc vNIC resources, " |
769 | "aborting.\n" ); |
770 | goto err_out_clear_intr; |
771 | } |
772 | |
773 | fnic_scsi_drv_init(fnic); |
774 | |
775 | for (hwq = 0; hwq < fnic->wq_copy_count; hwq++) { |
776 | fnic->sw_copy_wq[hwq].ioreq_table_size = fnic->fnic_max_tag_id; |
777 | fnic->sw_copy_wq[hwq].io_req_table = |
778 | kzalloc(size: (fnic->sw_copy_wq[hwq].ioreq_table_size + 1) * |
779 | sizeof(struct fnic_io_req *), GFP_KERNEL); |
780 | } |
781 | shost_printk(KERN_INFO, fnic->lport->host, "fnic copy wqs: %d, Q0 ioreq table size: %d\n" , |
782 | fnic->wq_copy_count, fnic->sw_copy_wq[0].ioreq_table_size); |
783 | |
784 | /* initialize all fnic locks */ |
785 | spin_lock_init(&fnic->fnic_lock); |
786 | |
787 | for (i = 0; i < FNIC_WQ_MAX; i++) |
788 | spin_lock_init(&fnic->wq_lock[i]); |
789 | |
790 | for (i = 0; i < FNIC_WQ_COPY_MAX; i++) { |
791 | spin_lock_init(&fnic->wq_copy_lock[i]); |
792 | fnic->wq_copy_desc_low[i] = DESC_CLEAN_LOW_WATERMARK; |
793 | fnic->fw_ack_recd[i] = 0; |
794 | fnic->fw_ack_index[i] = -1; |
795 | } |
796 | |
797 | err = -ENOMEM; |
798 | fnic->io_req_pool = mempool_create_slab_pool(min_nr: 2, kc: fnic_io_req_cache); |
799 | if (!fnic->io_req_pool) |
800 | goto err_out_free_resources; |
801 | |
802 | pool = mempool_create_slab_pool(min_nr: 2, kc: fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); |
803 | if (!pool) |
804 | goto err_out_free_ioreq_pool; |
805 | fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT] = pool; |
806 | |
807 | pool = mempool_create_slab_pool(min_nr: 2, kc: fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); |
808 | if (!pool) |
809 | goto err_out_free_dflt_pool; |
810 | fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX] = pool; |
811 | |
812 | /* setup vlan config, hw inserts vlan header */ |
813 | fnic->vlan_hw_insert = 1; |
814 | fnic->vlan_id = 0; |
815 | |
816 | /* Initialize the FIP fcoe_ctrl struct */ |
817 | fnic->ctlr.send = fnic_eth_send; |
818 | fnic->ctlr.update_mac = fnic_update_mac; |
819 | fnic->ctlr.get_src_addr = fnic_get_mac; |
820 | if (fnic->config.flags & VFCF_FIP_CAPABLE) { |
821 | shost_printk(KERN_INFO, fnic->lport->host, |
822 | "firmware supports FIP\n" ); |
823 | /* enable directed and multicast */ |
824 | vnic_dev_packet_filter(vdev: fnic->vdev, directed: 1, multicast: 1, broadcast: 0, promisc: 0, allmulti: 0); |
825 | vnic_dev_add_addr(vdev: fnic->vdev, FIP_ALL_ENODE_MACS); |
826 | vnic_dev_add_addr(vdev: fnic->vdev, addr: fnic->ctlr.ctl_src_addr); |
827 | fnic->set_vlan = fnic_set_vlan; |
828 | fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_AUTO); |
829 | timer_setup(&fnic->fip_timer, fnic_fip_notify_timer, 0); |
830 | spin_lock_init(&fnic->vlans_lock); |
831 | INIT_WORK(&fnic->fip_frame_work, fnic_handle_fip_frame); |
832 | INIT_WORK(&fnic->event_work, fnic_handle_event); |
833 | INIT_WORK(&fnic->flush_work, fnic_flush_tx); |
834 | skb_queue_head_init(list: &fnic->fip_frame_queue); |
835 | INIT_LIST_HEAD(list: &fnic->evlist); |
836 | INIT_LIST_HEAD(list: &fnic->vlans); |
837 | } else { |
838 | shost_printk(KERN_INFO, fnic->lport->host, |
839 | "firmware uses non-FIP mode\n" ); |
840 | fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_NON_FIP); |
841 | fnic->ctlr.state = FIP_ST_NON_FIP; |
842 | } |
843 | fnic->state = FNIC_IN_FC_MODE; |
844 | |
845 | atomic_set(v: &fnic->in_flight, i: 0); |
846 | fnic->state_flags = FNIC_FLAGS_NONE; |
847 | |
848 | /* Enable hardware stripping of vlan header on ingress */ |
849 | fnic_set_nic_config(fnic, rss_default_cpu: 0, rss_hash_type: 0, rss_hash_bits: 0, rss_base_cpu: 0, rss_enable: 0, tso_ipid_split_en: 0, ig_vlan_strip_en: 1); |
850 | |
851 | /* Setup notification buffer area */ |
852 | err = fnic_notify_set(fnic); |
853 | if (err) { |
854 | shost_printk(KERN_ERR, fnic->lport->host, |
855 | "Failed to alloc notify buffer, aborting.\n" ); |
856 | goto err_out_free_max_pool; |
857 | } |
858 | |
859 | /* Setup notify timer when using MSI interrupts */ |
860 | if (vnic_dev_get_intr_mode(vdev: fnic->vdev) == VNIC_DEV_INTR_MODE_MSI) |
861 | timer_setup(&fnic->notify_timer, fnic_notify_timer, 0); |
862 | |
863 | /* allocate RQ buffers and post them to RQ*/ |
864 | for (i = 0; i < fnic->rq_count; i++) { |
865 | err = vnic_rq_fill(rq: &fnic->rq[i], buf_fill: fnic_alloc_rq_frame); |
866 | if (err) { |
867 | shost_printk(KERN_ERR, fnic->lport->host, |
868 | "fnic_alloc_rq_frame can't alloc " |
869 | "frame\n" ); |
870 | goto err_out_rq_buf; |
871 | } |
872 | } |
873 | |
874 | /* Enable all queues */ |
875 | for (i = 0; i < fnic->raw_wq_count; i++) |
876 | vnic_wq_enable(wq: &fnic->wq[i]); |
877 | for (i = 0; i < fnic->rq_count; i++) { |
878 | if (!ioread32(&fnic->rq[i].ctrl->enable)) |
879 | vnic_rq_enable(rq: &fnic->rq[i]); |
880 | } |
881 | for (i = 0; i < fnic->wq_copy_count; i++) |
882 | vnic_wq_copy_enable(wq: &fnic->hw_copy_wq[i]); |
883 | |
884 | err = fnic_request_intr(fnic); |
885 | if (err) { |
886 | shost_printk(KERN_ERR, fnic->lport->host, |
887 | "Unable to request irq.\n" ); |
888 | goto err_out_request_intr; |
889 | } |
890 | |
891 | /* |
892 | * Initialization done with PCI system, hardware, firmware. |
893 | * Add host to SCSI |
894 | */ |
895 | err = scsi_add_host(host: lp->host, dev: &pdev->dev); |
896 | if (err) { |
897 | shost_printk(KERN_ERR, fnic->lport->host, |
898 | "fnic: scsi_add_host failed...exiting\n" ); |
899 | goto err_out_scsi_add_host; |
900 | } |
901 | |
902 | |
903 | /* Start local port initiatialization */ |
904 | |
905 | lp->link_up = 0; |
906 | |
907 | lp->max_retry_count = fnic->config.flogi_retries; |
908 | lp->max_rport_retry_count = fnic->config.plogi_retries; |
909 | lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | |
910 | FCP_SPPF_CONF_COMPL); |
911 | if (fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR) |
912 | lp->service_params |= FCP_SPPF_RETRY; |
913 | |
914 | lp->boot_time = jiffies; |
915 | lp->e_d_tov = fnic->config.ed_tov; |
916 | lp->r_a_tov = fnic->config.ra_tov; |
917 | lp->link_supported_speeds = FC_PORTSPEED_10GBIT; |
918 | fc_set_wwnn(lport: lp, wwnn: fnic->config.node_wwn); |
919 | fc_set_wwpn(lport: lp, wwpn: fnic->config.port_wwn); |
920 | |
921 | fcoe_libfc_config(lp, &fnic->ctlr, &fnic_transport_template, init_fcp: 0); |
922 | |
923 | if (!fc_exch_mgr_alloc(lp, class: FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START, |
924 | FCPIO_HOST_EXCH_RANGE_END, NULL)) { |
925 | err = -ENOMEM; |
926 | goto err_out_fc_exch_mgr_alloc; |
927 | } |
928 | |
929 | fc_lport_init_stats(lport: lp); |
930 | fnic->stats_reset_time = jiffies; |
931 | |
932 | fc_lport_config(lp); |
933 | |
934 | if (fc_set_mfs(lp, mfs: fnic->config.maxdatafieldsize + |
935 | sizeof(struct fc_frame_header))) { |
936 | err = -EINVAL; |
937 | goto err_out_free_exch_mgr; |
938 | } |
939 | fc_host_maxframe_size(lp->host) = lp->mfs; |
940 | fc_host_dev_loss_tmo(lp->host) = fnic->config.port_down_timeout / 1000; |
941 | |
942 | sprintf(fc_host_symbolic_name(lp->host), |
943 | DRV_NAME " v" DRV_VERSION " over %s" , fnic->name); |
944 | |
945 | spin_lock_irqsave(&fnic_list_lock, flags); |
946 | list_add_tail(new: &fnic->list, head: &fnic_list); |
947 | spin_unlock_irqrestore(lock: &fnic_list_lock, flags); |
948 | |
949 | INIT_WORK(&fnic->link_work, fnic_handle_link); |
950 | INIT_WORK(&fnic->frame_work, fnic_handle_frame); |
951 | skb_queue_head_init(list: &fnic->frame_queue); |
952 | skb_queue_head_init(list: &fnic->tx_queue); |
953 | |
954 | fc_fabric_login(lp); |
955 | |
956 | vnic_dev_enable(vdev: fnic->vdev); |
957 | |
958 | for (i = 0; i < fnic->intr_count; i++) |
959 | vnic_intr_unmask(intr: &fnic->intr[i]); |
960 | |
961 | fnic_notify_timer_start(fnic); |
962 | |
963 | return 0; |
964 | |
965 | err_out_free_exch_mgr: |
966 | fc_exch_mgr_free(lp); |
967 | err_out_fc_exch_mgr_alloc: |
968 | fc_remove_host(lp->host); |
969 | scsi_remove_host(lp->host); |
970 | err_out_scsi_add_host: |
971 | fnic_free_intr(fnic); |
972 | err_out_request_intr: |
973 | for (i = 0; i < fnic->rq_count; i++) |
974 | vnic_rq_clean(rq: &fnic->rq[i], buf_clean: fnic_free_rq_buf); |
975 | err_out_rq_buf: |
976 | vnic_dev_notify_unset(vdev: fnic->vdev); |
977 | err_out_free_max_pool: |
978 | mempool_destroy(pool: fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX]); |
979 | err_out_free_dflt_pool: |
980 | mempool_destroy(pool: fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT]); |
981 | err_out_free_ioreq_pool: |
982 | mempool_destroy(pool: fnic->io_req_pool); |
983 | err_out_free_resources: |
984 | for (hwq = 0; hwq < fnic->wq_copy_count; hwq++) |
985 | kfree(objp: fnic->sw_copy_wq[hwq].io_req_table); |
986 | fnic_free_vnic_resources(fnic); |
987 | err_out_clear_intr: |
988 | fnic_clear_intr_mode(fnic); |
989 | err_out_dev_close: |
990 | vnic_dev_close(vdev: fnic->vdev); |
991 | err_out_dev_cmd_deinit: |
992 | err_out_vnic_unregister: |
993 | vnic_dev_unregister(vdev: fnic->vdev); |
994 | err_out_iounmap: |
995 | fnic_iounmap(fnic); |
996 | err_out_release_regions: |
997 | pci_release_regions(pdev); |
998 | err_out_disable_device: |
999 | pci_disable_device(dev: pdev); |
1000 | err_out_free_hba: |
1001 | fnic_stats_debugfs_remove(fnic); |
1002 | ida_free(&fnic_ida, id: fnic->fnic_num); |
1003 | err_out_ida_alloc: |
1004 | scsi_host_put(t: lp->host); |
1005 | err_out: |
1006 | return err; |
1007 | } |
1008 | |
1009 | static void fnic_remove(struct pci_dev *pdev) |
1010 | { |
1011 | struct fnic *fnic = pci_get_drvdata(pdev); |
1012 | struct fc_lport *lp = fnic->lport; |
1013 | unsigned long flags; |
1014 | int hwq; |
1015 | |
1016 | /* |
1017 | * Mark state so that the workqueue thread stops forwarding |
1018 | * received frames and link events to the local port. ISR and |
1019 | * other threads that can queue work items will also stop |
1020 | * creating work items on the fnic workqueue |
1021 | */ |
1022 | spin_lock_irqsave(&fnic->fnic_lock, flags); |
1023 | fnic->stop_rx_link_events = 1; |
1024 | spin_unlock_irqrestore(lock: &fnic->fnic_lock, flags); |
1025 | |
1026 | if (vnic_dev_get_intr_mode(vdev: fnic->vdev) == VNIC_DEV_INTR_MODE_MSI) |
1027 | del_timer_sync(timer: &fnic->notify_timer); |
1028 | |
1029 | /* |
1030 | * Flush the fnic event queue. After this call, there should |
1031 | * be no event queued for this fnic device in the workqueue |
1032 | */ |
1033 | flush_workqueue(fnic_event_queue); |
1034 | skb_queue_purge(list: &fnic->frame_queue); |
1035 | skb_queue_purge(list: &fnic->tx_queue); |
1036 | |
1037 | if (fnic->config.flags & VFCF_FIP_CAPABLE) { |
1038 | del_timer_sync(timer: &fnic->fip_timer); |
1039 | skb_queue_purge(list: &fnic->fip_frame_queue); |
1040 | fnic_fcoe_reset_vlans(fnic); |
1041 | fnic_fcoe_evlist_free(fnic); |
1042 | } |
1043 | |
1044 | /* |
1045 | * Log off the fabric. This stops all remote ports, dns port, |
1046 | * logs off the fabric. This flushes all rport, disc, lport work |
1047 | * before returning |
1048 | */ |
1049 | fc_fabric_logoff(fnic->lport); |
1050 | |
1051 | spin_lock_irqsave(&fnic->fnic_lock, flags); |
1052 | fnic->in_remove = 1; |
1053 | spin_unlock_irqrestore(lock: &fnic->fnic_lock, flags); |
1054 | |
1055 | fcoe_ctlr_destroy(&fnic->ctlr); |
1056 | fc_lport_destroy(lp); |
1057 | fnic_stats_debugfs_remove(fnic); |
1058 | |
1059 | /* |
1060 | * This stops the fnic device, masks all interrupts. Completed |
1061 | * CQ entries are drained. Posted WQ/RQ/Copy-WQ entries are |
1062 | * cleaned up |
1063 | */ |
1064 | fnic_cleanup(fnic); |
1065 | |
1066 | BUG_ON(!skb_queue_empty(&fnic->frame_queue)); |
1067 | BUG_ON(!skb_queue_empty(&fnic->tx_queue)); |
1068 | |
1069 | spin_lock_irqsave(&fnic_list_lock, flags); |
1070 | list_del(entry: &fnic->list); |
1071 | spin_unlock_irqrestore(lock: &fnic_list_lock, flags); |
1072 | |
1073 | fc_remove_host(fnic->lport->host); |
1074 | scsi_remove_host(fnic->lport->host); |
1075 | for (hwq = 0; hwq < fnic->wq_copy_count; hwq++) |
1076 | kfree(objp: fnic->sw_copy_wq[hwq].io_req_table); |
1077 | fc_exch_mgr_free(fnic->lport); |
1078 | vnic_dev_notify_unset(vdev: fnic->vdev); |
1079 | fnic_free_intr(fnic); |
1080 | fnic_free_vnic_resources(fnic); |
1081 | fnic_clear_intr_mode(fnic); |
1082 | vnic_dev_close(vdev: fnic->vdev); |
1083 | vnic_dev_unregister(vdev: fnic->vdev); |
1084 | fnic_iounmap(fnic); |
1085 | pci_release_regions(pdev); |
1086 | pci_disable_device(dev: pdev); |
1087 | ida_free(&fnic_ida, id: fnic->fnic_num); |
1088 | scsi_host_put(t: lp->host); |
1089 | } |
1090 | |
1091 | static struct pci_driver fnic_driver = { |
1092 | .name = DRV_NAME, |
1093 | .id_table = fnic_id_table, |
1094 | .probe = fnic_probe, |
1095 | .remove = fnic_remove, |
1096 | }; |
1097 | |
1098 | static int __init fnic_init_module(void) |
1099 | { |
1100 | size_t len; |
1101 | int err = 0; |
1102 | |
1103 | printk(KERN_INFO PFX "%s, ver %s\n" , DRV_DESCRIPTION, DRV_VERSION); |
1104 | |
1105 | /* Create debugfs entries for fnic */ |
1106 | err = fnic_debugfs_init(); |
1107 | if (err < 0) { |
1108 | printk(KERN_ERR PFX "Failed to create fnic directory " |
1109 | "for tracing and stats logging\n" ); |
1110 | fnic_debugfs_terminate(); |
1111 | } |
1112 | |
1113 | /* Allocate memory for trace buffer */ |
1114 | err = fnic_trace_buf_init(); |
1115 | if (err < 0) { |
1116 | printk(KERN_ERR PFX |
1117 | "Trace buffer initialization Failed. " |
1118 | "Fnic Tracing utility is disabled\n" ); |
1119 | fnic_trace_free(); |
1120 | } |
1121 | |
1122 | /* Allocate memory for fc trace buffer */ |
1123 | err = fnic_fc_trace_init(); |
1124 | if (err < 0) { |
1125 | printk(KERN_ERR PFX "FC trace buffer initialization Failed " |
1126 | "FC frame tracing utility is disabled\n" ); |
1127 | fnic_fc_trace_free(); |
1128 | } |
1129 | |
1130 | /* Create a cache for allocation of default size sgls */ |
1131 | len = sizeof(struct fnic_dflt_sgl_list); |
1132 | fnic_sgl_cache[FNIC_SGL_CACHE_DFLT] = kmem_cache_create |
1133 | (name: "fnic_sgl_dflt" , size: len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN, |
1134 | SLAB_HWCACHE_ALIGN, |
1135 | NULL); |
1136 | if (!fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]) { |
1137 | printk(KERN_ERR PFX "failed to create fnic dflt sgl slab\n" ); |
1138 | err = -ENOMEM; |
1139 | goto err_create_fnic_sgl_slab_dflt; |
1140 | } |
1141 | |
1142 | /* Create a cache for allocation of max size sgls*/ |
1143 | len = sizeof(struct fnic_sgl_list); |
1144 | fnic_sgl_cache[FNIC_SGL_CACHE_MAX] = kmem_cache_create |
1145 | (name: "fnic_sgl_max" , size: len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN, |
1146 | SLAB_HWCACHE_ALIGN, |
1147 | NULL); |
1148 | if (!fnic_sgl_cache[FNIC_SGL_CACHE_MAX]) { |
1149 | printk(KERN_ERR PFX "failed to create fnic max sgl slab\n" ); |
1150 | err = -ENOMEM; |
1151 | goto err_create_fnic_sgl_slab_max; |
1152 | } |
1153 | |
1154 | /* Create a cache of io_req structs for use via mempool */ |
1155 | fnic_io_req_cache = kmem_cache_create(name: "fnic_io_req" , |
1156 | size: sizeof(struct fnic_io_req), |
1157 | align: 0, SLAB_HWCACHE_ALIGN, NULL); |
1158 | if (!fnic_io_req_cache) { |
1159 | printk(KERN_ERR PFX "failed to create fnic io_req slab\n" ); |
1160 | err = -ENOMEM; |
1161 | goto err_create_fnic_ioreq_slab; |
1162 | } |
1163 | |
1164 | fnic_event_queue = create_singlethread_workqueue("fnic_event_wq" ); |
1165 | if (!fnic_event_queue) { |
1166 | printk(KERN_ERR PFX "fnic work queue create failed\n" ); |
1167 | err = -ENOMEM; |
1168 | goto err_create_fnic_workq; |
1169 | } |
1170 | |
1171 | fnic_fip_queue = create_singlethread_workqueue("fnic_fip_q" ); |
1172 | if (!fnic_fip_queue) { |
1173 | printk(KERN_ERR PFX "fnic FIP work queue create failed\n" ); |
1174 | err = -ENOMEM; |
1175 | goto err_create_fip_workq; |
1176 | } |
1177 | |
1178 | fnic_fc_transport = fc_attach_transport(&fnic_fc_functions); |
1179 | if (!fnic_fc_transport) { |
1180 | printk(KERN_ERR PFX "fc_attach_transport error\n" ); |
1181 | err = -ENOMEM; |
1182 | goto err_fc_transport; |
1183 | } |
1184 | |
1185 | /* register the driver with PCI system */ |
1186 | err = pci_register_driver(&fnic_driver); |
1187 | if (err < 0) { |
1188 | printk(KERN_ERR PFX "pci register error\n" ); |
1189 | goto err_pci_register; |
1190 | } |
1191 | return err; |
1192 | |
1193 | err_pci_register: |
1194 | fc_release_transport(fnic_fc_transport); |
1195 | err_fc_transport: |
1196 | destroy_workqueue(wq: fnic_fip_queue); |
1197 | err_create_fip_workq: |
1198 | destroy_workqueue(wq: fnic_event_queue); |
1199 | err_create_fnic_workq: |
1200 | kmem_cache_destroy(s: fnic_io_req_cache); |
1201 | err_create_fnic_ioreq_slab: |
1202 | kmem_cache_destroy(s: fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); |
1203 | err_create_fnic_sgl_slab_max: |
1204 | kmem_cache_destroy(s: fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); |
1205 | err_create_fnic_sgl_slab_dflt: |
1206 | fnic_trace_free(); |
1207 | fnic_fc_trace_free(); |
1208 | fnic_debugfs_terminate(); |
1209 | return err; |
1210 | } |
1211 | |
1212 | static void __exit fnic_cleanup_module(void) |
1213 | { |
1214 | pci_unregister_driver(dev: &fnic_driver); |
1215 | destroy_workqueue(wq: fnic_event_queue); |
1216 | if (fnic_fip_queue) |
1217 | destroy_workqueue(wq: fnic_fip_queue); |
1218 | kmem_cache_destroy(s: fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); |
1219 | kmem_cache_destroy(s: fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); |
1220 | kmem_cache_destroy(s: fnic_io_req_cache); |
1221 | fc_release_transport(fnic_fc_transport); |
1222 | fnic_trace_free(); |
1223 | fnic_fc_trace_free(); |
1224 | fnic_debugfs_terminate(); |
1225 | ida_destroy(ida: &fnic_ida); |
1226 | } |
1227 | |
1228 | module_init(fnic_init_module); |
1229 | module_exit(fnic_cleanup_module); |
1230 | |