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