1e6550b3eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25df6d737SAbhijeet Joglekar /*
35df6d737SAbhijeet Joglekar * Copyright 2008 Cisco Systems, Inc. All rights reserved.
45df6d737SAbhijeet Joglekar * Copyright 2007 Nuova Systems, Inc. All rights reserved.
55df6d737SAbhijeet Joglekar */
65df6d737SAbhijeet Joglekar #include <linux/module.h>
75df6d737SAbhijeet Joglekar #include <linux/mempool.h>
85df6d737SAbhijeet Joglekar #include <linux/string.h>
95a0e3ad6STejun Heo #include <linux/slab.h>
105df6d737SAbhijeet Joglekar #include <linux/errno.h>
115df6d737SAbhijeet Joglekar #include <linux/init.h>
125df6d737SAbhijeet Joglekar #include <linux/pci.h>
135df6d737SAbhijeet Joglekar #include <linux/skbuff.h>
145df6d737SAbhijeet Joglekar #include <linux/interrupt.h>
1552f6e196SKaran Tilak Kumar #include <linux/irq.h>
165df6d737SAbhijeet Joglekar #include <linux/spinlock.h>
175df6d737SAbhijeet Joglekar #include <linux/workqueue.h>
1878112e55SJoe Eykholt #include <linux/if_ether.h>
1952f6e196SKaran Tilak Kumar #include <linux/blk-mq-pci.h>
2078112e55SJoe Eykholt #include <scsi/fc/fc_fip.h>
215df6d737SAbhijeet Joglekar #include <scsi/scsi_host.h>
225df6d737SAbhijeet Joglekar #include <scsi/scsi_transport.h>
235df6d737SAbhijeet Joglekar #include <scsi/scsi_transport_fc.h>
245df6d737SAbhijeet Joglekar #include <scsi/scsi_tcq.h>
255df6d737SAbhijeet Joglekar #include <scsi/libfc.h>
265df6d737SAbhijeet Joglekar #include <scsi/fc_frame.h>
275df6d737SAbhijeet Joglekar
285df6d737SAbhijeet Joglekar #include "vnic_dev.h"
295df6d737SAbhijeet Joglekar #include "vnic_intr.h"
305df6d737SAbhijeet Joglekar #include "vnic_stats.h"
315df6d737SAbhijeet Joglekar #include "fnic_io.h"
32d3c995f1SHiral Patel #include "fnic_fip.h"
335df6d737SAbhijeet Joglekar #include "fnic.h"
345df6d737SAbhijeet Joglekar
355df6d737SAbhijeet Joglekar #define PCI_DEVICE_ID_CISCO_FNIC 0x0045
365df6d737SAbhijeet Joglekar
375df6d737SAbhijeet Joglekar /* Timer to poll notification area for events. Used for MSI interrupts */
385df6d737SAbhijeet Joglekar #define FNIC_NOTIFY_TIMER_PERIOD (2 * HZ)
395df6d737SAbhijeet Joglekar
405df6d737SAbhijeet Joglekar static struct kmem_cache *fnic_sgl_cache[FNIC_SGL_NUM_CACHES];
415df6d737SAbhijeet Joglekar static struct kmem_cache *fnic_io_req_cache;
421d8baf9eSJason Yan static LIST_HEAD(fnic_list);
431d8baf9eSJason Yan static DEFINE_SPINLOCK(fnic_list_lock);
44ca008aeeSKaran Tilak Kumar static DEFINE_IDA(fnic_ida);
455df6d737SAbhijeet Joglekar
465df6d737SAbhijeet Joglekar /* Supported devices by fnic module */
475df6d737SAbhijeet Joglekar static struct pci_device_id fnic_id_table[] = {
485df6d737SAbhijeet Joglekar { PCI_DEVICE(PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_CISCO_FNIC) },
495df6d737SAbhijeet Joglekar { 0, }
505df6d737SAbhijeet Joglekar };
515df6d737SAbhijeet Joglekar
525df6d737SAbhijeet Joglekar MODULE_DESCRIPTION(DRV_DESCRIPTION);
535df6d737SAbhijeet Joglekar MODULE_AUTHOR("Abhijeet Joglekar <abjoglek@cisco.com>, "
545df6d737SAbhijeet Joglekar "Joseph R. Eykholt <jeykholt@cisco.com>");
555df6d737SAbhijeet Joglekar MODULE_LICENSE("GPL v2");
565df6d737SAbhijeet Joglekar MODULE_VERSION(DRV_VERSION);
575df6d737SAbhijeet Joglekar MODULE_DEVICE_TABLE(pci, fnic_id_table);
585df6d737SAbhijeet Joglekar
595df6d737SAbhijeet Joglekar unsigned int fnic_log_level;
605df6d737SAbhijeet Joglekar module_param(fnic_log_level, int, S_IRUGO|S_IWUSR);
615df6d737SAbhijeet Joglekar MODULE_PARM_DESC(fnic_log_level, "bit mask of fnic logging levels");
625df6d737SAbhijeet Joglekar
6318244e94SSatish Kharat
6418244e94SSatish Kharat unsigned int io_completions = FNIC_DFLT_IO_COMPLETIONS;
6518244e94SSatish Kharat module_param(io_completions, int, S_IRUGO|S_IWUSR);
6618244e94SSatish Kharat MODULE_PARM_DESC(io_completions, "Max CQ entries to process at a time");
6718244e94SSatish Kharat
684d7007b4SHiral Patel unsigned int fnic_trace_max_pages = 16;
694d7007b4SHiral Patel module_param(fnic_trace_max_pages, uint, S_IRUGO|S_IWUSR);
704d7007b4SHiral Patel MODULE_PARM_DESC(fnic_trace_max_pages, "Total allocated memory pages "
714d7007b4SHiral Patel "for fnic trace buffer");
725df6d737SAbhijeet Joglekar
73abb14148SHiral Shah unsigned int fnic_fc_trace_max_pages = 64;
74abb14148SHiral Shah module_param(fnic_fc_trace_max_pages, uint, S_IRUGO|S_IWUSR);
75abb14148SHiral Shah MODULE_PARM_DESC(fnic_fc_trace_max_pages,
76abb14148SHiral Shah "Total allocated memory pages for fc trace buffer");
77abb14148SHiral Shah
78fc85799eSHiral Patel static unsigned int fnic_max_qdepth = FNIC_DFLT_QUEUE_DEPTH;
79fc85799eSHiral Patel module_param(fnic_max_qdepth, uint, S_IRUGO|S_IWUSR);
80fc85799eSHiral Patel MODULE_PARM_DESC(fnic_max_qdepth, "Queue depth to report for each LUN");
81fc85799eSHiral Patel
825df6d737SAbhijeet Joglekar static struct libfc_function_template fnic_transport_template = {
835df6d737SAbhijeet Joglekar .frame_send = fnic_send,
8478112e55SJoe Eykholt .lport_set_port_id = fnic_set_port_id,
855df6d737SAbhijeet Joglekar .fcp_abort_io = fnic_empty_scsi_cleanup,
865df6d737SAbhijeet Joglekar .fcp_cleanup = fnic_empty_scsi_cleanup,
875df6d737SAbhijeet Joglekar .exch_mgr_reset = fnic_exch_mgr_reset
885df6d737SAbhijeet Joglekar };
895df6d737SAbhijeet Joglekar
fnic_slave_alloc(struct scsi_device * sdev)905df6d737SAbhijeet Joglekar static int fnic_slave_alloc(struct scsi_device *sdev)
915df6d737SAbhijeet Joglekar {
925df6d737SAbhijeet Joglekar struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
935df6d737SAbhijeet Joglekar
945df6d737SAbhijeet Joglekar if (!rport || fc_remote_port_chkready(rport))
955df6d737SAbhijeet Joglekar return -ENXIO;
965df6d737SAbhijeet Joglekar
97db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, fnic_max_qdepth);
985df6d737SAbhijeet Joglekar return 0;
995df6d737SAbhijeet Joglekar }
1005df6d737SAbhijeet Joglekar
101bf3614bdSBart Van Assche static const struct scsi_host_template fnic_host_template = {
1025df6d737SAbhijeet Joglekar .module = THIS_MODULE,
1035df6d737SAbhijeet Joglekar .name = DRV_NAME,
1045df6d737SAbhijeet Joglekar .queuecommand = fnic_queuecommand,
105b6a05c82SChristoph Hellwig .eh_timed_out = fc_eh_timed_out,
1065df6d737SAbhijeet Joglekar .eh_abort_handler = fnic_abort_cmd,
1075df6d737SAbhijeet Joglekar .eh_device_reset_handler = fnic_device_reset,
1085df6d737SAbhijeet Joglekar .eh_host_reset_handler = fnic_host_reset,
1095df6d737SAbhijeet Joglekar .slave_alloc = fnic_slave_alloc,
110db5ed4dfSChristoph Hellwig .change_queue_depth = scsi_change_queue_depth,
1115df6d737SAbhijeet Joglekar .this_id = -1,
1125df6d737SAbhijeet Joglekar .cmd_per_lun = 3,
113c8ff03c6SHiral Shah .can_queue = FNIC_DFLT_IO_REQ,
1145df6d737SAbhijeet Joglekar .sg_tablesize = FNIC_MAX_SG_DESC_CNT,
1155df6d737SAbhijeet Joglekar .max_sectors = 0xffff,
116d6ddcd8bSBart Van Assche .shost_groups = fnic_host_groups,
117c40ecc12SChristoph Hellwig .track_queue_depth = 1,
118924cb24dSBart Van Assche .cmd_size = sizeof(struct fnic_cmd_priv),
11952f6e196SKaran Tilak Kumar .map_queues = fnic_mq_map_queues_cpus,
1205df6d737SAbhijeet Joglekar };
1215df6d737SAbhijeet Joglekar
1228196a934SMike Christie static void
fnic_set_rport_dev_loss_tmo(struct fc_rport * rport,u32 timeout)12348586820SMike Christie fnic_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
1248196a934SMike Christie {
12548586820SMike Christie if (timeout)
12648586820SMike Christie rport->dev_loss_tmo = timeout;
12748586820SMike Christie else
12848586820SMike Christie rport->dev_loss_tmo = 1;
1298196a934SMike Christie }
1308196a934SMike Christie
1315df6d737SAbhijeet Joglekar static void fnic_get_host_speed(struct Scsi_Host *shost);
1325df6d737SAbhijeet Joglekar static struct scsi_transport_template *fnic_fc_transport;
1335df6d737SAbhijeet Joglekar static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *);
1341adee040SNarsimhulu Musini static void fnic_reset_host_stats(struct Scsi_Host *);
1355df6d737SAbhijeet Joglekar
1365df6d737SAbhijeet Joglekar static struct fc_function_template fnic_fc_functions = {
1375df6d737SAbhijeet Joglekar
1385df6d737SAbhijeet Joglekar .show_host_node_name = 1,
1395df6d737SAbhijeet Joglekar .show_host_port_name = 1,
1405df6d737SAbhijeet Joglekar .show_host_supported_classes = 1,
1415df6d737SAbhijeet Joglekar .show_host_supported_fc4s = 1,
1425df6d737SAbhijeet Joglekar .show_host_active_fc4s = 1,
1435df6d737SAbhijeet Joglekar .show_host_maxframe_size = 1,
1445df6d737SAbhijeet Joglekar .show_host_port_id = 1,
1455df6d737SAbhijeet Joglekar .show_host_supported_speeds = 1,
1465df6d737SAbhijeet Joglekar .get_host_speed = fnic_get_host_speed,
1475df6d737SAbhijeet Joglekar .show_host_speed = 1,
1485df6d737SAbhijeet Joglekar .show_host_port_type = 1,
1495df6d737SAbhijeet Joglekar .get_host_port_state = fc_get_host_port_state,
1505df6d737SAbhijeet Joglekar .show_host_port_state = 1,
1515df6d737SAbhijeet Joglekar .show_host_symbolic_name = 1,
1525df6d737SAbhijeet Joglekar .show_rport_maxframe_size = 1,
1535df6d737SAbhijeet Joglekar .show_rport_supported_classes = 1,
1545df6d737SAbhijeet Joglekar .show_host_fabric_name = 1,
1555df6d737SAbhijeet Joglekar .show_starget_node_name = 1,
1565df6d737SAbhijeet Joglekar .show_starget_port_name = 1,
1575df6d737SAbhijeet Joglekar .show_starget_port_id = 1,
1585df6d737SAbhijeet Joglekar .show_rport_dev_loss_tmo = 1,
15948586820SMike Christie .set_rport_dev_loss_tmo = fnic_set_rport_dev_loss_tmo,
1605df6d737SAbhijeet Joglekar .issue_fc_host_lip = fnic_reset,
1615df6d737SAbhijeet Joglekar .get_fc_host_stats = fnic_get_stats,
1621adee040SNarsimhulu Musini .reset_fc_host_stats = fnic_reset_host_stats,
1635df6d737SAbhijeet Joglekar .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv),
1645df6d737SAbhijeet Joglekar .terminate_rport_io = fnic_terminate_rport_io,
16576d8737cSJoe Eykholt .bsg_request = fc_lport_bsg_request,
1665df6d737SAbhijeet Joglekar };
1675df6d737SAbhijeet Joglekar
fnic_get_host_speed(struct Scsi_Host * shost)1685df6d737SAbhijeet Joglekar static void fnic_get_host_speed(struct Scsi_Host *shost)
1695df6d737SAbhijeet Joglekar {
1705df6d737SAbhijeet Joglekar struct fc_lport *lp = shost_priv(shost);
1715df6d737SAbhijeet Joglekar struct fnic *fnic = lport_priv(lp);
1725df6d737SAbhijeet Joglekar u32 port_speed = vnic_dev_port_speed(fnic->vdev);
1735df6d737SAbhijeet Joglekar
1745df6d737SAbhijeet Joglekar /* Add in other values as they get defined in fw */
1755df6d737SAbhijeet Joglekar switch (port_speed) {
176c22fa50bSSatish Kharat case DCEM_PORTSPEED_10G:
1775df6d737SAbhijeet Joglekar fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
1785df6d737SAbhijeet Joglekar break;
179c01461a6SSatish Kharat case DCEM_PORTSPEED_20G:
180c01461a6SSatish Kharat fc_host_speed(shost) = FC_PORTSPEED_20GBIT;
181c01461a6SSatish Kharat break;
182c22fa50bSSatish Kharat case DCEM_PORTSPEED_25G:
183c22fa50bSSatish Kharat fc_host_speed(shost) = FC_PORTSPEED_25GBIT;
184c22fa50bSSatish Kharat break;
185c22fa50bSSatish Kharat case DCEM_PORTSPEED_40G:
186c22fa50bSSatish Kharat case DCEM_PORTSPEED_4x10G:
187c22fa50bSSatish Kharat fc_host_speed(shost) = FC_PORTSPEED_40GBIT;
188c22fa50bSSatish Kharat break;
189c22fa50bSSatish Kharat case DCEM_PORTSPEED_100G:
190c22fa50bSSatish Kharat fc_host_speed(shost) = FC_PORTSPEED_100GBIT;
191c22fa50bSSatish Kharat break;
1925df6d737SAbhijeet Joglekar default:
193c22fa50bSSatish Kharat fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
1945df6d737SAbhijeet Joglekar break;
1955df6d737SAbhijeet Joglekar }
1965df6d737SAbhijeet Joglekar }
1975df6d737SAbhijeet Joglekar
fnic_get_stats(struct Scsi_Host * host)1985df6d737SAbhijeet Joglekar static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *host)
1995df6d737SAbhijeet Joglekar {
2005df6d737SAbhijeet Joglekar int ret;
2015df6d737SAbhijeet Joglekar struct fc_lport *lp = shost_priv(host);
2025df6d737SAbhijeet Joglekar struct fnic *fnic = lport_priv(lp);
2035df6d737SAbhijeet Joglekar struct fc_host_statistics *stats = &lp->host_stats;
2045df6d737SAbhijeet Joglekar struct vnic_stats *vs;
2055df6d737SAbhijeet Joglekar unsigned long flags;
2065df6d737SAbhijeet Joglekar
2075df6d737SAbhijeet Joglekar if (time_before(jiffies, fnic->stats_time + HZ / FNIC_STATS_RATE_LIMIT))
2085df6d737SAbhijeet Joglekar return stats;
2095df6d737SAbhijeet Joglekar fnic->stats_time = jiffies;
2105df6d737SAbhijeet Joglekar
2115df6d737SAbhijeet Joglekar spin_lock_irqsave(&fnic->fnic_lock, flags);
2125df6d737SAbhijeet Joglekar ret = vnic_dev_stats_dump(fnic->vdev, &fnic->stats);
2135df6d737SAbhijeet Joglekar spin_unlock_irqrestore(&fnic->fnic_lock, flags);
2145df6d737SAbhijeet Joglekar
2155df6d737SAbhijeet Joglekar if (ret) {
2163df9dd0dSKaran Tilak Kumar FNIC_MAIN_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num,
2175df6d737SAbhijeet Joglekar "fnic: Get vnic stats failed"
2185df6d737SAbhijeet Joglekar " 0x%x", ret);
2195df6d737SAbhijeet Joglekar return stats;
2205df6d737SAbhijeet Joglekar }
2215df6d737SAbhijeet Joglekar vs = fnic->stats;
2225df6d737SAbhijeet Joglekar stats->tx_frames = vs->tx.tx_unicast_frames_ok;
2235df6d737SAbhijeet Joglekar stats->tx_words = vs->tx.tx_unicast_bytes_ok / 4;
2245df6d737SAbhijeet Joglekar stats->rx_frames = vs->rx.rx_unicast_frames_ok;
2255df6d737SAbhijeet Joglekar stats->rx_words = vs->rx.rx_unicast_bytes_ok / 4;
2265df6d737SAbhijeet Joglekar stats->error_frames = vs->tx.tx_errors + vs->rx.rx_errors;
2275df6d737SAbhijeet Joglekar stats->dumped_frames = vs->tx.tx_drops + vs->rx.rx_drop;
2285df6d737SAbhijeet Joglekar stats->invalid_crc_count = vs->rx.rx_crc_errors;
2291adee040SNarsimhulu Musini stats->seconds_since_last_reset =
2301adee040SNarsimhulu Musini (jiffies - fnic->stats_reset_time) / HZ;
2315df6d737SAbhijeet Joglekar stats->fcp_input_megabytes = div_u64(fnic->fcp_input_bytes, 1000000);
2325df6d737SAbhijeet Joglekar stats->fcp_output_megabytes = div_u64(fnic->fcp_output_bytes, 1000000);
2335df6d737SAbhijeet Joglekar
2345df6d737SAbhijeet Joglekar return stats;
2355df6d737SAbhijeet Joglekar }
2365df6d737SAbhijeet Joglekar
2371adee040SNarsimhulu Musini /*
2381adee040SNarsimhulu Musini * fnic_dump_fchost_stats
2391adee040SNarsimhulu Musini * note : dumps fc_statistics into system logs
2401adee040SNarsimhulu Musini */
fnic_dump_fchost_stats(struct Scsi_Host * host,struct fc_host_statistics * stats)2411adee040SNarsimhulu Musini void fnic_dump_fchost_stats(struct Scsi_Host *host,
2421adee040SNarsimhulu Musini struct fc_host_statistics *stats)
2431adee040SNarsimhulu Musini {
2441adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2451adee040SNarsimhulu Musini "fnic: seconds since last reset = %llu\n",
2461adee040SNarsimhulu Musini stats->seconds_since_last_reset);
2471adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2481adee040SNarsimhulu Musini "fnic: tx frames = %llu\n",
2491adee040SNarsimhulu Musini stats->tx_frames);
2501adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2511adee040SNarsimhulu Musini "fnic: tx words = %llu\n",
2521adee040SNarsimhulu Musini stats->tx_words);
2531adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2541adee040SNarsimhulu Musini "fnic: rx frames = %llu\n",
2551adee040SNarsimhulu Musini stats->rx_frames);
2561adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2571adee040SNarsimhulu Musini "fnic: rx words = %llu\n",
2581adee040SNarsimhulu Musini stats->rx_words);
2591adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2601adee040SNarsimhulu Musini "fnic: lip count = %llu\n",
2611adee040SNarsimhulu Musini stats->lip_count);
2621adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2631adee040SNarsimhulu Musini "fnic: nos count = %llu\n",
2641adee040SNarsimhulu Musini stats->nos_count);
2651adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2661adee040SNarsimhulu Musini "fnic: error frames = %llu\n",
2671adee040SNarsimhulu Musini stats->error_frames);
2681adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2691adee040SNarsimhulu Musini "fnic: dumped frames = %llu\n",
2701adee040SNarsimhulu Musini stats->dumped_frames);
2711adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2721adee040SNarsimhulu Musini "fnic: link failure count = %llu\n",
2731adee040SNarsimhulu Musini stats->link_failure_count);
2741adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2751adee040SNarsimhulu Musini "fnic: loss of sync count = %llu\n",
2761adee040SNarsimhulu Musini stats->loss_of_sync_count);
2771adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2781adee040SNarsimhulu Musini "fnic: loss of signal count = %llu\n",
2791adee040SNarsimhulu Musini stats->loss_of_signal_count);
2801adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2811adee040SNarsimhulu Musini "fnic: prim seq protocol err count = %llu\n",
2821adee040SNarsimhulu Musini stats->prim_seq_protocol_err_count);
2831adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2841adee040SNarsimhulu Musini "fnic: invalid tx word count= %llu\n",
2851adee040SNarsimhulu Musini stats->invalid_tx_word_count);
2861adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2871adee040SNarsimhulu Musini "fnic: invalid crc count = %llu\n",
2881adee040SNarsimhulu Musini stats->invalid_crc_count);
2891adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2901adee040SNarsimhulu Musini "fnic: fcp input requests = %llu\n",
2911adee040SNarsimhulu Musini stats->fcp_input_requests);
2921adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2931adee040SNarsimhulu Musini "fnic: fcp output requests = %llu\n",
2941adee040SNarsimhulu Musini stats->fcp_output_requests);
2951adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2961adee040SNarsimhulu Musini "fnic: fcp control requests = %llu\n",
2971adee040SNarsimhulu Musini stats->fcp_control_requests);
2981adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
2991adee040SNarsimhulu Musini "fnic: fcp input megabytes = %llu\n",
3001adee040SNarsimhulu Musini stats->fcp_input_megabytes);
3011adee040SNarsimhulu Musini FNIC_MAIN_NOTE(KERN_NOTICE, host,
3021adee040SNarsimhulu Musini "fnic: fcp output megabytes = %llu\n",
3031adee040SNarsimhulu Musini stats->fcp_output_megabytes);
3041adee040SNarsimhulu Musini return;
3051adee040SNarsimhulu Musini }
3061adee040SNarsimhulu Musini
3071adee040SNarsimhulu Musini /*
3081adee040SNarsimhulu Musini * fnic_reset_host_stats : clears host stats
3091adee040SNarsimhulu Musini * note : called when reset_statistics set under sysfs dir
3101adee040SNarsimhulu Musini */
fnic_reset_host_stats(struct Scsi_Host * host)3111adee040SNarsimhulu Musini static void fnic_reset_host_stats(struct Scsi_Host *host)
3121adee040SNarsimhulu Musini {
3131adee040SNarsimhulu Musini int ret;
3141adee040SNarsimhulu Musini struct fc_lport *lp = shost_priv(host);
3151adee040SNarsimhulu Musini struct fnic *fnic = lport_priv(lp);
3161adee040SNarsimhulu Musini struct fc_host_statistics *stats;
3171adee040SNarsimhulu Musini unsigned long flags;
3181adee040SNarsimhulu Musini
3191adee040SNarsimhulu Musini /* dump current stats, before clearing them */
3201adee040SNarsimhulu Musini stats = fnic_get_stats(host);
3211adee040SNarsimhulu Musini fnic_dump_fchost_stats(host, stats);
3221adee040SNarsimhulu Musini
3231adee040SNarsimhulu Musini spin_lock_irqsave(&fnic->fnic_lock, flags);
3241adee040SNarsimhulu Musini ret = vnic_dev_stats_clear(fnic->vdev);
3251adee040SNarsimhulu Musini spin_unlock_irqrestore(&fnic->fnic_lock, flags);
3261adee040SNarsimhulu Musini
3271adee040SNarsimhulu Musini if (ret) {
3283df9dd0dSKaran Tilak Kumar FNIC_MAIN_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num,
3291adee040SNarsimhulu Musini "fnic: Reset vnic stats failed"
3301adee040SNarsimhulu Musini " 0x%x", ret);
3311adee040SNarsimhulu Musini return;
3321adee040SNarsimhulu Musini }
3331adee040SNarsimhulu Musini fnic->stats_reset_time = jiffies;
3341adee040SNarsimhulu Musini memset(stats, 0, sizeof(*stats));
3351adee040SNarsimhulu Musini
3361adee040SNarsimhulu Musini return;
3371adee040SNarsimhulu Musini }
3381adee040SNarsimhulu Musini
fnic_log_q_error(struct fnic * fnic)3395df6d737SAbhijeet Joglekar void fnic_log_q_error(struct fnic *fnic)
3405df6d737SAbhijeet Joglekar {
3415df6d737SAbhijeet Joglekar unsigned int i;
3425df6d737SAbhijeet Joglekar u32 error_status;
3435df6d737SAbhijeet Joglekar
3445df6d737SAbhijeet Joglekar for (i = 0; i < fnic->raw_wq_count; i++) {
3455df6d737SAbhijeet Joglekar error_status = ioread32(&fnic->wq[i].ctrl->error_status);
3465df6d737SAbhijeet Joglekar if (error_status)
3475df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
3485df6d737SAbhijeet Joglekar "WQ[%d] error_status"
3495df6d737SAbhijeet Joglekar " %d\n", i, error_status);
3505df6d737SAbhijeet Joglekar }
3515df6d737SAbhijeet Joglekar
3525df6d737SAbhijeet Joglekar for (i = 0; i < fnic->rq_count; i++) {
3535df6d737SAbhijeet Joglekar error_status = ioread32(&fnic->rq[i].ctrl->error_status);
3545df6d737SAbhijeet Joglekar if (error_status)
3555df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
3565df6d737SAbhijeet Joglekar "RQ[%d] error_status"
3575df6d737SAbhijeet Joglekar " %d\n", i, error_status);
3585df6d737SAbhijeet Joglekar }
3595df6d737SAbhijeet Joglekar
3605df6d737SAbhijeet Joglekar for (i = 0; i < fnic->wq_copy_count; i++) {
36186b86a7dSKaran Tilak Kumar error_status = ioread32(&fnic->hw_copy_wq[i].ctrl->error_status);
3625df6d737SAbhijeet Joglekar if (error_status)
3635df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
3645df6d737SAbhijeet Joglekar "CWQ[%d] error_status"
3655df6d737SAbhijeet Joglekar " %d\n", i, error_status);
3665df6d737SAbhijeet Joglekar }
3675df6d737SAbhijeet Joglekar }
3685df6d737SAbhijeet Joglekar
fnic_handle_link_event(struct fnic * fnic)3695df6d737SAbhijeet Joglekar void fnic_handle_link_event(struct fnic *fnic)
3705df6d737SAbhijeet Joglekar {
3715df6d737SAbhijeet Joglekar unsigned long flags;
3725df6d737SAbhijeet Joglekar
3735df6d737SAbhijeet Joglekar spin_lock_irqsave(&fnic->fnic_lock, flags);
3745df6d737SAbhijeet Joglekar if (fnic->stop_rx_link_events) {
3755df6d737SAbhijeet Joglekar spin_unlock_irqrestore(&fnic->fnic_lock, flags);
3765df6d737SAbhijeet Joglekar return;
3775df6d737SAbhijeet Joglekar }
3785df6d737SAbhijeet Joglekar spin_unlock_irqrestore(&fnic->fnic_lock, flags);
3795df6d737SAbhijeet Joglekar
3805df6d737SAbhijeet Joglekar queue_work(fnic_event_queue, &fnic->link_work);
3815df6d737SAbhijeet Joglekar
3825df6d737SAbhijeet Joglekar }
3835df6d737SAbhijeet Joglekar
fnic_notify_set(struct fnic * fnic)3845df6d737SAbhijeet Joglekar static int fnic_notify_set(struct fnic *fnic)
3855df6d737SAbhijeet Joglekar {
3865df6d737SAbhijeet Joglekar int err;
3875df6d737SAbhijeet Joglekar
3885df6d737SAbhijeet Joglekar switch (vnic_dev_get_intr_mode(fnic->vdev)) {
3895df6d737SAbhijeet Joglekar case VNIC_DEV_INTR_MODE_INTX:
3905df6d737SAbhijeet Joglekar err = vnic_dev_notify_set(fnic->vdev, FNIC_INTX_NOTIFY);
3915df6d737SAbhijeet Joglekar break;
3925df6d737SAbhijeet Joglekar case VNIC_DEV_INTR_MODE_MSI:
3935df6d737SAbhijeet Joglekar err = vnic_dev_notify_set(fnic->vdev, -1);
3945df6d737SAbhijeet Joglekar break;
3955df6d737SAbhijeet Joglekar case VNIC_DEV_INTR_MODE_MSIX:
39652f6e196SKaran Tilak Kumar err = vnic_dev_notify_set(fnic->vdev, fnic->wq_copy_count + fnic->copy_wq_base);
3975df6d737SAbhijeet Joglekar break;
3985df6d737SAbhijeet Joglekar default:
3995df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
4005df6d737SAbhijeet Joglekar "Interrupt mode should be set up"
4015df6d737SAbhijeet Joglekar " before devcmd notify set %d\n",
4025df6d737SAbhijeet Joglekar vnic_dev_get_intr_mode(fnic->vdev));
4035df6d737SAbhijeet Joglekar err = -1;
4045df6d737SAbhijeet Joglekar break;
4055df6d737SAbhijeet Joglekar }
4065df6d737SAbhijeet Joglekar
4075df6d737SAbhijeet Joglekar return err;
4085df6d737SAbhijeet Joglekar }
4095df6d737SAbhijeet Joglekar
fnic_notify_timer(struct timer_list * t)410e99e88a9SKees Cook static void fnic_notify_timer(struct timer_list *t)
4115df6d737SAbhijeet Joglekar {
412e99e88a9SKees Cook struct fnic *fnic = from_timer(fnic, t, notify_timer);
4135df6d737SAbhijeet Joglekar
4145df6d737SAbhijeet Joglekar fnic_handle_link_event(fnic);
4155df6d737SAbhijeet Joglekar mod_timer(&fnic->notify_timer,
4165df6d737SAbhijeet Joglekar round_jiffies(jiffies + FNIC_NOTIFY_TIMER_PERIOD));
4175df6d737SAbhijeet Joglekar }
4185df6d737SAbhijeet Joglekar
fnic_fip_notify_timer(struct timer_list * t)419e99e88a9SKees Cook static void fnic_fip_notify_timer(struct timer_list *t)
420d3c995f1SHiral Patel {
421e99e88a9SKees Cook struct fnic *fnic = from_timer(fnic, t, fip_timer);
422d3c995f1SHiral Patel
423d3c995f1SHiral Patel fnic_handle_fip_timer(fnic);
424d3c995f1SHiral Patel }
425d3c995f1SHiral Patel
fnic_notify_timer_start(struct fnic * fnic)4265df6d737SAbhijeet Joglekar static void fnic_notify_timer_start(struct fnic *fnic)
4275df6d737SAbhijeet Joglekar {
4285df6d737SAbhijeet Joglekar switch (vnic_dev_get_intr_mode(fnic->vdev)) {
4295df6d737SAbhijeet Joglekar case VNIC_DEV_INTR_MODE_MSI:
4305df6d737SAbhijeet Joglekar /*
4315df6d737SAbhijeet Joglekar * Schedule first timeout immediately. The driver is
4325df6d737SAbhijeet Joglekar * initiatialized and ready to look for link up notification
4335df6d737SAbhijeet Joglekar */
4345df6d737SAbhijeet Joglekar mod_timer(&fnic->notify_timer, jiffies);
4355df6d737SAbhijeet Joglekar break;
4365df6d737SAbhijeet Joglekar default:
4375df6d737SAbhijeet Joglekar /* Using intr for notification for INTx/MSI-X */
4385df6d737SAbhijeet Joglekar break;
439bff8b14bSJason Yan }
4405df6d737SAbhijeet Joglekar }
4415df6d737SAbhijeet Joglekar
fnic_dev_wait(struct vnic_dev * vdev,int (* start)(struct vnic_dev *,int),int (* finished)(struct vnic_dev *,int *),int arg)4425df6d737SAbhijeet Joglekar static int fnic_dev_wait(struct vnic_dev *vdev,
4435df6d737SAbhijeet Joglekar int (*start)(struct vnic_dev *, int),
4445df6d737SAbhijeet Joglekar int (*finished)(struct vnic_dev *, int *),
4455df6d737SAbhijeet Joglekar int arg)
4465df6d737SAbhijeet Joglekar {
4475df6d737SAbhijeet Joglekar unsigned long time;
4485df6d737SAbhijeet Joglekar int done;
4495df6d737SAbhijeet Joglekar int err;
450a232bfbeSHiral Shah int count;
451a232bfbeSHiral Shah
452a232bfbeSHiral Shah count = 0;
4535df6d737SAbhijeet Joglekar
4545df6d737SAbhijeet Joglekar err = start(vdev, arg);
4555df6d737SAbhijeet Joglekar if (err)
4565df6d737SAbhijeet Joglekar return err;
4575df6d737SAbhijeet Joglekar
458a232bfbeSHiral Shah /* Wait for func to complete.
459a232bfbeSHiral Shah * Sometime schedule_timeout_uninterruptible take long time
460a232bfbeSHiral Shah * to wake up so we do not retry as we are only waiting for
461a232bfbeSHiral Shah * 2 seconds in while loop. By adding count, we make sure
462a232bfbeSHiral Shah * we try atleast three times before returning -ETIMEDOUT
463a232bfbeSHiral Shah */
4645df6d737SAbhijeet Joglekar time = jiffies + (HZ * 2);
4655df6d737SAbhijeet Joglekar do {
4665df6d737SAbhijeet Joglekar err = finished(vdev, &done);
467a232bfbeSHiral Shah count++;
4685df6d737SAbhijeet Joglekar if (err)
4695df6d737SAbhijeet Joglekar return err;
4705df6d737SAbhijeet Joglekar if (done)
4715df6d737SAbhijeet Joglekar return 0;
4725df6d737SAbhijeet Joglekar schedule_timeout_uninterruptible(HZ / 10);
473a232bfbeSHiral Shah } while (time_after(time, jiffies) || (count < 3));
4745df6d737SAbhijeet Joglekar
4755df6d737SAbhijeet Joglekar return -ETIMEDOUT;
4765df6d737SAbhijeet Joglekar }
4775df6d737SAbhijeet Joglekar
fnic_cleanup(struct fnic * fnic)4785df6d737SAbhijeet Joglekar static int fnic_cleanup(struct fnic *fnic)
4795df6d737SAbhijeet Joglekar {
4805df6d737SAbhijeet Joglekar unsigned int i;
4815df6d737SAbhijeet Joglekar int err;
4828a8449caSKaran Tilak Kumar int raw_wq_rq_counts;
4835df6d737SAbhijeet Joglekar
4845df6d737SAbhijeet Joglekar vnic_dev_disable(fnic->vdev);
4855df6d737SAbhijeet Joglekar for (i = 0; i < fnic->intr_count; i++)
4865df6d737SAbhijeet Joglekar vnic_intr_mask(&fnic->intr[i]);
4875df6d737SAbhijeet Joglekar
4885df6d737SAbhijeet Joglekar for (i = 0; i < fnic->rq_count; i++) {
4895df6d737SAbhijeet Joglekar err = vnic_rq_disable(&fnic->rq[i]);
4905df6d737SAbhijeet Joglekar if (err)
4915df6d737SAbhijeet Joglekar return err;
4925df6d737SAbhijeet Joglekar }
4935df6d737SAbhijeet Joglekar for (i = 0; i < fnic->raw_wq_count; i++) {
4945df6d737SAbhijeet Joglekar err = vnic_wq_disable(&fnic->wq[i]);
4955df6d737SAbhijeet Joglekar if (err)
4965df6d737SAbhijeet Joglekar return err;
4975df6d737SAbhijeet Joglekar }
4985df6d737SAbhijeet Joglekar for (i = 0; i < fnic->wq_copy_count; i++) {
49986b86a7dSKaran Tilak Kumar err = vnic_wq_copy_disable(&fnic->hw_copy_wq[i]);
5005df6d737SAbhijeet Joglekar if (err)
5015df6d737SAbhijeet Joglekar return err;
5028a8449caSKaran Tilak Kumar raw_wq_rq_counts = fnic->raw_wq_count + fnic->rq_count;
5038a8449caSKaran Tilak Kumar fnic_wq_copy_cmpl_handler(fnic, -1, i + raw_wq_rq_counts);
5045df6d737SAbhijeet Joglekar }
5055df6d737SAbhijeet Joglekar
5065df6d737SAbhijeet Joglekar /* Clean up completed IOs and FCS frames */
5075df6d737SAbhijeet Joglekar fnic_wq_cmpl_handler(fnic, -1);
5085df6d737SAbhijeet Joglekar fnic_rq_cmpl_handler(fnic, -1);
5095df6d737SAbhijeet Joglekar
5105df6d737SAbhijeet Joglekar /* Clean up the IOs and FCS frames that have not completed */
5115df6d737SAbhijeet Joglekar for (i = 0; i < fnic->raw_wq_count; i++)
5125df6d737SAbhijeet Joglekar vnic_wq_clean(&fnic->wq[i], fnic_free_wq_buf);
5135df6d737SAbhijeet Joglekar for (i = 0; i < fnic->rq_count; i++)
5145df6d737SAbhijeet Joglekar vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf);
5155df6d737SAbhijeet Joglekar for (i = 0; i < fnic->wq_copy_count; i++)
51686b86a7dSKaran Tilak Kumar vnic_wq_copy_clean(&fnic->hw_copy_wq[i],
5175df6d737SAbhijeet Joglekar fnic_wq_copy_cleanup_handler);
5185df6d737SAbhijeet Joglekar
5195df6d737SAbhijeet Joglekar for (i = 0; i < fnic->cq_count; i++)
5205df6d737SAbhijeet Joglekar vnic_cq_clean(&fnic->cq[i]);
5215df6d737SAbhijeet Joglekar for (i = 0; i < fnic->intr_count; i++)
5225df6d737SAbhijeet Joglekar vnic_intr_clean(&fnic->intr[i]);
5235df6d737SAbhijeet Joglekar
5245df6d737SAbhijeet Joglekar mempool_destroy(fnic->io_req_pool);
5255df6d737SAbhijeet Joglekar for (i = 0; i < FNIC_SGL_NUM_CACHES; i++)
5265df6d737SAbhijeet Joglekar mempool_destroy(fnic->io_sgl_pool[i]);
5275df6d737SAbhijeet Joglekar
5285df6d737SAbhijeet Joglekar return 0;
5295df6d737SAbhijeet Joglekar }
5305df6d737SAbhijeet Joglekar
fnic_iounmap(struct fnic * fnic)5315df6d737SAbhijeet Joglekar static void fnic_iounmap(struct fnic *fnic)
5325df6d737SAbhijeet Joglekar {
5335df6d737SAbhijeet Joglekar if (fnic->bar0.vaddr)
5345df6d737SAbhijeet Joglekar iounmap(fnic->bar0.vaddr);
5355df6d737SAbhijeet Joglekar }
5365df6d737SAbhijeet Joglekar
53778112e55SJoe Eykholt /**
53878112e55SJoe Eykholt * fnic_get_mac() - get assigned data MAC address for FIP code.
53978112e55SJoe Eykholt * @lport: local port.
54078112e55SJoe Eykholt */
fnic_get_mac(struct fc_lport * lport)54178112e55SJoe Eykholt static u8 *fnic_get_mac(struct fc_lport *lport)
54278112e55SJoe Eykholt {
54378112e55SJoe Eykholt struct fnic *fnic = lport_priv(lport);
54478112e55SJoe Eykholt
54578112e55SJoe Eykholt return fnic->data_src_addr;
54678112e55SJoe Eykholt }
54778112e55SJoe Eykholt
fnic_set_vlan(struct fnic * fnic,u16 vlan_id)548d3c995f1SHiral Patel static void fnic_set_vlan(struct fnic *fnic, u16 vlan_id)
549d3c995f1SHiral Patel {
550c65b4f37SJason Yan vnic_dev_set_default_vlan(fnic->vdev, vlan_id);
551d3c995f1SHiral Patel }
552d3c995f1SHiral Patel
fnic_scsi_drv_init(struct fnic * fnic)553aec95e3aSKaran Tilak Kumar static int fnic_scsi_drv_init(struct fnic *fnic)
554aec95e3aSKaran Tilak Kumar {
555aec95e3aSKaran Tilak Kumar struct Scsi_Host *host = fnic->lport->host;
556aec95e3aSKaran Tilak Kumar
557aec95e3aSKaran Tilak Kumar /* Configure maximum outstanding IO reqs*/
558aec95e3aSKaran Tilak Kumar if (fnic->config.io_throttle_count != FNIC_UCSM_DFLT_THROTTLE_CNT_BLD)
559aec95e3aSKaran Tilak Kumar host->can_queue = min_t(u32, FNIC_MAX_IO_REQ,
560aec95e3aSKaran Tilak Kumar max_t(u32, FNIC_MIN_IO_REQ,
561aec95e3aSKaran Tilak Kumar fnic->config.io_throttle_count));
562aec95e3aSKaran Tilak Kumar
563aec95e3aSKaran Tilak Kumar fnic->fnic_max_tag_id = host->can_queue;
564aec95e3aSKaran Tilak Kumar host->max_lun = fnic->config.luns_per_tgt;
565aec95e3aSKaran Tilak Kumar host->max_id = FNIC_MAX_FCP_TARGET;
566aec95e3aSKaran Tilak Kumar host->max_cmd_len = FCOE_MAX_CMD_LEN;
567aec95e3aSKaran Tilak Kumar
568aec95e3aSKaran Tilak Kumar host->nr_hw_queues = fnic->wq_copy_count;
569aec95e3aSKaran Tilak Kumar
570aec95e3aSKaran Tilak Kumar shost_printk(KERN_INFO, host,
571aec95e3aSKaran Tilak Kumar "fnic: can_queue: %d max_lun: %llu",
572aec95e3aSKaran Tilak Kumar host->can_queue, host->max_lun);
573aec95e3aSKaran Tilak Kumar
574aec95e3aSKaran Tilak Kumar shost_printk(KERN_INFO, host,
575aec95e3aSKaran Tilak Kumar "fnic: max_id: %d max_cmd_len: %d nr_hw_queues: %d",
576aec95e3aSKaran Tilak Kumar host->max_id, host->max_cmd_len, host->nr_hw_queues);
577aec95e3aSKaran Tilak Kumar
578aec95e3aSKaran Tilak Kumar return 0;
579aec95e3aSKaran Tilak Kumar }
580aec95e3aSKaran Tilak Kumar
fnic_mq_map_queues_cpus(struct Scsi_Host * host)58152f6e196SKaran Tilak Kumar void fnic_mq_map_queues_cpus(struct Scsi_Host *host)
58252f6e196SKaran Tilak Kumar {
58352f6e196SKaran Tilak Kumar struct fc_lport *lp = shost_priv(host);
58452f6e196SKaran Tilak Kumar struct fnic *fnic = lport_priv(lp);
58552f6e196SKaran Tilak Kumar struct pci_dev *l_pdev = fnic->pdev;
58652f6e196SKaran Tilak Kumar int intr_mode = fnic->config.intr_mode;
58752f6e196SKaran Tilak Kumar struct blk_mq_queue_map *qmap = &host->tag_set.map[HCTX_TYPE_DEFAULT];
58852f6e196SKaran Tilak Kumar
58952f6e196SKaran Tilak Kumar if (intr_mode == VNIC_DEV_INTR_MODE_MSI || intr_mode == VNIC_DEV_INTR_MODE_INTX) {
59052f6e196SKaran Tilak Kumar FNIC_MAIN_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num,
59152f6e196SKaran Tilak Kumar "intr_mode is not msix\n");
59252f6e196SKaran Tilak Kumar return;
59352f6e196SKaran Tilak Kumar }
59452f6e196SKaran Tilak Kumar
59552f6e196SKaran Tilak Kumar FNIC_MAIN_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num,
59652f6e196SKaran Tilak Kumar "qmap->nr_queues: %d\n", qmap->nr_queues);
59752f6e196SKaran Tilak Kumar
59852f6e196SKaran Tilak Kumar if (l_pdev == NULL) {
59952f6e196SKaran Tilak Kumar FNIC_MAIN_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num,
60052f6e196SKaran Tilak Kumar "l_pdev is null\n");
60152f6e196SKaran Tilak Kumar return;
60252f6e196SKaran Tilak Kumar }
60352f6e196SKaran Tilak Kumar
60452f6e196SKaran Tilak Kumar blk_mq_pci_map_queues(qmap, l_pdev, FNIC_PCI_OFFSET);
60552f6e196SKaran Tilak Kumar }
60652f6e196SKaran Tilak Kumar
fnic_probe(struct pci_dev * pdev,const struct pci_device_id * ent)6076f039790SGreg Kroah-Hartman static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
6085df6d737SAbhijeet Joglekar {
6095df6d737SAbhijeet Joglekar struct Scsi_Host *host;
6105df6d737SAbhijeet Joglekar struct fc_lport *lp;
6115df6d737SAbhijeet Joglekar struct fnic *fnic;
6125df6d737SAbhijeet Joglekar mempool_t *pool;
613ca008aeeSKaran Tilak Kumar int err = 0;
614ca008aeeSKaran Tilak Kumar int fnic_id = 0;
6155df6d737SAbhijeet Joglekar int i;
6165df6d737SAbhijeet Joglekar unsigned long flags;
61752f6e196SKaran Tilak Kumar int hwq;
6185df6d737SAbhijeet Joglekar
6195df6d737SAbhijeet Joglekar /*
6205df6d737SAbhijeet Joglekar * Allocate SCSI Host and set up association between host,
6215df6d737SAbhijeet Joglekar * local port, and fnic
6225df6d737SAbhijeet Joglekar */
62386221969SChris Leech lp = libfc_host_alloc(&fnic_host_template, sizeof(struct fnic));
62486221969SChris Leech if (!lp) {
62586221969SChris Leech printk(KERN_ERR PFX "Unable to alloc libfc local port\n");
6265df6d737SAbhijeet Joglekar err = -ENOMEM;
6275df6d737SAbhijeet Joglekar goto err_out;
6285df6d737SAbhijeet Joglekar }
629ca008aeeSKaran Tilak Kumar
63086221969SChris Leech host = lp->host;
6315df6d737SAbhijeet Joglekar fnic = lport_priv(lp);
632ca008aeeSKaran Tilak Kumar
633ca008aeeSKaran Tilak Kumar fnic_id = ida_alloc(&fnic_ida, GFP_KERNEL);
634ca008aeeSKaran Tilak Kumar if (fnic_id < 0) {
635ca008aeeSKaran Tilak Kumar pr_err("Unable to alloc fnic ID\n");
636ca008aeeSKaran Tilak Kumar err = fnic_id;
637ca008aeeSKaran Tilak Kumar goto err_out_ida_alloc;
638ca008aeeSKaran Tilak Kumar }
6395df6d737SAbhijeet Joglekar fnic->lport = lp;
64078112e55SJoe Eykholt fnic->ctlr.lp = lp;
641f9e2beb9SKaran Tilak Kumar fnic->link_events = 0;
64252f6e196SKaran Tilak Kumar fnic->pdev = pdev;
643f9e2beb9SKaran Tilak Kumar
6445df6d737SAbhijeet Joglekar snprintf(fnic->name, sizeof(fnic->name) - 1, "%s%d", DRV_NAME,
6455df6d737SAbhijeet Joglekar host->host_no);
6465df6d737SAbhijeet Joglekar
6475df6d737SAbhijeet Joglekar host->transportt = fnic_fc_transport;
648ca008aeeSKaran Tilak Kumar fnic->fnic_num = fnic_id;
6491dbaa379SGreg Kroah-Hartman fnic_stats_debugfs_init(fnic);
65067125b02SHiral Patel
6515df6d737SAbhijeet Joglekar err = pci_enable_device(pdev);
6525df6d737SAbhijeet Joglekar if (err) {
6535df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
6545df6d737SAbhijeet Joglekar "Cannot enable PCI device, aborting.\n");
6555df6d737SAbhijeet Joglekar goto err_out_free_hba;
6565df6d737SAbhijeet Joglekar }
6575df6d737SAbhijeet Joglekar
6585df6d737SAbhijeet Joglekar err = pci_request_regions(pdev, DRV_NAME);
6595df6d737SAbhijeet Joglekar if (err) {
6605df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
6615df6d737SAbhijeet Joglekar "Cannot enable PCI resources, aborting\n");
6625df6d737SAbhijeet Joglekar goto err_out_disable_device;
6635df6d737SAbhijeet Joglekar }
6645df6d737SAbhijeet Joglekar
6655df6d737SAbhijeet Joglekar pci_set_master(pdev);
6665df6d737SAbhijeet Joglekar
6675df6d737SAbhijeet Joglekar /* Query PCI controller on system for DMA addressing
668b559b99aSKaran Tilak Kumar * limitation for the device. Try 47-bit first, and
669b559b99aSKaran Tilak Kumar * fail to 32-bit. Cisco VIC supports 47 bits only.
6705df6d737SAbhijeet Joglekar */
671b559b99aSKaran Tilak Kumar err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(47));
6725df6d737SAbhijeet Joglekar if (err) {
6737f9b0f77SChristoph Hellwig err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
6745df6d737SAbhijeet Joglekar if (err) {
6755df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
6765df6d737SAbhijeet Joglekar "No usable DMA configuration "
6775df6d737SAbhijeet Joglekar "aborting\n");
6785df6d737SAbhijeet Joglekar goto err_out_release_regions;
6795df6d737SAbhijeet Joglekar }
6805df6d737SAbhijeet Joglekar }
6815df6d737SAbhijeet Joglekar
6825df6d737SAbhijeet Joglekar /* Map vNIC resources from BAR0 */
6835df6d737SAbhijeet Joglekar if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
6845df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
6855df6d737SAbhijeet Joglekar "BAR0 not memory-map'able, aborting.\n");
6865df6d737SAbhijeet Joglekar err = -ENODEV;
6875df6d737SAbhijeet Joglekar goto err_out_release_regions;
6885df6d737SAbhijeet Joglekar }
6895df6d737SAbhijeet Joglekar
6905df6d737SAbhijeet Joglekar fnic->bar0.vaddr = pci_iomap(pdev, 0, 0);
6915df6d737SAbhijeet Joglekar fnic->bar0.bus_addr = pci_resource_start(pdev, 0);
6925df6d737SAbhijeet Joglekar fnic->bar0.len = pci_resource_len(pdev, 0);
6935df6d737SAbhijeet Joglekar
6945df6d737SAbhijeet Joglekar if (!fnic->bar0.vaddr) {
6955df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
6965df6d737SAbhijeet Joglekar "Cannot memory-map BAR0 res hdr, "
6975df6d737SAbhijeet Joglekar "aborting.\n");
6985df6d737SAbhijeet Joglekar err = -ENODEV;
6995df6d737SAbhijeet Joglekar goto err_out_release_regions;
7005df6d737SAbhijeet Joglekar }
7015df6d737SAbhijeet Joglekar
7025df6d737SAbhijeet Joglekar fnic->vdev = vnic_dev_register(NULL, fnic, pdev, &fnic->bar0);
7035df6d737SAbhijeet Joglekar if (!fnic->vdev) {
7045df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
7055df6d737SAbhijeet Joglekar "vNIC registration failed, "
7065df6d737SAbhijeet Joglekar "aborting.\n");
7075df6d737SAbhijeet Joglekar err = -ENODEV;
7085df6d737SAbhijeet Joglekar goto err_out_iounmap;
7095df6d737SAbhijeet Joglekar }
7105df6d737SAbhijeet Joglekar
711e119d14cSSatish Kharat err = vnic_dev_cmd_init(fnic->vdev);
712e119d14cSSatish Kharat if (err) {
713e119d14cSSatish Kharat shost_printk(KERN_ERR, fnic->lport->host,
714e119d14cSSatish Kharat "vnic_dev_cmd_init() returns %d, aborting\n",
715e119d14cSSatish Kharat err);
716e119d14cSSatish Kharat goto err_out_vnic_unregister;
717e119d14cSSatish Kharat }
718e119d14cSSatish Kharat
7195df6d737SAbhijeet Joglekar err = fnic_dev_wait(fnic->vdev, vnic_dev_open,
72068e3cc02SSatish Kharat vnic_dev_open_done, CMD_OPENF_RQ_ENABLE_THEN_POST);
7215df6d737SAbhijeet Joglekar if (err) {
7225df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
7235df6d737SAbhijeet Joglekar "vNIC dev open failed, aborting.\n");
724e119d14cSSatish Kharat goto err_out_dev_cmd_deinit;
7255df6d737SAbhijeet Joglekar }
7265df6d737SAbhijeet Joglekar
7275df6d737SAbhijeet Joglekar err = vnic_dev_init(fnic->vdev, 0);
7285df6d737SAbhijeet Joglekar if (err) {
7295df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
7305df6d737SAbhijeet Joglekar "vNIC dev init failed, aborting.\n");
7315df6d737SAbhijeet Joglekar goto err_out_dev_close;
7325df6d737SAbhijeet Joglekar }
7335df6d737SAbhijeet Joglekar
73478112e55SJoe Eykholt err = vnic_dev_mac_addr(fnic->vdev, fnic->ctlr.ctl_src_addr);
7355df6d737SAbhijeet Joglekar if (err) {
7365df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
7375df6d737SAbhijeet Joglekar "vNIC get MAC addr failed \n");
7385df6d737SAbhijeet Joglekar goto err_out_dev_close;
7395df6d737SAbhijeet Joglekar }
74078112e55SJoe Eykholt /* set data_src for point-to-point mode and to keep it non-zero */
74178112e55SJoe Eykholt memcpy(fnic->data_src_addr, fnic->ctlr.ctl_src_addr, ETH_ALEN);
7425df6d737SAbhijeet Joglekar
7435df6d737SAbhijeet Joglekar /* Get vNIC configuration */
7445df6d737SAbhijeet Joglekar err = fnic_get_vnic_config(fnic);
7455df6d737SAbhijeet Joglekar if (err) {
7465df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
7475df6d737SAbhijeet Joglekar "Get vNIC configuration failed, "
7485df6d737SAbhijeet Joglekar "aborting.\n");
7495df6d737SAbhijeet Joglekar goto err_out_dev_close;
7505df6d737SAbhijeet Joglekar }
751fc85799eSHiral Patel
75252f6e196SKaran Tilak Kumar /* Setup PCI resources */
75352f6e196SKaran Tilak Kumar pci_set_drvdata(pdev, fnic);
7545df6d737SAbhijeet Joglekar
7555df6d737SAbhijeet Joglekar fnic_get_res_counts(fnic);
7565df6d737SAbhijeet Joglekar
7575df6d737SAbhijeet Joglekar err = fnic_set_intr_mode(fnic);
7585df6d737SAbhijeet Joglekar if (err) {
7595df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
7605df6d737SAbhijeet Joglekar "Failed to set intr mode, "
7615df6d737SAbhijeet Joglekar "aborting.\n");
7625df6d737SAbhijeet Joglekar goto err_out_dev_close;
7635df6d737SAbhijeet Joglekar }
7645df6d737SAbhijeet Joglekar
7655df6d737SAbhijeet Joglekar err = fnic_alloc_vnic_resources(fnic);
7665df6d737SAbhijeet Joglekar if (err) {
7675df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
7685df6d737SAbhijeet Joglekar "Failed to alloc vNIC resources, "
7695df6d737SAbhijeet Joglekar "aborting.\n");
7702e76f767SAbhijeet Joglekar goto err_out_clear_intr;
7715df6d737SAbhijeet Joglekar }
7725df6d737SAbhijeet Joglekar
77352f6e196SKaran Tilak Kumar fnic_scsi_drv_init(fnic);
77452f6e196SKaran Tilak Kumar
77552f6e196SKaran Tilak Kumar for (hwq = 0; hwq < fnic->wq_copy_count; hwq++) {
77652f6e196SKaran Tilak Kumar fnic->sw_copy_wq[hwq].ioreq_table_size = fnic->fnic_max_tag_id;
77752f6e196SKaran Tilak Kumar fnic->sw_copy_wq[hwq].io_req_table =
77852f6e196SKaran Tilak Kumar kzalloc((fnic->sw_copy_wq[hwq].ioreq_table_size + 1) *
77952f6e196SKaran Tilak Kumar sizeof(struct fnic_io_req *), GFP_KERNEL);
78052f6e196SKaran Tilak Kumar }
78152f6e196SKaran Tilak Kumar shost_printk(KERN_INFO, fnic->lport->host, "fnic copy wqs: %d, Q0 ioreq table size: %d\n",
78252f6e196SKaran Tilak Kumar fnic->wq_copy_count, fnic->sw_copy_wq[0].ioreq_table_size);
7835df6d737SAbhijeet Joglekar
7845df6d737SAbhijeet Joglekar /* initialize all fnic locks */
7855df6d737SAbhijeet Joglekar spin_lock_init(&fnic->fnic_lock);
7865df6d737SAbhijeet Joglekar
7875df6d737SAbhijeet Joglekar for (i = 0; i < FNIC_WQ_MAX; i++)
7885df6d737SAbhijeet Joglekar spin_lock_init(&fnic->wq_lock[i]);
7895df6d737SAbhijeet Joglekar
7905df6d737SAbhijeet Joglekar for (i = 0; i < FNIC_WQ_COPY_MAX; i++) {
7915df6d737SAbhijeet Joglekar spin_lock_init(&fnic->wq_copy_lock[i]);
7925df6d737SAbhijeet Joglekar fnic->wq_copy_desc_low[i] = DESC_CLEAN_LOW_WATERMARK;
7935df6d737SAbhijeet Joglekar fnic->fw_ack_recd[i] = 0;
7945df6d737SAbhijeet Joglekar fnic->fw_ack_index[i] = -1;
7955df6d737SAbhijeet Joglekar }
7965df6d737SAbhijeet Joglekar
797d4fc94feSZhang Changzhong err = -ENOMEM;
7985df6d737SAbhijeet Joglekar fnic->io_req_pool = mempool_create_slab_pool(2, fnic_io_req_cache);
7995df6d737SAbhijeet Joglekar if (!fnic->io_req_pool)
8005df6d737SAbhijeet Joglekar goto err_out_free_resources;
8015df6d737SAbhijeet Joglekar
8020c79c742SAbhijeet Joglekar pool = mempool_create_slab_pool(2, fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]);
8035df6d737SAbhijeet Joglekar if (!pool)
8045df6d737SAbhijeet Joglekar goto err_out_free_ioreq_pool;
8055df6d737SAbhijeet Joglekar fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT] = pool;
8065df6d737SAbhijeet Joglekar
8070c79c742SAbhijeet Joglekar pool = mempool_create_slab_pool(2, fnic_sgl_cache[FNIC_SGL_CACHE_MAX]);
8085df6d737SAbhijeet Joglekar if (!pool)
8095df6d737SAbhijeet Joglekar goto err_out_free_dflt_pool;
8105df6d737SAbhijeet Joglekar fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX] = pool;
8115df6d737SAbhijeet Joglekar
8125df6d737SAbhijeet Joglekar /* setup vlan config, hw inserts vlan header */
8135df6d737SAbhijeet Joglekar fnic->vlan_hw_insert = 1;
8145df6d737SAbhijeet Joglekar fnic->vlan_id = 0;
8155df6d737SAbhijeet Joglekar
81678112e55SJoe Eykholt /* Initialize the FIP fcoe_ctrl struct */
81778112e55SJoe Eykholt fnic->ctlr.send = fnic_eth_send;
81878112e55SJoe Eykholt fnic->ctlr.update_mac = fnic_update_mac;
81978112e55SJoe Eykholt fnic->ctlr.get_src_addr = fnic_get_mac;
82078112e55SJoe Eykholt if (fnic->config.flags & VFCF_FIP_CAPABLE) {
82178112e55SJoe Eykholt shost_printk(KERN_INFO, fnic->lport->host,
82278112e55SJoe Eykholt "firmware supports FIP\n");
823aaa5e569SVenkata Siva Vijayendra Bhamidipati /* enable directed and multicast */
824aaa5e569SVenkata Siva Vijayendra Bhamidipati vnic_dev_packet_filter(fnic->vdev, 1, 1, 0, 0, 0);
82578112e55SJoe Eykholt vnic_dev_add_addr(fnic->vdev, FIP_ALL_ENODE_MACS);
82678112e55SJoe Eykholt vnic_dev_add_addr(fnic->vdev, fnic->ctlr.ctl_src_addr);
827d3c995f1SHiral Patel fnic->set_vlan = fnic_set_vlan;
8283d902ac0SJoe Eykholt fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_AUTO);
829e99e88a9SKees Cook timer_setup(&fnic->fip_timer, fnic_fip_notify_timer, 0);
830d3c995f1SHiral Patel spin_lock_init(&fnic->vlans_lock);
831d3c995f1SHiral Patel INIT_WORK(&fnic->fip_frame_work, fnic_handle_fip_frame);
832d3c995f1SHiral Patel INIT_WORK(&fnic->event_work, fnic_handle_event);
833d3c995f1SHiral Patel skb_queue_head_init(&fnic->fip_frame_queue);
834d3c995f1SHiral Patel INIT_LIST_HEAD(&fnic->evlist);
835d3c995f1SHiral Patel INIT_LIST_HEAD(&fnic->vlans);
83678112e55SJoe Eykholt } else {
83778112e55SJoe Eykholt shost_printk(KERN_INFO, fnic->lport->host,
83878112e55SJoe Eykholt "firmware uses non-FIP mode\n");
8393d902ac0SJoe Eykholt fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_NON_FIP);
840c8ff03c6SHiral Shah fnic->ctlr.state = FIP_ST_NON_FIP;
84178112e55SJoe Eykholt }
8425df6d737SAbhijeet Joglekar fnic->state = FNIC_IN_FC_MODE;
8435df6d737SAbhijeet Joglekar
84403298552SHiral Patel atomic_set(&fnic->in_flight, 0);
84503298552SHiral Patel fnic->state_flags = FNIC_FLAGS_NONE;
84603298552SHiral Patel
8475df6d737SAbhijeet Joglekar /* Enable hardware stripping of vlan header on ingress */
8485df6d737SAbhijeet Joglekar fnic_set_nic_config(fnic, 0, 0, 0, 0, 0, 0, 1);
8495df6d737SAbhijeet Joglekar
8505df6d737SAbhijeet Joglekar /* Setup notification buffer area */
8515df6d737SAbhijeet Joglekar err = fnic_notify_set(fnic);
8525df6d737SAbhijeet Joglekar if (err) {
8535df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
8545df6d737SAbhijeet Joglekar "Failed to alloc notify buffer, aborting.\n");
8555df6d737SAbhijeet Joglekar goto err_out_free_max_pool;
8565df6d737SAbhijeet Joglekar }
8575df6d737SAbhijeet Joglekar
8585df6d737SAbhijeet Joglekar /* Setup notify timer when using MSI interrupts */
8595df6d737SAbhijeet Joglekar if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI)
860e99e88a9SKees Cook timer_setup(&fnic->notify_timer, fnic_notify_timer, 0);
8615df6d737SAbhijeet Joglekar
8625df6d737SAbhijeet Joglekar /* allocate RQ buffers and post them to RQ*/
8635df6d737SAbhijeet Joglekar for (i = 0; i < fnic->rq_count; i++) {
8645df6d737SAbhijeet Joglekar err = vnic_rq_fill(&fnic->rq[i], fnic_alloc_rq_frame);
8655df6d737SAbhijeet Joglekar if (err) {
8665df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
8675df6d737SAbhijeet Joglekar "fnic_alloc_rq_frame can't alloc "
8685df6d737SAbhijeet Joglekar "frame\n");
86952f6e196SKaran Tilak Kumar goto err_out_rq_buf;
8705df6d737SAbhijeet Joglekar }
8715df6d737SAbhijeet Joglekar }
8725df6d737SAbhijeet Joglekar
87352f6e196SKaran Tilak Kumar /* Enable all queues */
87452f6e196SKaran Tilak Kumar for (i = 0; i < fnic->raw_wq_count; i++)
87552f6e196SKaran Tilak Kumar vnic_wq_enable(&fnic->wq[i]);
87652f6e196SKaran Tilak Kumar for (i = 0; i < fnic->rq_count; i++) {
87752f6e196SKaran Tilak Kumar if (!ioread32(&fnic->rq[i].ctrl->enable))
87852f6e196SKaran Tilak Kumar vnic_rq_enable(&fnic->rq[i]);
87952f6e196SKaran Tilak Kumar }
88052f6e196SKaran Tilak Kumar for (i = 0; i < fnic->wq_copy_count; i++)
88152f6e196SKaran Tilak Kumar vnic_wq_copy_enable(&fnic->hw_copy_wq[i]);
88252f6e196SKaran Tilak Kumar
88352f6e196SKaran Tilak Kumar err = fnic_request_intr(fnic);
88452f6e196SKaran Tilak Kumar if (err) {
88552f6e196SKaran Tilak Kumar shost_printk(KERN_ERR, fnic->lport->host,
88652f6e196SKaran Tilak Kumar "Unable to request irq.\n");
88752f6e196SKaran Tilak Kumar goto err_out_request_intr;
88852f6e196SKaran Tilak Kumar }
88952f6e196SKaran Tilak Kumar
8905df6d737SAbhijeet Joglekar /*
8915df6d737SAbhijeet Joglekar * Initialization done with PCI system, hardware, firmware.
8925df6d737SAbhijeet Joglekar * Add host to SCSI
8935df6d737SAbhijeet Joglekar */
8945df6d737SAbhijeet Joglekar err = scsi_add_host(lp->host, &pdev->dev);
8955df6d737SAbhijeet Joglekar if (err) {
8965df6d737SAbhijeet Joglekar shost_printk(KERN_ERR, fnic->lport->host,
8975df6d737SAbhijeet Joglekar "fnic: scsi_add_host failed...exiting\n");
89852f6e196SKaran Tilak Kumar goto err_out_scsi_add_host;
8995df6d737SAbhijeet Joglekar }
9005df6d737SAbhijeet Joglekar
90152f6e196SKaran Tilak Kumar
9025df6d737SAbhijeet Joglekar /* Start local port initiatialization */
9035df6d737SAbhijeet Joglekar
9045df6d737SAbhijeet Joglekar lp->link_up = 0;
9055df6d737SAbhijeet Joglekar
9065df6d737SAbhijeet Joglekar lp->max_retry_count = fnic->config.flogi_retries;
907a3666955SAbhijeet Joglekar lp->max_rport_retry_count = fnic->config.plogi_retries;
9085df6d737SAbhijeet Joglekar lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
9095df6d737SAbhijeet Joglekar FCP_SPPF_CONF_COMPL);
9105df6d737SAbhijeet Joglekar if (fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR)
9115df6d737SAbhijeet Joglekar lp->service_params |= FCP_SPPF_RETRY;
9125df6d737SAbhijeet Joglekar
9135df6d737SAbhijeet Joglekar lp->boot_time = jiffies;
9145df6d737SAbhijeet Joglekar lp->e_d_tov = fnic->config.ed_tov;
9155df6d737SAbhijeet Joglekar lp->r_a_tov = fnic->config.ra_tov;
9165df6d737SAbhijeet Joglekar lp->link_supported_speeds = FC_PORTSPEED_10GBIT;
9175df6d737SAbhijeet Joglekar fc_set_wwnn(lp, fnic->config.node_wwn);
9185df6d737SAbhijeet Joglekar fc_set_wwpn(lp, fnic->config.port_wwn);
9195df6d737SAbhijeet Joglekar
920e10f8c66SJoe Eykholt fcoe_libfc_config(lp, &fnic->ctlr, &fnic_transport_template, 0);
9215df6d737SAbhijeet Joglekar
92252ff878cSVasu Dev if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START,
92352ff878cSVasu Dev FCPIO_HOST_EXCH_RANGE_END, NULL)) {
92452ff878cSVasu Dev err = -ENOMEM;
92552f6e196SKaran Tilak Kumar goto err_out_fc_exch_mgr_alloc;
92652ff878cSVasu Dev }
92752ff878cSVasu Dev
928c693a71dSVenkata Siva Vijayendra Bhamidipati fc_lport_init_stats(lp);
9291adee040SNarsimhulu Musini fnic->stats_reset_time = jiffies;
930c693a71dSVenkata Siva Vijayendra Bhamidipati
9315df6d737SAbhijeet Joglekar fc_lport_config(lp);
9325df6d737SAbhijeet Joglekar
9335df6d737SAbhijeet Joglekar if (fc_set_mfs(lp, fnic->config.maxdatafieldsize +
9345df6d737SAbhijeet Joglekar sizeof(struct fc_frame_header))) {
9355df6d737SAbhijeet Joglekar err = -EINVAL;
9365df6d737SAbhijeet Joglekar goto err_out_free_exch_mgr;
9375df6d737SAbhijeet Joglekar }
9385df6d737SAbhijeet Joglekar fc_host_maxframe_size(lp->host) = lp->mfs;
93948586820SMike Christie fc_host_dev_loss_tmo(lp->host) = fnic->config.port_down_timeout / 1000;
9405df6d737SAbhijeet Joglekar
9415df6d737SAbhijeet Joglekar sprintf(fc_host_symbolic_name(lp->host),
9425df6d737SAbhijeet Joglekar DRV_NAME " v" DRV_VERSION " over %s", fnic->name);
9435df6d737SAbhijeet Joglekar
9445df6d737SAbhijeet Joglekar spin_lock_irqsave(&fnic_list_lock, flags);
9455df6d737SAbhijeet Joglekar list_add_tail(&fnic->list, &fnic_list);
9465df6d737SAbhijeet Joglekar spin_unlock_irqrestore(&fnic_list_lock, flags);
9475df6d737SAbhijeet Joglekar
9485df6d737SAbhijeet Joglekar INIT_WORK(&fnic->link_work, fnic_handle_link);
9495df6d737SAbhijeet Joglekar INIT_WORK(&fnic->frame_work, fnic_handle_frame);
950*f30e5f77SMartin Wilck INIT_WORK(&fnic->flush_work, fnic_flush_tx);
9515df6d737SAbhijeet Joglekar skb_queue_head_init(&fnic->frame_queue);
95278112e55SJoe Eykholt skb_queue_head_init(&fnic->tx_queue);
9535df6d737SAbhijeet Joglekar
9545df6d737SAbhijeet Joglekar fc_fabric_login(lp);
9555df6d737SAbhijeet Joglekar
956120dbfd9SSatish Kharat vnic_dev_enable(fnic->vdev);
957120dbfd9SSatish Kharat
9585df6d737SAbhijeet Joglekar for (i = 0; i < fnic->intr_count; i++)
9595df6d737SAbhijeet Joglekar vnic_intr_unmask(&fnic->intr[i]);
9605df6d737SAbhijeet Joglekar
9615df6d737SAbhijeet Joglekar fnic_notify_timer_start(fnic);
9625df6d737SAbhijeet Joglekar
9635df6d737SAbhijeet Joglekar return 0;
9645df6d737SAbhijeet Joglekar
9655df6d737SAbhijeet Joglekar err_out_free_exch_mgr:
96652ff878cSVasu Dev fc_exch_mgr_free(lp);
96752f6e196SKaran Tilak Kumar err_out_fc_exch_mgr_alloc:
96878112e55SJoe Eykholt fc_remove_host(lp->host);
96978112e55SJoe Eykholt scsi_remove_host(lp->host);
97052f6e196SKaran Tilak Kumar err_out_scsi_add_host:
97152f6e196SKaran Tilak Kumar fnic_free_intr(fnic);
97252f6e196SKaran Tilak Kumar err_out_request_intr:
9735df6d737SAbhijeet Joglekar for (i = 0; i < fnic->rq_count; i++)
9745df6d737SAbhijeet Joglekar vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf);
97552f6e196SKaran Tilak Kumar err_out_rq_buf:
9765df6d737SAbhijeet Joglekar vnic_dev_notify_unset(fnic->vdev);
9775df6d737SAbhijeet Joglekar err_out_free_max_pool:
9785df6d737SAbhijeet Joglekar mempool_destroy(fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX]);
9795df6d737SAbhijeet Joglekar err_out_free_dflt_pool:
9805df6d737SAbhijeet Joglekar mempool_destroy(fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT]);
9815df6d737SAbhijeet Joglekar err_out_free_ioreq_pool:
9825df6d737SAbhijeet Joglekar mempool_destroy(fnic->io_req_pool);
9835df6d737SAbhijeet Joglekar err_out_free_resources:
98452f6e196SKaran Tilak Kumar for (hwq = 0; hwq < fnic->wq_copy_count; hwq++)
98552f6e196SKaran Tilak Kumar kfree(fnic->sw_copy_wq[hwq].io_req_table);
9865df6d737SAbhijeet Joglekar fnic_free_vnic_resources(fnic);
9875df6d737SAbhijeet Joglekar err_out_clear_intr:
9885df6d737SAbhijeet Joglekar fnic_clear_intr_mode(fnic);
9895df6d737SAbhijeet Joglekar err_out_dev_close:
9905df6d737SAbhijeet Joglekar vnic_dev_close(fnic->vdev);
991e119d14cSSatish Kharat err_out_dev_cmd_deinit:
9925df6d737SAbhijeet Joglekar err_out_vnic_unregister:
9935df6d737SAbhijeet Joglekar vnic_dev_unregister(fnic->vdev);
9945df6d737SAbhijeet Joglekar err_out_iounmap:
9955df6d737SAbhijeet Joglekar fnic_iounmap(fnic);
9965df6d737SAbhijeet Joglekar err_out_release_regions:
9975df6d737SAbhijeet Joglekar pci_release_regions(pdev);
9985df6d737SAbhijeet Joglekar err_out_disable_device:
9995df6d737SAbhijeet Joglekar pci_disable_device(pdev);
10005df6d737SAbhijeet Joglekar err_out_free_hba:
100167125b02SHiral Patel fnic_stats_debugfs_remove(fnic);
1002ca008aeeSKaran Tilak Kumar ida_free(&fnic_ida, fnic->fnic_num);
1003ca008aeeSKaran Tilak Kumar err_out_ida_alloc:
10045df6d737SAbhijeet Joglekar scsi_host_put(lp->host);
10055df6d737SAbhijeet Joglekar err_out:
10065df6d737SAbhijeet Joglekar return err;
10075df6d737SAbhijeet Joglekar }
10085df6d737SAbhijeet Joglekar
fnic_remove(struct pci_dev * pdev)10096f039790SGreg Kroah-Hartman static void fnic_remove(struct pci_dev *pdev)
10105df6d737SAbhijeet Joglekar {
10115df6d737SAbhijeet Joglekar struct fnic *fnic = pci_get_drvdata(pdev);
101278112e55SJoe Eykholt struct fc_lport *lp = fnic->lport;
10135df6d737SAbhijeet Joglekar unsigned long flags;
101452f6e196SKaran Tilak Kumar int hwq;
10155df6d737SAbhijeet Joglekar
10165df6d737SAbhijeet Joglekar /*
10175df6d737SAbhijeet Joglekar * Mark state so that the workqueue thread stops forwarding
10185df6d737SAbhijeet Joglekar * received frames and link events to the local port. ISR and
10195df6d737SAbhijeet Joglekar * other threads that can queue work items will also stop
10205df6d737SAbhijeet Joglekar * creating work items on the fnic workqueue
10215df6d737SAbhijeet Joglekar */
10225df6d737SAbhijeet Joglekar spin_lock_irqsave(&fnic->fnic_lock, flags);
10235df6d737SAbhijeet Joglekar fnic->stop_rx_link_events = 1;
10245df6d737SAbhijeet Joglekar spin_unlock_irqrestore(&fnic->fnic_lock, flags);
10255df6d737SAbhijeet Joglekar
10265df6d737SAbhijeet Joglekar if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI)
10275df6d737SAbhijeet Joglekar del_timer_sync(&fnic->notify_timer);
10285df6d737SAbhijeet Joglekar
10295df6d737SAbhijeet Joglekar /*
10305df6d737SAbhijeet Joglekar * Flush the fnic event queue. After this call, there should
10315df6d737SAbhijeet Joglekar * be no event queued for this fnic device in the workqueue
10325df6d737SAbhijeet Joglekar */
10335df6d737SAbhijeet Joglekar flush_workqueue(fnic_event_queue);
10345df6d737SAbhijeet Joglekar skb_queue_purge(&fnic->frame_queue);
103578112e55SJoe Eykholt skb_queue_purge(&fnic->tx_queue);
10365df6d737SAbhijeet Joglekar
1037d3c995f1SHiral Patel if (fnic->config.flags & VFCF_FIP_CAPABLE) {
1038d3c995f1SHiral Patel del_timer_sync(&fnic->fip_timer);
1039d3c995f1SHiral Patel skb_queue_purge(&fnic->fip_frame_queue);
1040d3c995f1SHiral Patel fnic_fcoe_reset_vlans(fnic);
1041d3c995f1SHiral Patel fnic_fcoe_evlist_free(fnic);
1042d3c995f1SHiral Patel }
1043d3c995f1SHiral Patel
10445df6d737SAbhijeet Joglekar /*
10455df6d737SAbhijeet Joglekar * Log off the fabric. This stops all remote ports, dns port,
10465df6d737SAbhijeet Joglekar * logs off the fabric. This flushes all rport, disc, lport work
10475df6d737SAbhijeet Joglekar * before returning
10485df6d737SAbhijeet Joglekar */
10495df6d737SAbhijeet Joglekar fc_fabric_logoff(fnic->lport);
10505df6d737SAbhijeet Joglekar
10515df6d737SAbhijeet Joglekar spin_lock_irqsave(&fnic->fnic_lock, flags);
10525df6d737SAbhijeet Joglekar fnic->in_remove = 1;
10535df6d737SAbhijeet Joglekar spin_unlock_irqrestore(&fnic->fnic_lock, flags);
10545df6d737SAbhijeet Joglekar
105578112e55SJoe Eykholt fcoe_ctlr_destroy(&fnic->ctlr);
105678112e55SJoe Eykholt fc_lport_destroy(lp);
105767125b02SHiral Patel fnic_stats_debugfs_remove(fnic);
10585df6d737SAbhijeet Joglekar
10595df6d737SAbhijeet Joglekar /*
10605df6d737SAbhijeet Joglekar * This stops the fnic device, masks all interrupts. Completed
10615df6d737SAbhijeet Joglekar * CQ entries are drained. Posted WQ/RQ/Copy-WQ entries are
10625df6d737SAbhijeet Joglekar * cleaned up
10635df6d737SAbhijeet Joglekar */
10645df6d737SAbhijeet Joglekar fnic_cleanup(fnic);
10655df6d737SAbhijeet Joglekar
10665df6d737SAbhijeet Joglekar BUG_ON(!skb_queue_empty(&fnic->frame_queue));
106778112e55SJoe Eykholt BUG_ON(!skb_queue_empty(&fnic->tx_queue));
10685df6d737SAbhijeet Joglekar
10695df6d737SAbhijeet Joglekar spin_lock_irqsave(&fnic_list_lock, flags);
10705df6d737SAbhijeet Joglekar list_del(&fnic->list);
10715df6d737SAbhijeet Joglekar spin_unlock_irqrestore(&fnic_list_lock, flags);
10725df6d737SAbhijeet Joglekar
10735df6d737SAbhijeet Joglekar fc_remove_host(fnic->lport->host);
10745df6d737SAbhijeet Joglekar scsi_remove_host(fnic->lport->host);
107552f6e196SKaran Tilak Kumar for (hwq = 0; hwq < fnic->wq_copy_count; hwq++)
107652f6e196SKaran Tilak Kumar kfree(fnic->sw_copy_wq[hwq].io_req_table);
107752ff878cSVasu Dev fc_exch_mgr_free(fnic->lport);
10785df6d737SAbhijeet Joglekar vnic_dev_notify_unset(fnic->vdev);
10795df6d737SAbhijeet Joglekar fnic_free_intr(fnic);
10802e76f767SAbhijeet Joglekar fnic_free_vnic_resources(fnic);
10815df6d737SAbhijeet Joglekar fnic_clear_intr_mode(fnic);
10825df6d737SAbhijeet Joglekar vnic_dev_close(fnic->vdev);
10835df6d737SAbhijeet Joglekar vnic_dev_unregister(fnic->vdev);
10845df6d737SAbhijeet Joglekar fnic_iounmap(fnic);
10855df6d737SAbhijeet Joglekar pci_release_regions(pdev);
10865df6d737SAbhijeet Joglekar pci_disable_device(pdev);
1087ca008aeeSKaran Tilak Kumar ida_free(&fnic_ida, fnic->fnic_num);
108878112e55SJoe Eykholt scsi_host_put(lp->host);
10895df6d737SAbhijeet Joglekar }
10905df6d737SAbhijeet Joglekar
10915df6d737SAbhijeet Joglekar static struct pci_driver fnic_driver = {
10925df6d737SAbhijeet Joglekar .name = DRV_NAME,
10935df6d737SAbhijeet Joglekar .id_table = fnic_id_table,
10945df6d737SAbhijeet Joglekar .probe = fnic_probe,
10956f039790SGreg Kroah-Hartman .remove = fnic_remove,
10965df6d737SAbhijeet Joglekar };
10975df6d737SAbhijeet Joglekar
fnic_init_module(void)10985df6d737SAbhijeet Joglekar static int __init fnic_init_module(void)
10995df6d737SAbhijeet Joglekar {
11005df6d737SAbhijeet Joglekar size_t len;
11015df6d737SAbhijeet Joglekar int err = 0;
11025df6d737SAbhijeet Joglekar
11035df6d737SAbhijeet Joglekar printk(KERN_INFO PFX "%s, ver %s\n", DRV_DESCRIPTION, DRV_VERSION);
11045df6d737SAbhijeet Joglekar
110567125b02SHiral Patel /* Create debugfs entries for fnic */
110667125b02SHiral Patel err = fnic_debugfs_init();
110767125b02SHiral Patel if (err < 0) {
110867125b02SHiral Patel printk(KERN_ERR PFX "Failed to create fnic directory "
110967125b02SHiral Patel "for tracing and stats logging\n");
111067125b02SHiral Patel fnic_debugfs_terminate();
111167125b02SHiral Patel }
111267125b02SHiral Patel
11134d7007b4SHiral Patel /* Allocate memory for trace buffer */
11144d7007b4SHiral Patel err = fnic_trace_buf_init();
11154d7007b4SHiral Patel if (err < 0) {
1116abb14148SHiral Shah printk(KERN_ERR PFX
1117abb14148SHiral Shah "Trace buffer initialization Failed. "
11184d7007b4SHiral Patel "Fnic Tracing utility is disabled\n");
11194d7007b4SHiral Patel fnic_trace_free();
11204d7007b4SHiral Patel }
11214d7007b4SHiral Patel
1122abb14148SHiral Shah /* Allocate memory for fc trace buffer */
1123abb14148SHiral Shah err = fnic_fc_trace_init();
1124abb14148SHiral Shah if (err < 0) {
1125abb14148SHiral Shah printk(KERN_ERR PFX "FC trace buffer initialization Failed "
1126abb14148SHiral Shah "FC frame tracing utility is disabled\n");
1127abb14148SHiral Shah fnic_fc_trace_free();
1128abb14148SHiral Shah }
1129abb14148SHiral Shah
11305df6d737SAbhijeet Joglekar /* Create a cache for allocation of default size sgls */
11315df6d737SAbhijeet Joglekar len = sizeof(struct fnic_dflt_sgl_list);
11325df6d737SAbhijeet Joglekar fnic_sgl_cache[FNIC_SGL_CACHE_DFLT] = kmem_cache_create
11335df6d737SAbhijeet Joglekar ("fnic_sgl_dflt", len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN,
11340c79c742SAbhijeet Joglekar SLAB_HWCACHE_ALIGN,
11355df6d737SAbhijeet Joglekar NULL);
11365df6d737SAbhijeet Joglekar if (!fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]) {
11375df6d737SAbhijeet Joglekar printk(KERN_ERR PFX "failed to create fnic dflt sgl slab\n");
11385df6d737SAbhijeet Joglekar err = -ENOMEM;
11395df6d737SAbhijeet Joglekar goto err_create_fnic_sgl_slab_dflt;
11405df6d737SAbhijeet Joglekar }
11415df6d737SAbhijeet Joglekar
11425df6d737SAbhijeet Joglekar /* Create a cache for allocation of max size sgls*/
11435df6d737SAbhijeet Joglekar len = sizeof(struct fnic_sgl_list);
11445df6d737SAbhijeet Joglekar fnic_sgl_cache[FNIC_SGL_CACHE_MAX] = kmem_cache_create
11455df6d737SAbhijeet Joglekar ("fnic_sgl_max", len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN,
11460c79c742SAbhijeet Joglekar SLAB_HWCACHE_ALIGN,
11475df6d737SAbhijeet Joglekar NULL);
11485df6d737SAbhijeet Joglekar if (!fnic_sgl_cache[FNIC_SGL_CACHE_MAX]) {
11495df6d737SAbhijeet Joglekar printk(KERN_ERR PFX "failed to create fnic max sgl slab\n");
11505df6d737SAbhijeet Joglekar err = -ENOMEM;
11515df6d737SAbhijeet Joglekar goto err_create_fnic_sgl_slab_max;
11525df6d737SAbhijeet Joglekar }
11535df6d737SAbhijeet Joglekar
11545df6d737SAbhijeet Joglekar /* Create a cache of io_req structs for use via mempool */
11555df6d737SAbhijeet Joglekar fnic_io_req_cache = kmem_cache_create("fnic_io_req",
11565df6d737SAbhijeet Joglekar sizeof(struct fnic_io_req),
11575df6d737SAbhijeet Joglekar 0, SLAB_HWCACHE_ALIGN, NULL);
11585df6d737SAbhijeet Joglekar if (!fnic_io_req_cache) {
11595df6d737SAbhijeet Joglekar printk(KERN_ERR PFX "failed to create fnic io_req slab\n");
11605df6d737SAbhijeet Joglekar err = -ENOMEM;
11615df6d737SAbhijeet Joglekar goto err_create_fnic_ioreq_slab;
11625df6d737SAbhijeet Joglekar }
11635df6d737SAbhijeet Joglekar
1164b97c0741SBart Van Assche fnic_event_queue =
1165b97c0741SBart Van Assche alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, "fnic_event_wq");
11665df6d737SAbhijeet Joglekar if (!fnic_event_queue) {
11675df6d737SAbhijeet Joglekar printk(KERN_ERR PFX "fnic work queue create failed\n");
11685df6d737SAbhijeet Joglekar err = -ENOMEM;
11695df6d737SAbhijeet Joglekar goto err_create_fnic_workq;
11705df6d737SAbhijeet Joglekar }
11715df6d737SAbhijeet Joglekar
1172b97c0741SBart Van Assche fnic_fip_queue =
1173b97c0741SBart Van Assche alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, "fnic_fip_q");
1174e09056b2SChris Leech if (!fnic_fip_queue) {
1175e09056b2SChris Leech printk(KERN_ERR PFX "fnic FIP work queue create failed\n");
1176e09056b2SChris Leech err = -ENOMEM;
1177e09056b2SChris Leech goto err_create_fip_workq;
1178e09056b2SChris Leech }
1179e09056b2SChris Leech
11805df6d737SAbhijeet Joglekar fnic_fc_transport = fc_attach_transport(&fnic_fc_functions);
11815df6d737SAbhijeet Joglekar if (!fnic_fc_transport) {
11825df6d737SAbhijeet Joglekar printk(KERN_ERR PFX "fc_attach_transport error\n");
11835df6d737SAbhijeet Joglekar err = -ENOMEM;
11845df6d737SAbhijeet Joglekar goto err_fc_transport;
11855df6d737SAbhijeet Joglekar }
11865df6d737SAbhijeet Joglekar
11875df6d737SAbhijeet Joglekar /* register the driver with PCI system */
11885df6d737SAbhijeet Joglekar err = pci_register_driver(&fnic_driver);
11895df6d737SAbhijeet Joglekar if (err < 0) {
11905df6d737SAbhijeet Joglekar printk(KERN_ERR PFX "pci register error\n");
11915df6d737SAbhijeet Joglekar goto err_pci_register;
11925df6d737SAbhijeet Joglekar }
11935df6d737SAbhijeet Joglekar return err;
11945df6d737SAbhijeet Joglekar
11955df6d737SAbhijeet Joglekar err_pci_register:
11965df6d737SAbhijeet Joglekar fc_release_transport(fnic_fc_transport);
11975df6d737SAbhijeet Joglekar err_fc_transport:
1198e09056b2SChris Leech destroy_workqueue(fnic_fip_queue);
1199e09056b2SChris Leech err_create_fip_workq:
12005df6d737SAbhijeet Joglekar destroy_workqueue(fnic_event_queue);
12015df6d737SAbhijeet Joglekar err_create_fnic_workq:
12025df6d737SAbhijeet Joglekar kmem_cache_destroy(fnic_io_req_cache);
12035df6d737SAbhijeet Joglekar err_create_fnic_ioreq_slab:
12045df6d737SAbhijeet Joglekar kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_MAX]);
12055df6d737SAbhijeet Joglekar err_create_fnic_sgl_slab_max:
12065df6d737SAbhijeet Joglekar kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]);
12075df6d737SAbhijeet Joglekar err_create_fnic_sgl_slab_dflt:
12084d7007b4SHiral Patel fnic_trace_free();
1209abb14148SHiral Shah fnic_fc_trace_free();
121067125b02SHiral Patel fnic_debugfs_terminate();
12115df6d737SAbhijeet Joglekar return err;
12125df6d737SAbhijeet Joglekar }
12135df6d737SAbhijeet Joglekar
fnic_cleanup_module(void)12145df6d737SAbhijeet Joglekar static void __exit fnic_cleanup_module(void)
12155df6d737SAbhijeet Joglekar {
12165df6d737SAbhijeet Joglekar pci_unregister_driver(&fnic_driver);
12175df6d737SAbhijeet Joglekar destroy_workqueue(fnic_event_queue);
1218671a52f2Sran jianping if (fnic_fip_queue)
1219d3c995f1SHiral Patel destroy_workqueue(fnic_fip_queue);
12205df6d737SAbhijeet Joglekar kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_MAX]);
12215df6d737SAbhijeet Joglekar kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]);
12225df6d737SAbhijeet Joglekar kmem_cache_destroy(fnic_io_req_cache);
12235df6d737SAbhijeet Joglekar fc_release_transport(fnic_fc_transport);
12244d7007b4SHiral Patel fnic_trace_free();
1225abb14148SHiral Shah fnic_fc_trace_free();
122667125b02SHiral Patel fnic_debugfs_terminate();
1227ca008aeeSKaran Tilak Kumar ida_destroy(&fnic_ida);
12285df6d737SAbhijeet Joglekar }
12295df6d737SAbhijeet Joglekar
12305df6d737SAbhijeet Joglekar module_init(fnic_init_module);
12315df6d737SAbhijeet Joglekar module_exit(fnic_cleanup_module);
1232