xref: /freebsd-src/sys/dev/ocs_fc/ocs_pci.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1ef270ab1SKenneth D. Merry /*-
2ef270ab1SKenneth D. Merry  * Copyright (c) 2017 Broadcom. All rights reserved.
3ef270ab1SKenneth D. Merry  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4ef270ab1SKenneth D. Merry  *
5ef270ab1SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
6ef270ab1SKenneth D. Merry  * modification, are permitted provided that the following conditions are met:
7ef270ab1SKenneth D. Merry  *
8ef270ab1SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright notice,
9ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer.
10ef270ab1SKenneth D. Merry  *
11ef270ab1SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright notice,
12ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer in the documentation
13ef270ab1SKenneth D. Merry  *    and/or other materials provided with the distribution.
14ef270ab1SKenneth D. Merry  *
15ef270ab1SKenneth D. Merry  * 3. Neither the name of the copyright holder nor the names of its contributors
16ef270ab1SKenneth D. Merry  *    may be used to endorse or promote products derived from this software
17ef270ab1SKenneth D. Merry  *    without specific prior written permission.
18ef270ab1SKenneth D. Merry  *
19ef270ab1SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20ef270ab1SKenneth D. Merry  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21ef270ab1SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22ef270ab1SKenneth D. Merry  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23ef270ab1SKenneth D. Merry  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24ef270ab1SKenneth D. Merry  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25ef270ab1SKenneth D. Merry  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26ef270ab1SKenneth D. Merry  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27ef270ab1SKenneth D. Merry  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28ef270ab1SKenneth D. Merry  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29ef270ab1SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGE.
30ef270ab1SKenneth D. Merry  */
31ef270ab1SKenneth D. Merry 
32ef270ab1SKenneth D. Merry #define OCS_COPYRIGHT "Copyright (C) 2017 Broadcom. All rights reserved."
33ef270ab1SKenneth D. Merry 
34ef270ab1SKenneth D. Merry /**
35ef270ab1SKenneth D. Merry  * @file
36ef270ab1SKenneth D. Merry  * Implementation of required FreeBSD PCI interface functions
37ef270ab1SKenneth D. Merry  */
38ef270ab1SKenneth D. Merry 
39ef270ab1SKenneth D. Merry #include "ocs.h"
40ef270ab1SKenneth D. Merry #include "version.h"
41ef270ab1SKenneth D. Merry #include <sys/sysctl.h>
42ef270ab1SKenneth D. Merry #include <sys/malloc.h>
43ef270ab1SKenneth D. Merry 
44ef270ab1SKenneth D. Merry static MALLOC_DEFINE(M_OCS, "OCS", "OneCore Storage data");
45ef270ab1SKenneth D. Merry 
46ef270ab1SKenneth D. Merry #include <dev/pci/pcireg.h>
47ef270ab1SKenneth D. Merry #include <dev/pci/pcivar.h>
48ef270ab1SKenneth D. Merry 
49ef270ab1SKenneth D. Merry #include <machine/bus.h>
50ef270ab1SKenneth D. Merry 
51ef270ab1SKenneth D. Merry /**
52ef270ab1SKenneth D. Merry  * Tunable parameters for transport
53ef270ab1SKenneth D. Merry  */
54ef270ab1SKenneth D. Merry int logmask = 0;
55ef270ab1SKenneth D. Merry int ctrlmask = 2;
56ef270ab1SKenneth D. Merry int logdest = 1;
57ef270ab1SKenneth D. Merry int loglevel = LOG_INFO;
58ef270ab1SKenneth D. Merry int ramlog_size = 1*1024*1024;
59ef270ab1SKenneth D. Merry int ddump_saved_size = 0;
60ef270ab1SKenneth D. Merry static const char *queue_topology = "eq cq rq cq mq $nulp($nwq(cq wq:ulp=$rpt1)) cq wq:len=256:class=1";
61ef270ab1SKenneth D. Merry 
62ef270ab1SKenneth D. Merry static void ocs_release_bus(struct ocs_softc *);
63ef270ab1SKenneth D. Merry static int32_t ocs_intr_alloc(struct ocs_softc *);
64ef270ab1SKenneth D. Merry static int32_t ocs_intr_setup(struct ocs_softc *);
65ef270ab1SKenneth D. Merry static int32_t ocs_intr_teardown(struct ocs_softc *);
66ef270ab1SKenneth D. Merry static int ocs_pci_intx_filter(void *);
67ef270ab1SKenneth D. Merry static void ocs_pci_intr(void *);
68ef270ab1SKenneth D. Merry static int32_t ocs_init_dma_tag(struct ocs_softc *ocs);
69ef270ab1SKenneth D. Merry 
70ef270ab1SKenneth D. Merry static int32_t ocs_setup_fcports(ocs_t *ocs);
71ef270ab1SKenneth D. Merry 
72ef270ab1SKenneth D. Merry ocs_t *ocs_devices[MAX_OCS_DEVICES];
73ef270ab1SKenneth D. Merry 
74ef270ab1SKenneth D. Merry /**
75ef270ab1SKenneth D. Merry  * @brief Check support for the given device
76ef270ab1SKenneth D. Merry  *
77ef270ab1SKenneth D. Merry  * Determine support for a given device by examining the PCI vendor and
78ef270ab1SKenneth D. Merry  * device IDs
79ef270ab1SKenneth D. Merry  *
80ef270ab1SKenneth D. Merry  * @param dev device abstraction
81ef270ab1SKenneth D. Merry  *
82ef270ab1SKenneth D. Merry  * @return 0 if device is supported, ENXIO otherwise
83ef270ab1SKenneth D. Merry  */
84ef270ab1SKenneth D. Merry static int
ocs_pci_probe(device_t dev)85ef270ab1SKenneth D. Merry ocs_pci_probe(device_t dev)
86ef270ab1SKenneth D. Merry {
87ef270ab1SKenneth D. Merry 	char	*desc = NULL;
88ef270ab1SKenneth D. Merry 
89ef270ab1SKenneth D. Merry 	if (pci_get_vendor(dev) != PCI_VENDOR_EMULEX) {
90ef270ab1SKenneth D. Merry 		return ENXIO;
91ef270ab1SKenneth D. Merry 	}
92ef270ab1SKenneth D. Merry 
93ef270ab1SKenneth D. Merry 	switch (pci_get_device(dev)) {
94ef270ab1SKenneth D. Merry 	case PCI_PRODUCT_EMULEX_OCE16001:
95ef270ab1SKenneth D. Merry 		desc = "Emulex LightPulse FC Adapter";
96ef270ab1SKenneth D. Merry 		break;
97ef270ab1SKenneth D. Merry 	case PCI_PRODUCT_EMULEX_LPE31004:
98ef270ab1SKenneth D. Merry 		desc = "Emulex LightPulse FC Adapter";
99ef270ab1SKenneth D. Merry 		break;
100ef270ab1SKenneth D. Merry 	case PCI_PRODUCT_EMULEX_OCE50102:
101ef270ab1SKenneth D. Merry 		desc = "Emulex LightPulse 10GbE FCoE/NIC Adapter";
102ef270ab1SKenneth D. Merry 		break;
1033bf42363SRam Kishore Vegesna 	case PCI_PRODUCT_EMULEX_LANCER_G7:
1043bf42363SRam Kishore Vegesna 		desc = "Emulex LightPulse G7 FC Adapter";
1053bf42363SRam Kishore Vegesna 		break;
106ef270ab1SKenneth D. Merry 	default:
107ef270ab1SKenneth D. Merry 		return ENXIO;
108ef270ab1SKenneth D. Merry 	}
109ef270ab1SKenneth D. Merry 
110ef270ab1SKenneth D. Merry 	device_set_desc(dev, desc);
111ef270ab1SKenneth D. Merry 
112ef270ab1SKenneth D. Merry 	return BUS_PROBE_DEFAULT;
113ef270ab1SKenneth D. Merry }
114ef270ab1SKenneth D. Merry 
115ef270ab1SKenneth D. Merry static int
ocs_map_g7_bars(device_t dev,struct ocs_softc * ocs)1163bf42363SRam Kishore Vegesna ocs_map_g7_bars(device_t dev, struct ocs_softc *ocs)
1173bf42363SRam Kishore Vegesna {
1183bf42363SRam Kishore Vegesna 	int i, r;
1193bf42363SRam Kishore Vegesna 	uint32_t  val = 0;
1203bf42363SRam Kishore Vegesna 
1213bf42363SRam Kishore Vegesna 	for (i = 0, r = 0; i < PCI_MAX_BAR; i++) {
1223bf42363SRam Kishore Vegesna 		val = pci_read_config(dev, PCIR_BAR(i), 4);
1233bf42363SRam Kishore Vegesna 		if (!PCI_BAR_MEM(val)) {
1243bf42363SRam Kishore Vegesna 			continue;
1253bf42363SRam Kishore Vegesna                 }
1263bf42363SRam Kishore Vegesna                 if (!(val & PCIM_BAR_MEM_BASE)) {
1273bf42363SRam Kishore Vegesna 			/* no address */
1283bf42363SRam Kishore Vegesna 			continue;
1293bf42363SRam Kishore Vegesna 		}
1303bf42363SRam Kishore Vegesna 		ocs->reg[r].rid = PCIR_BAR(i);
1313bf42363SRam Kishore Vegesna 		ocs->reg[r].res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
1323bf42363SRam Kishore Vegesna 				&ocs->reg[r].rid, RF_ACTIVE);
1333bf42363SRam Kishore Vegesna 		if (ocs->reg[r].res) {
1343bf42363SRam Kishore Vegesna 			ocs->reg[r].btag = rman_get_bustag(ocs->reg[r].res);
1353bf42363SRam Kishore Vegesna 			ocs->reg[r].bhandle = rman_get_bushandle(ocs->reg[r].res);
1363bf42363SRam Kishore Vegesna 			r++;
1373bf42363SRam Kishore Vegesna 		} else {
1383bf42363SRam Kishore Vegesna 			device_printf(dev, "bus_alloc_resource failed rid=%#x\n",
1393bf42363SRam Kishore Vegesna 			ocs->reg[r].rid);
1403bf42363SRam Kishore Vegesna 			ocs_release_bus(ocs);
1413bf42363SRam Kishore Vegesna 			return ENXIO;
1423bf42363SRam Kishore Vegesna 		}
1433bf42363SRam Kishore Vegesna 
1443bf42363SRam Kishore Vegesna 		/*
1453bf42363SRam Kishore Vegesna 		 * If the 64-bit attribute is set, both this BAR and the
1463bf42363SRam Kishore Vegesna 		 * next form the complete address. Skip processing the
1473bf42363SRam Kishore Vegesna 		 * next BAR.
1483bf42363SRam Kishore Vegesna 		 */
1493bf42363SRam Kishore Vegesna 		if (val & PCIM_BAR_MEM_64) {
1503bf42363SRam Kishore Vegesna 			i++;
1513bf42363SRam Kishore Vegesna 		}
1523bf42363SRam Kishore Vegesna 	}
1533bf42363SRam Kishore Vegesna 
1543bf42363SRam Kishore Vegesna 	return 0;
1553bf42363SRam Kishore Vegesna }
1563bf42363SRam Kishore Vegesna 
1573bf42363SRam Kishore Vegesna static int
ocs_map_bars(device_t dev,struct ocs_softc * ocs)158ef270ab1SKenneth D. Merry ocs_map_bars(device_t dev, struct ocs_softc *ocs)
159ef270ab1SKenneth D. Merry {
160ef270ab1SKenneth D. Merry 	/*
161ef270ab1SKenneth D. Merry 	 * Map PCI BAR0 register into the CPU's space.
162ef270ab1SKenneth D. Merry 	 */
163ef270ab1SKenneth D. Merry 
164ef270ab1SKenneth D. Merry 	ocs->reg[0].rid = PCIR_BAR(PCI_64BIT_BAR0);
165ef270ab1SKenneth D. Merry 	ocs->reg[0].res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
166ef270ab1SKenneth D. Merry 			&ocs->reg[0].rid, RF_ACTIVE);
167ef270ab1SKenneth D. Merry 
168ef270ab1SKenneth D. Merry 	if (ocs->reg[0].res == NULL) {
169ef270ab1SKenneth D. Merry 		device_printf(dev, "bus_alloc_resource failed rid=%#x\n",
170ef270ab1SKenneth D. Merry 				ocs->reg[0].rid);
171ef270ab1SKenneth D. Merry 		return ENXIO;
172ef270ab1SKenneth D. Merry 	}
173ef270ab1SKenneth D. Merry 
174ef270ab1SKenneth D. Merry 	ocs->reg[0].btag = rman_get_bustag(ocs->reg[0].res);
175ef270ab1SKenneth D. Merry 	ocs->reg[0].bhandle = rman_get_bushandle(ocs->reg[0].res);
176ef270ab1SKenneth D. Merry 	return 0;
177ef270ab1SKenneth D. Merry }
178ef270ab1SKenneth D. Merry 
179ef270ab1SKenneth D. Merry static int
ocs_setup_params(struct ocs_softc * ocs)180ef270ab1SKenneth D. Merry ocs_setup_params(struct ocs_softc *ocs)
181ef270ab1SKenneth D. Merry {
182ef270ab1SKenneth D. Merry 	int32_t	i = 0;
183ef270ab1SKenneth D. Merry 	const char	*hw_war_version;
184ef270ab1SKenneth D. Merry 	/* Setup tunable parameters */
185ef270ab1SKenneth D. Merry 	ocs->ctrlmask = ctrlmask;
186ef270ab1SKenneth D. Merry 	ocs->speed = 0;
187ef270ab1SKenneth D. Merry 	ocs->topology = 0;
188ef270ab1SKenneth D. Merry 	ocs->ethernet_license = 0;
189ef270ab1SKenneth D. Merry 	ocs->num_scsi_ios = 8192;
190ef270ab1SKenneth D. Merry 	ocs->enable_hlm = 0;
191ef270ab1SKenneth D. Merry 	ocs->hlm_group_size = 8;
192ef270ab1SKenneth D. Merry 	ocs->logmask = logmask;
193ef270ab1SKenneth D. Merry 
194ef270ab1SKenneth D. Merry 	ocs->config_tgt = FALSE;
195ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
196ef270ab1SKenneth D. Merry 					"target", &i)) {
197ef270ab1SKenneth D. Merry 		if (1 == i) {
198ef270ab1SKenneth D. Merry 			ocs->config_tgt = TRUE;
199ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "Enabling target\n");
200ef270ab1SKenneth D. Merry 		}
201ef270ab1SKenneth D. Merry 	}
202ef270ab1SKenneth D. Merry 
203ef270ab1SKenneth D. Merry 	ocs->config_ini = TRUE;
204ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
205ef270ab1SKenneth D. Merry 					"initiator", &i)) {
206ef270ab1SKenneth D. Merry 		if (0 == i) {
207ef270ab1SKenneth D. Merry 			ocs->config_ini = FALSE;
208ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "Disabling initiator\n");
209ef270ab1SKenneth D. Merry 		}
210ef270ab1SKenneth D. Merry 	}
211ef270ab1SKenneth D. Merry 	ocs->enable_ini = ocs->config_ini;
212ef270ab1SKenneth D. Merry 
213ef270ab1SKenneth D. Merry 	if (!ocs->config_ini && !ocs->config_tgt) {
214ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "Unsupported, both initiator and target mode disabled.\n");
215ef270ab1SKenneth D. Merry 		return 1;
216ef270ab1SKenneth D. Merry         }
217ef270ab1SKenneth D. Merry 
218ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
219ef270ab1SKenneth D. Merry 					"logmask", &logmask)) {
220ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "logmask = %#x\n", logmask);
221ef270ab1SKenneth D. Merry 	}
222ef270ab1SKenneth D. Merry 
223ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
224ef270ab1SKenneth D. Merry 					"logdest", &logdest)) {
225ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "logdest = %#x\n", logdest);
226ef270ab1SKenneth D. Merry 	}
227ef270ab1SKenneth D. Merry 
228ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
229ef270ab1SKenneth D. Merry 					"loglevel", &loglevel)) {
230ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "loglevel = %#x\n", loglevel);
231ef270ab1SKenneth D. Merry 	}
232ef270ab1SKenneth D. Merry 
233ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
234ef270ab1SKenneth D. Merry 					"ramlog_size", &ramlog_size)) {
235ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "ramlog_size = %#x\n", ramlog_size);
236ef270ab1SKenneth D. Merry 	}
237ef270ab1SKenneth D. Merry 
238ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
239ef270ab1SKenneth D. Merry 					"ddump_saved_size", &ddump_saved_size)) {
240ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "ddump_saved_size= %#x\n", ddump_saved_size);
241ef270ab1SKenneth D. Merry 	}
242ef270ab1SKenneth D. Merry 
243ef270ab1SKenneth D. Merry 	/* If enabled, initailize a RAM logging buffer */
244ef270ab1SKenneth D. Merry 	if (logdest & 2) {
245ef270ab1SKenneth D. Merry 		ocs->ramlog = ocs_ramlog_init(ocs, ramlog_size/OCS_RAMLOG_DEFAULT_BUFFERS,
246ef270ab1SKenneth D. Merry 			OCS_RAMLOG_DEFAULT_BUFFERS);
247ef270ab1SKenneth D. Merry 		/* If NULL was returned, then we'll simply skip using the ramlog but */
248ef270ab1SKenneth D. Merry 		/* set logdest to 1 to ensure that we at least get default logging.  */
249ef270ab1SKenneth D. Merry 		if (ocs->ramlog == NULL) {
250ef270ab1SKenneth D. Merry 			logdest = 1;
251ef270ab1SKenneth D. Merry 		}
252ef270ab1SKenneth D. Merry 	}
253ef270ab1SKenneth D. Merry 
254ef270ab1SKenneth D. Merry 	/* initialize a saved ddump */
255ef270ab1SKenneth D. Merry 	if (ddump_saved_size) {
256ef270ab1SKenneth D. Merry 		if (ocs_textbuf_alloc(ocs, &ocs->ddump_saved, ddump_saved_size)) {
257ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "failed to allocate memory for saved ddump\n");
258ef270ab1SKenneth D. Merry 		}
259ef270ab1SKenneth D. Merry 	}
260ef270ab1SKenneth D. Merry 
261ef270ab1SKenneth D. Merry 	if (0 == resource_string_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
262ef270ab1SKenneth D. Merry 					"hw_war_version", &hw_war_version)) {
263ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "hw_war_version = %s\n", hw_war_version);
264ef270ab1SKenneth D. Merry 		ocs->hw_war_version = strdup(hw_war_version, M_OCS);
265ef270ab1SKenneth D. Merry 	}
266ef270ab1SKenneth D. Merry 
267ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
268ef270ab1SKenneth D. Merry 				    "explicit_buffer_list", &i)) {
269ef270ab1SKenneth D. Merry 		ocs->explicit_buffer_list = i;
270ef270ab1SKenneth D. Merry 	}
271ef270ab1SKenneth D. Merry 
272ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
273ef270ab1SKenneth D. Merry 					"ethernet_license", &i)) {
274ef270ab1SKenneth D. Merry 		ocs->ethernet_license = i;
275ef270ab1SKenneth D. Merry 	}
276ef270ab1SKenneth D. Merry 
277ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
278ef270ab1SKenneth D. Merry 					"speed", &i)) {
279ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "speed = %d Mbps\n", i);
280ef270ab1SKenneth D. Merry 		ocs->speed = i;
281ef270ab1SKenneth D. Merry 	}
282ef270ab1SKenneth D. Merry 	ocs->desc = device_get_desc(ocs->dev);
283ef270ab1SKenneth D. Merry 
284ef270ab1SKenneth D. Merry 	ocs_device_lock_init(ocs);
285ef270ab1SKenneth D. Merry 	ocs->driver_version = STR_BE_MAJOR "." STR_BE_MINOR "." STR_BE_BUILD "." STR_BE_BRANCH;
286ef270ab1SKenneth D. Merry 	ocs->model = ocs_pci_model(ocs->pci_vendor, ocs->pci_device);
287ef270ab1SKenneth D. Merry 
288ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
289ef270ab1SKenneth D. Merry 				    "enable_hlm", &i)) {
290ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "enable_hlm = %d\n", i);
291ef270ab1SKenneth D. Merry 		ocs->enable_hlm = i;
292ef270ab1SKenneth D. Merry 		if (ocs->enable_hlm) {
293ef270ab1SKenneth D. Merry 			ocs->hlm_group_size = 8;
294ef270ab1SKenneth D. Merry 
295ef270ab1SKenneth D. Merry 			if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
296ef270ab1SKenneth D. Merry 						    "hlm_group_size", &i)) {
297ef270ab1SKenneth D. Merry 				ocs->hlm_group_size = i;
298ef270ab1SKenneth D. Merry 			}
299ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "hlm_group_size = %d\n", i);
300ef270ab1SKenneth D. Merry 		}
301ef270ab1SKenneth D. Merry 	}
302ef270ab1SKenneth D. Merry 
303ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
304ef270ab1SKenneth D. Merry 					"num_scsi_ios", &i)) {
305ef270ab1SKenneth D. Merry 		ocs->num_scsi_ios = i;
306ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "num_scsi_ios = %d\n", ocs->num_scsi_ios);
307ef270ab1SKenneth D. Merry 	} else {
308ef270ab1SKenneth D. Merry 		ocs->num_scsi_ios = 8192;
309ef270ab1SKenneth D. Merry 	}
310ef270ab1SKenneth D. Merry 
311ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
312ef270ab1SKenneth D. Merry 					"topology", &i)) {
313ef270ab1SKenneth D. Merry 		ocs->topology = i;
314ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "Setting topology=%#x\n", i);
315ef270ab1SKenneth D. Merry 	}
316ef270ab1SKenneth D. Merry 
317ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
318ef270ab1SKenneth D. Merry 				    "num_vports", &i)) {
319ef270ab1SKenneth D. Merry 		if (i >= 0 && i <= 254) {
320ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "num_vports = %d\n", i);
321ef270ab1SKenneth D. Merry 			ocs->num_vports = i;
322ef270ab1SKenneth D. Merry 		} else {
323ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "num_vports: %d not supported \n", i);
324ef270ab1SKenneth D. Merry 		}
325ef270ab1SKenneth D. Merry 	}
326ef270ab1SKenneth D. Merry 
327ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
328ef270ab1SKenneth D. Merry 				    "external_loopback", &i)) {
329ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "external_loopback = %d\n", i);
330ef270ab1SKenneth D. Merry 		ocs->external_loopback = i;
331ef270ab1SKenneth D. Merry 	}
332ef270ab1SKenneth D. Merry 
333ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
334ef270ab1SKenneth D. Merry 				    "tgt_rscn_delay", &i)) {
335ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "tgt_rscn_delay = %d\n", i);
336ef270ab1SKenneth D. Merry 		ocs->tgt_rscn_delay_msec = i * 1000;
337ef270ab1SKenneth D. Merry 	}
338ef270ab1SKenneth D. Merry 
339ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
340ef270ab1SKenneth D. Merry 				    "tgt_rscn_period", &i)) {
341ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "tgt_rscn_period = %d\n", i);
342ef270ab1SKenneth D. Merry 		ocs->tgt_rscn_period_msec = i * 1000;
343ef270ab1SKenneth D. Merry 	}
344ef270ab1SKenneth D. Merry 
345ef270ab1SKenneth D. Merry 	if (0 == resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
346ef270ab1SKenneth D. Merry 				    "target_io_timer", &i)) {
347ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "target_io_timer = %d\n", i);
348ef270ab1SKenneth D. Merry 		ocs->target_io_timer_sec = i;
349ef270ab1SKenneth D. Merry 	}
350ef270ab1SKenneth D. Merry 
351ef270ab1SKenneth D. Merry 	hw_global.queue_topology_string = queue_topology;
352ef270ab1SKenneth D. Merry 	ocs->rq_selection_policy = 0;
353ef270ab1SKenneth D. Merry 	ocs->rr_quanta = 1;
354ef270ab1SKenneth D. Merry 	ocs->filter_def = "0,0,0,0";
355ef270ab1SKenneth D. Merry 
356ef270ab1SKenneth D. Merry 	return 0;
357ef270ab1SKenneth D. Merry }
358ef270ab1SKenneth D. Merry 
359ef270ab1SKenneth D. Merry static int32_t
ocs_setup_fcports(ocs_t * ocs)360ef270ab1SKenneth D. Merry ocs_setup_fcports(ocs_t *ocs)
361ef270ab1SKenneth D. Merry {
362ef270ab1SKenneth D. Merry 	uint32_t        i = 0, role = 0;
363ef270ab1SKenneth D. Merry 	uint64_t sli_wwpn, sli_wwnn;
364ef270ab1SKenneth D. Merry 	size_t size;
365ef270ab1SKenneth D. Merry 	ocs_xport_t *xport = ocs->xport;
366ef270ab1SKenneth D. Merry 	ocs_vport_spec_t *vport;
367ef270ab1SKenneth D. Merry 	ocs_fcport *fcp = NULL;
368ef270ab1SKenneth D. Merry 
369ef270ab1SKenneth D. Merry 	size = sizeof(ocs_fcport) * (ocs->num_vports + 1);
370ef270ab1SKenneth D. Merry 
371ef270ab1SKenneth D. Merry 	ocs->fcports = ocs_malloc(ocs, size, M_ZERO|M_NOWAIT);
372ef270ab1SKenneth D. Merry 	if (ocs->fcports == NULL) {
373ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "Can't allocate fcport \n");
374ef270ab1SKenneth D. Merry 		return 1;
375ef270ab1SKenneth D. Merry 	}
376ef270ab1SKenneth D. Merry 
377ef270ab1SKenneth D. Merry 	role = (ocs->enable_ini)? KNOB_ROLE_INITIATOR: 0 |
378ef270ab1SKenneth D. Merry 		(ocs->enable_tgt)? KNOB_ROLE_TARGET: 0;
379ef270ab1SKenneth D. Merry 
380ef270ab1SKenneth D. Merry 	fcp = FCPORT(ocs, i);
381ef270ab1SKenneth D. Merry 	fcp->role = role;
382ef270ab1SKenneth D. Merry 	i++;
383ef270ab1SKenneth D. Merry 
384ef270ab1SKenneth D. Merry 	ocs_list_foreach(&xport->vport_list, vport) {
385ef270ab1SKenneth D. Merry 		fcp = FCPORT(ocs, i);
386ef270ab1SKenneth D. Merry 		vport->tgt_data = fcp;
387ef270ab1SKenneth D. Merry 		fcp->vport = vport;
388ef270ab1SKenneth D. Merry 		fcp->role = role;
389ef270ab1SKenneth D. Merry 
390ef270ab1SKenneth D. Merry 		if (ocs_hw_get_def_wwn(ocs, i, &sli_wwpn, &sli_wwnn)) {
391ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "Get default wwn failed \n");
392ef270ab1SKenneth D. Merry 			i++;
393ef270ab1SKenneth D. Merry 			continue;
394ef270ab1SKenneth D. Merry 		}
395ef270ab1SKenneth D. Merry 
396ef270ab1SKenneth D. Merry 		vport->wwpn = ocs_be64toh(sli_wwpn);
397ef270ab1SKenneth D. Merry 		vport->wwnn = ocs_be64toh(sli_wwnn);
398ef270ab1SKenneth D. Merry 		i++;
399ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "VPort wwpn: %lx wwnn: %lx \n", vport->wwpn, vport->wwnn);
400ef270ab1SKenneth D. Merry 	}
401ef270ab1SKenneth D. Merry 
402ef270ab1SKenneth D. Merry 	return 0;
403ef270ab1SKenneth D. Merry }
404ef270ab1SKenneth D. Merry 
405ef270ab1SKenneth D. Merry int32_t
ocs_device_attach(ocs_t * ocs)406ef270ab1SKenneth D. Merry ocs_device_attach(ocs_t *ocs)
407ef270ab1SKenneth D. Merry {
408ef270ab1SKenneth D. Merry         int32_t i;
409ef270ab1SKenneth D. Merry 	ocs_io_t *io = NULL;
410ef270ab1SKenneth D. Merry 
411ef270ab1SKenneth D. Merry         if (ocs->attached) {
412ef270ab1SKenneth D. Merry                 ocs_log_warn(ocs, "%s: Device is already attached\n", __func__);
413ef270ab1SKenneth D. Merry                 return -1;
414ef270ab1SKenneth D. Merry         }
415ef270ab1SKenneth D. Merry 
416ef270ab1SKenneth D. Merry 	/* Allocate transport object and bring online */
417ef270ab1SKenneth D. Merry 	ocs->xport = ocs_xport_alloc(ocs);
418ef270ab1SKenneth D. Merry 	if (ocs->xport == NULL) {
419ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "failed to allocate transport object\n");
420ef270ab1SKenneth D. Merry 		return ENOMEM;
421ef270ab1SKenneth D. Merry 	} else if (ocs_xport_attach(ocs->xport) != 0) {
422ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: failed to attach transport object\n", __func__);
423ef270ab1SKenneth D. Merry 		goto fail_xport_attach;
424ef270ab1SKenneth D. Merry 	} else if (ocs_xport_initialize(ocs->xport) != 0) {
425ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: failed to initialize transport object\n", __func__);
426ef270ab1SKenneth D. Merry 		goto fail_xport_init;
427ef270ab1SKenneth D. Merry 	}
428ef270ab1SKenneth D. Merry 
429ef270ab1SKenneth D. Merry 	if (ocs_init_dma_tag(ocs)) {
430ef270ab1SKenneth D. Merry 		goto fail_intr_setup;
431ef270ab1SKenneth D. Merry 	}
432ef270ab1SKenneth D. Merry 
433ef270ab1SKenneth D. Merry 	for (i = 0; (io = ocs_io_get_instance(ocs, i)); i++) {
434ef270ab1SKenneth D. Merry 		if (bus_dmamap_create(ocs->buf_dmat, 0, &io->tgt_io.dmap)) {
435ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "%s: bad dma map create\n", __func__);
436ef270ab1SKenneth D. Merry 		}
437ef270ab1SKenneth D. Merry 
438ef270ab1SKenneth D. Merry 		io->tgt_io.state = OCS_CAM_IO_FREE;
439ef270ab1SKenneth D. Merry 	}
440ef270ab1SKenneth D. Merry 
441ef270ab1SKenneth D. Merry 	if (ocs_setup_fcports(ocs)) {
442ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "FCports creation failed\n");
443ef270ab1SKenneth D. Merry 		goto fail_intr_setup;
444ef270ab1SKenneth D. Merry 	}
445ef270ab1SKenneth D. Merry 
446ef270ab1SKenneth D. Merry 	if (ocs_cam_attach(ocs)) {
447ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "cam attach failed \n");
448ef270ab1SKenneth D. Merry 		goto fail_intr_setup;
449ef270ab1SKenneth D. Merry 	}
450ef270ab1SKenneth D. Merry 
451ef270ab1SKenneth D. Merry 	if (ocs_intr_setup(ocs)) {
452ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "Interrupt setup failed\n");
453ef270ab1SKenneth D. Merry 		goto fail_intr_setup;
454ef270ab1SKenneth D. Merry 	}
455ef270ab1SKenneth D. Merry 
456ef270ab1SKenneth D. Merry 	if (ocs->enable_ini || ocs->enable_tgt) {
457ef270ab1SKenneth D. Merry 		if (ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE)) {
458ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "Can't init port\n");
459ef270ab1SKenneth D. Merry 			goto fail_xport_online;
460ef270ab1SKenneth D. Merry 		}
461ef270ab1SKenneth D. Merry 	}
462ef270ab1SKenneth D. Merry 
463ef270ab1SKenneth D. Merry 	ocs->attached = true;
464ef270ab1SKenneth D. Merry 
465ef270ab1SKenneth D. Merry 	return 0;
466ef270ab1SKenneth D. Merry 
467ef270ab1SKenneth D. Merry fail_xport_online:
468ef270ab1SKenneth D. Merry 	if (ocs_xport_control(ocs->xport, OCS_XPORT_SHUTDOWN)) {
469ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "Transport Shutdown timed out\n");
470ef270ab1SKenneth D. Merry 	}
471ef270ab1SKenneth D. Merry 	ocs_intr_teardown(ocs);
472ef270ab1SKenneth D. Merry fail_intr_setup:
473ef270ab1SKenneth D. Merry fail_xport_init:
474ef270ab1SKenneth D. Merry 	ocs_xport_detach(ocs->xport);
475ef270ab1SKenneth D. Merry 	if (ocs->config_tgt)
476ef270ab1SKenneth D. Merry 		ocs_scsi_tgt_del_device(ocs);
477ef270ab1SKenneth D. Merry 
478ef270ab1SKenneth D. Merry 	ocs_xport_free(ocs->xport);
479ef270ab1SKenneth D. Merry 	ocs->xport = NULL;
480ef270ab1SKenneth D. Merry fail_xport_attach:
481ef270ab1SKenneth D. Merry 	if (ocs->xport)
482ef270ab1SKenneth D. Merry 		ocs_free(ocs, ocs->xport, sizeof(*(ocs->xport)));
483ef270ab1SKenneth D. Merry 	ocs->xport = NULL;
484ef270ab1SKenneth D. Merry 	return ENXIO;
485ef270ab1SKenneth D. Merry }
486ef270ab1SKenneth D. Merry 
487ef270ab1SKenneth D. Merry /**
488ef270ab1SKenneth D. Merry  * @brief Connect the driver to the given device
489ef270ab1SKenneth D. Merry  *
490ef270ab1SKenneth D. Merry  * If the probe routine is successful, the OS will give the driver
491ef270ab1SKenneth D. Merry  * the opportunity to connect itself to the device. This routine
492ef270ab1SKenneth D. Merry  * maps PCI resources (memory BARs and interrupts) and initialize a
493ef270ab1SKenneth D. Merry  * hardware object.
494ef270ab1SKenneth D. Merry  *
495ef270ab1SKenneth D. Merry  * @param dev device abstraction
496ef270ab1SKenneth D. Merry  *
497ef270ab1SKenneth D. Merry  * @return 0 if the driver attaches to the device, ENXIO otherwise
498ef270ab1SKenneth D. Merry  */
499ef270ab1SKenneth D. Merry 
500ef270ab1SKenneth D. Merry static int
ocs_pci_attach(device_t dev)501ef270ab1SKenneth D. Merry ocs_pci_attach(device_t dev)
502ef270ab1SKenneth D. Merry {
503ef270ab1SKenneth D. Merry 	struct ocs_softc	*ocs;
504ef270ab1SKenneth D. Merry 	int			instance;
505ef270ab1SKenneth D. Merry 
506ef270ab1SKenneth D. Merry 	instance = device_get_unit(dev);
507ef270ab1SKenneth D. Merry 
508ef270ab1SKenneth D. Merry 	ocs = (struct ocs_softc *)device_get_softc(dev);
509ef270ab1SKenneth D. Merry 	if (NULL == ocs) {
510ef270ab1SKenneth D. Merry 		device_printf(dev, "cannot allocate softc\n");
511ef270ab1SKenneth D. Merry 		return ENOMEM;
512ef270ab1SKenneth D. Merry 	}
513ef270ab1SKenneth D. Merry 	memset(ocs, 0, sizeof(struct ocs_softc));
514ef270ab1SKenneth D. Merry 
515ef270ab1SKenneth D. Merry 	if (instance < ARRAY_SIZE(ocs_devices)) {
516ef270ab1SKenneth D. Merry 		ocs_devices[instance] = ocs;
517ef270ab1SKenneth D. Merry 	} else {
518ef270ab1SKenneth D. Merry 		device_printf(dev, "got unexpected ocs instance number %d\n", instance);
519ef270ab1SKenneth D. Merry 	}
520ef270ab1SKenneth D. Merry 
521ef270ab1SKenneth D. Merry 	ocs->instance_index = instance;
522ef270ab1SKenneth D. Merry 
523ef270ab1SKenneth D. Merry 	ocs->dev = dev;
524ef270ab1SKenneth D. Merry 
525ef270ab1SKenneth D. Merry 	pci_enable_io(dev, SYS_RES_MEMORY);
526ef270ab1SKenneth D. Merry 	pci_enable_busmaster(dev);
527ef270ab1SKenneth D. Merry 
528ef270ab1SKenneth D. Merry 	ocs->pci_vendor = pci_get_vendor(dev);
529ef270ab1SKenneth D. Merry 	ocs->pci_device = pci_get_device(dev);
530cba757efSRam Kishore Vegesna 	ocs->pci_subsystem_vendor = pci_get_subvendor(dev);
531cba757efSRam Kishore Vegesna 	ocs->pci_subsystem_device = pci_get_subdevice(dev);
532cba757efSRam Kishore Vegesna 
533ef270ab1SKenneth D. Merry 	snprintf(ocs->businfo, sizeof(ocs->businfo), "%02X:%02X:%02X",
534ef270ab1SKenneth D. Merry 		pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev));
535ef270ab1SKenneth D. Merry 
536ef270ab1SKenneth D. Merry 	/* Map all memory BARs */
5373bf42363SRam Kishore Vegesna 	if (ocs->pci_device == PCI_PRODUCT_EMULEX_LANCER_G7) {
5383bf42363SRam Kishore Vegesna 		if(ocs_map_g7_bars(dev,ocs)) {
5393bf42363SRam Kishore Vegesna 			device_printf(dev, "Failed to map pci bars\n");
5403bf42363SRam Kishore Vegesna 			goto release_bus;
5413bf42363SRam Kishore Vegesna 		}
5423bf42363SRam Kishore Vegesna 	} else {
543ef270ab1SKenneth D. Merry 		if (ocs_map_bars(dev, ocs)) {
544ef270ab1SKenneth D. Merry 			device_printf(dev, "Failed to map pci bars\n");
545ef270ab1SKenneth D. Merry 			goto release_bus;
546ef270ab1SKenneth D. Merry 		}
5473bf42363SRam Kishore Vegesna 	}
548ef270ab1SKenneth D. Merry 
549ef270ab1SKenneth D. Merry 	/* create a root DMA tag for the device */
550ef270ab1SKenneth D. Merry 	if (bus_dma_tag_create(bus_get_dma_tag(dev),
551ef270ab1SKenneth D. Merry 				1,		/* byte alignment */
552ef270ab1SKenneth D. Merry 				0,		/* no boundary restrictions */
553ef270ab1SKenneth D. Merry 				BUS_SPACE_MAXADDR, /* no minimum low address */
554ef270ab1SKenneth D. Merry 				BUS_SPACE_MAXADDR, /* no maximum high address */
555ef270ab1SKenneth D. Merry 				NULL,		/* no filter function */
556ef270ab1SKenneth D. Merry 				NULL,		/* or arguments */
557ef270ab1SKenneth D. Merry 				BUS_SPACE_MAXSIZE, /* max size covered by tag */
558ef270ab1SKenneth D. Merry 				BUS_SPACE_UNRESTRICTED, /* no segment count restrictions */
559ef270ab1SKenneth D. Merry 				BUS_SPACE_MAXSIZE, /* no segment length restrictions */
560ef270ab1SKenneth D. Merry 				0,		/* flags */
561ef270ab1SKenneth D. Merry 				NULL,		/* no lock manipulation function */
562ef270ab1SKenneth D. Merry 				NULL,		/* or arguments */
563ef270ab1SKenneth D. Merry 				&ocs->dmat)) {
564ef270ab1SKenneth D. Merry 		device_printf(dev, "parent DMA tag allocation failed\n");
565ef270ab1SKenneth D. Merry 		goto release_bus;
566ef270ab1SKenneth D. Merry 	}
567ef270ab1SKenneth D. Merry 
568ef270ab1SKenneth D. Merry 	if (ocs_intr_alloc(ocs)) {
569ef270ab1SKenneth D. Merry 		device_printf(dev, "Interrupt allocation failed\n");
570ef270ab1SKenneth D. Merry 		goto release_bus;
571ef270ab1SKenneth D. Merry 	}
572ef270ab1SKenneth D. Merry 
573ef270ab1SKenneth D. Merry 	if (PCIC_SERIALBUS == pci_get_class(dev) &&
574ef270ab1SKenneth D. Merry 			PCIS_SERIALBUS_FC == pci_get_subclass(dev))
575ef270ab1SKenneth D. Merry 		ocs->ocs_xport = OCS_XPORT_FC;
576ef270ab1SKenneth D. Merry 	else {
577ef270ab1SKenneth D. Merry 		device_printf(dev, "unsupported class (%#x : %#x)\n",
578ef270ab1SKenneth D. Merry 				pci_get_class(dev),
579ef270ab1SKenneth D. Merry 				pci_get_class(dev));
580ef270ab1SKenneth D. Merry 		goto release_bus;
581ef270ab1SKenneth D. Merry 	}
582ef270ab1SKenneth D. Merry 
583ef270ab1SKenneth D. Merry 	/* Setup tunable parameters */
584ef270ab1SKenneth D. Merry 	if (ocs_setup_params(ocs)) {
585ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "failed to setup params\n");
586ef270ab1SKenneth D. Merry 		goto release_bus;
587ef270ab1SKenneth D. Merry 	}
588ef270ab1SKenneth D. Merry 
589ef270ab1SKenneth D. Merry 	if (ocs_device_attach(ocs)) {
590ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "failed to attach device\n");
591ef270ab1SKenneth D. Merry 		goto release_params;
592ef270ab1SKenneth D. Merry 	}
593ef270ab1SKenneth D. Merry 
594ef270ab1SKenneth D. Merry 	ocs->fc_type = FC_TYPE_FCP;
595ef270ab1SKenneth D. Merry 
596ef270ab1SKenneth D. Merry 	ocs_debug_attach(ocs);
597ef270ab1SKenneth D. Merry 
598ef270ab1SKenneth D. Merry 	return 0;
599ef270ab1SKenneth D. Merry 
600ef270ab1SKenneth D. Merry release_params:
601ef270ab1SKenneth D. Merry 	ocs_ramlog_free(ocs, ocs->ramlog);
602ef270ab1SKenneth D. Merry 	ocs_device_lock_free(ocs);
603ef270ab1SKenneth D. Merry 	free(ocs->hw_war_version, M_OCS);
604ef270ab1SKenneth D. Merry release_bus:
605ef270ab1SKenneth D. Merry 	ocs_release_bus(ocs);
606ef270ab1SKenneth D. Merry 	return ENXIO;
607ef270ab1SKenneth D. Merry }
608ef270ab1SKenneth D. Merry 
609ef270ab1SKenneth D. Merry /**
610ef270ab1SKenneth D. Merry  * @brief free resources when pci device detach
611ef270ab1SKenneth D. Merry  *
612ef270ab1SKenneth D. Merry  * @param ocs pointer to ocs structure
613ef270ab1SKenneth D. Merry  *
614ef270ab1SKenneth D. Merry  * @return 0 for success, a negative error code value for failure.
615ef270ab1SKenneth D. Merry  */
616ef270ab1SKenneth D. Merry 
617ef270ab1SKenneth D. Merry int32_t
ocs_device_detach(ocs_t * ocs)618ef270ab1SKenneth D. Merry ocs_device_detach(ocs_t *ocs)
619ef270ab1SKenneth D. Merry {
620ef270ab1SKenneth D. Merry         int32_t rc = 0, i;
621ef270ab1SKenneth D. Merry 	ocs_io_t *io = NULL;
622ef270ab1SKenneth D. Merry 
623ef270ab1SKenneth D. Merry         if (ocs != NULL) {
624ef270ab1SKenneth D. Merry                 if (!ocs->attached) {
625ef270ab1SKenneth D. Merry                         ocs_log_warn(ocs, "%s: Device is not attached\n", __func__);
626ef270ab1SKenneth D. Merry                         return -1;
627ef270ab1SKenneth D. Merry                 }
628ef270ab1SKenneth D. Merry 
6296affb8ebSRam Kishore Vegesna                 ocs->attached = FALSE;
6306affb8ebSRam Kishore Vegesna 
631ef270ab1SKenneth D. Merry                 rc = ocs_xport_control(ocs->xport, OCS_XPORT_SHUTDOWN);
632ef270ab1SKenneth D. Merry                 if (rc) {
633ef270ab1SKenneth D. Merry                         ocs_log_err(ocs, "%s: Transport Shutdown timed out\n", __func__);
634ef270ab1SKenneth D. Merry                 }
635ef270ab1SKenneth D. Merry 
636ef270ab1SKenneth D. Merry 		ocs_intr_teardown(ocs);
637ef270ab1SKenneth D. Merry 
638ef270ab1SKenneth D. Merry                 if (ocs_xport_detach(ocs->xport) != 0) {
639ef270ab1SKenneth D. Merry                         ocs_log_err(ocs, "%s: Transport detach failed\n", __func__);
640ef270ab1SKenneth D. Merry                 }
641ef270ab1SKenneth D. Merry 
642ef270ab1SKenneth D. Merry 		ocs_cam_detach(ocs);
6434915e5c7SRam Kishore Vegesna 		ocs_free(ocs, ocs->fcports, sizeof(*(ocs->fcports)));
644ef270ab1SKenneth D. Merry 
645ef270ab1SKenneth D. Merry 		for (i = 0; (io = ocs_io_get_instance(ocs, i)); i++) {
646ef270ab1SKenneth D. Merry 			if (bus_dmamap_destroy(ocs->buf_dmat, io->tgt_io.dmap)) {
647ef270ab1SKenneth D. Merry 				device_printf(ocs->dev, "%s: bad dma map destroy\n", __func__);
648ef270ab1SKenneth D. Merry 			}
649ef270ab1SKenneth D. Merry 		}
650ef270ab1SKenneth D. Merry 		bus_dma_tag_destroy(ocs->dmat);
651ef270ab1SKenneth D. Merry                 ocs_xport_free(ocs->xport);
652ef270ab1SKenneth D. Merry                 ocs->xport = NULL;
653ef270ab1SKenneth D. Merry         }
654ef270ab1SKenneth D. Merry 
655ef270ab1SKenneth D. Merry         return 0;
656ef270ab1SKenneth D. Merry }
657ef270ab1SKenneth D. Merry 
658ef270ab1SKenneth D. Merry /**
659ef270ab1SKenneth D. Merry  * @brief Detach the driver from the given device
660ef270ab1SKenneth D. Merry  *
661ef270ab1SKenneth D. Merry  * If the driver is a loadable module, this routine gets called at unload
662ef270ab1SKenneth D. Merry  * time. This routine will stop the device and free any allocated resources.
663ef270ab1SKenneth D. Merry  *
664ef270ab1SKenneth D. Merry  * @param dev device abstraction
665ef270ab1SKenneth D. Merry  *
666ef270ab1SKenneth D. Merry  * @return 0 if the driver detaches from the device, ENXIO otherwise
667ef270ab1SKenneth D. Merry  */
668ef270ab1SKenneth D. Merry static int
ocs_pci_detach(device_t dev)669ef270ab1SKenneth D. Merry ocs_pci_detach(device_t dev)
670ef270ab1SKenneth D. Merry {
671ef270ab1SKenneth D. Merry 	struct ocs_softc	*ocs;
672ef270ab1SKenneth D. Merry 
673ef270ab1SKenneth D. Merry 	ocs = (struct ocs_softc *)device_get_softc(dev);
674ef270ab1SKenneth D. Merry 	if (!ocs) {
675ef270ab1SKenneth D. Merry 		device_printf(dev, "no driver context?!?\n");
676ef270ab1SKenneth D. Merry 		return -1;
677ef270ab1SKenneth D. Merry 	}
678ef270ab1SKenneth D. Merry 
679ef270ab1SKenneth D. Merry 	if (ocs->config_tgt && ocs->enable_tgt) {
680ef270ab1SKenneth D. Merry 		device_printf(dev, "can't detach with target mode enabled\n");
681ef270ab1SKenneth D. Merry 		return EBUSY;
682ef270ab1SKenneth D. Merry 	}
683ef270ab1SKenneth D. Merry 
684ef270ab1SKenneth D. Merry 	ocs_device_detach(ocs);
685ef270ab1SKenneth D. Merry 
686ef270ab1SKenneth D. Merry 	/*
687ef270ab1SKenneth D. Merry 	 * Workaround for OCS SCSI Transport quirk.
688ef270ab1SKenneth D. Merry 	 *
689ef270ab1SKenneth D. Merry 	 * CTL requires that target mode is disabled prior to unloading the
690ef270ab1SKenneth D. Merry 	 * driver (ie ocs->enable_tgt = FALSE), but once the target is disabled,
691ef270ab1SKenneth D. Merry 	 * the transport will not call ocs_scsi_tgt_del_device() which deallocates
692ef270ab1SKenneth D. Merry 	 * CAM resources. The workaround is to explicitly make the call here.
693ef270ab1SKenneth D. Merry 	 */
694ef270ab1SKenneth D. Merry 	if (ocs->config_tgt)
695ef270ab1SKenneth D. Merry 		ocs_scsi_tgt_del_device(ocs);
696ef270ab1SKenneth D. Merry 
697ef270ab1SKenneth D. Merry 	/* free strdup created buffer.*/
698ef270ab1SKenneth D. Merry 	free(ocs->hw_war_version, M_OCS);
699ef270ab1SKenneth D. Merry 
700ef270ab1SKenneth D. Merry 	ocs_device_lock_free(ocs);
701ef270ab1SKenneth D. Merry 
702ef270ab1SKenneth D. Merry 	ocs_debug_detach(ocs);
703ef270ab1SKenneth D. Merry 
704ef270ab1SKenneth D. Merry 	ocs_ramlog_free(ocs, ocs->ramlog);
705ef270ab1SKenneth D. Merry 
706ef270ab1SKenneth D. Merry 	ocs_release_bus(ocs);
707ef270ab1SKenneth D. Merry 
708ef270ab1SKenneth D. Merry 	return 0;
709ef270ab1SKenneth D. Merry }
710ef270ab1SKenneth D. Merry 
711ef270ab1SKenneth D. Merry /**
712ef270ab1SKenneth D. Merry  * @brief Notify driver of system shutdown
713ef270ab1SKenneth D. Merry  *
714ef270ab1SKenneth D. Merry  * @param dev device abstraction
715ef270ab1SKenneth D. Merry  *
716ef270ab1SKenneth D. Merry  * @return 0 if the driver attaches to the device, ENXIO otherwise
717ef270ab1SKenneth D. Merry  */
718ef270ab1SKenneth D. Merry static int
ocs_pci_shutdown(device_t dev)719ef270ab1SKenneth D. Merry ocs_pci_shutdown(device_t dev)
720ef270ab1SKenneth D. Merry {
721ef270ab1SKenneth D. Merry 	device_printf(dev, "%s\n", __func__);
722ef270ab1SKenneth D. Merry 	return 0;
723ef270ab1SKenneth D. Merry }
724ef270ab1SKenneth D. Merry 
725ef270ab1SKenneth D. Merry /**
726ef270ab1SKenneth D. Merry  * @brief Release bus resources allocated within the soft context
727ef270ab1SKenneth D. Merry  *
728ef270ab1SKenneth D. Merry  * @param ocs Pointer to the driver's context
729ef270ab1SKenneth D. Merry  *
730ef270ab1SKenneth D. Merry  * @return none
731ef270ab1SKenneth D. Merry  */
732ef270ab1SKenneth D. Merry static void
ocs_release_bus(struct ocs_softc * ocs)733ef270ab1SKenneth D. Merry ocs_release_bus(struct ocs_softc *ocs)
734ef270ab1SKenneth D. Merry {
735ef270ab1SKenneth D. Merry 
736ef270ab1SKenneth D. Merry 	if (NULL != ocs) {
737ef270ab1SKenneth D. Merry 		uint32_t	i;
738ef270ab1SKenneth D. Merry 
739ef270ab1SKenneth D. Merry 		ocs_intr_teardown(ocs);
740ef270ab1SKenneth D. Merry 
741ef270ab1SKenneth D. Merry 		if (ocs->irq) {
742ef270ab1SKenneth D. Merry 			bus_release_resource(ocs->dev, SYS_RES_IRQ,
743ef270ab1SKenneth D. Merry 					rman_get_rid(ocs->irq), ocs->irq);
744ef270ab1SKenneth D. Merry 
745ef270ab1SKenneth D. Merry 			if (ocs->n_vec) {
746ef270ab1SKenneth D. Merry 				pci_release_msi(ocs->dev);
747ef270ab1SKenneth D. Merry 				ocs->n_vec = 0;
748ef270ab1SKenneth D. Merry 			}
749ef270ab1SKenneth D. Merry 
750ef270ab1SKenneth D. Merry 			ocs->irq = NULL;
751ef270ab1SKenneth D. Merry 		}
752ef270ab1SKenneth D. Merry 
753ef270ab1SKenneth D. Merry 		bus_dma_tag_destroy(ocs->dmat);
754ef270ab1SKenneth D. Merry 
755ef270ab1SKenneth D. Merry 		for (i = 0; i < PCI_MAX_BAR; i++) {
756ef270ab1SKenneth D. Merry 			if (ocs->reg[i].res) {
757ef270ab1SKenneth D. Merry 				bus_release_resource(ocs->dev, SYS_RES_MEMORY,
758ef270ab1SKenneth D. Merry 						ocs->reg[i].rid,
759ef270ab1SKenneth D. Merry 						ocs->reg[i].res);
760ef270ab1SKenneth D. Merry 			}
761ef270ab1SKenneth D. Merry 		}
762ef270ab1SKenneth D. Merry 	}
763ef270ab1SKenneth D. Merry }
764ef270ab1SKenneth D. Merry 
765ef270ab1SKenneth D. Merry /**
766ef270ab1SKenneth D. Merry  * @brief Allocate and initialize interrupts
767ef270ab1SKenneth D. Merry  *
768ef270ab1SKenneth D. Merry  * @param ocs Pointer to the driver's context
769ef270ab1SKenneth D. Merry  *
770ef270ab1SKenneth D. Merry  * @return none
771ef270ab1SKenneth D. Merry  */
772ef270ab1SKenneth D. Merry static int32_t
ocs_intr_alloc(struct ocs_softc * ocs)773ef270ab1SKenneth D. Merry ocs_intr_alloc(struct ocs_softc *ocs)
774ef270ab1SKenneth D. Merry {
775ef270ab1SKenneth D. Merry 
776ef270ab1SKenneth D. Merry 	ocs->n_vec = 1;
777ef270ab1SKenneth D. Merry 	if (pci_alloc_msix(ocs->dev, &ocs->n_vec)) {
778ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "MSI-X allocation failed\n");
779ef270ab1SKenneth D. Merry 		if (pci_alloc_msi(ocs->dev, &ocs->n_vec)) {
780ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "MSI allocation failed \n");
781ef270ab1SKenneth D. Merry 			ocs->irqid = 0;
782ef270ab1SKenneth D. Merry 			ocs->n_vec = 0;
783ef270ab1SKenneth D. Merry 		} else
784ef270ab1SKenneth D. Merry 			ocs->irqid = 1;
785ef270ab1SKenneth D. Merry 	} else {
786ef270ab1SKenneth D. Merry 		ocs->irqid = 1;
787ef270ab1SKenneth D. Merry 	}
788ef270ab1SKenneth D. Merry 
789ef270ab1SKenneth D. Merry 	ocs->irq = bus_alloc_resource_any(ocs->dev, SYS_RES_IRQ, &ocs->irqid,
790ef270ab1SKenneth D. Merry 			RF_ACTIVE | RF_SHAREABLE);
791ef270ab1SKenneth D. Merry 	if (NULL == ocs->irq) {
792ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "could not allocate interrupt\n");
793ef270ab1SKenneth D. Merry 		return -1;
794ef270ab1SKenneth D. Merry 	}
795ef270ab1SKenneth D. Merry 
796ef270ab1SKenneth D. Merry 	ocs->intr_ctx.vec = 0;
797ef270ab1SKenneth D. Merry 	ocs->intr_ctx.softc = ocs;
798ef270ab1SKenneth D. Merry 	snprintf(ocs->intr_ctx.name, sizeof(ocs->intr_ctx.name),
799ef270ab1SKenneth D. Merry 			"%s_intr_%d",
800ef270ab1SKenneth D. Merry 			device_get_nameunit(ocs->dev),
801ef270ab1SKenneth D. Merry 			ocs->intr_ctx.vec);
802ef270ab1SKenneth D. Merry 
803ef270ab1SKenneth D. Merry 	return 0;
804ef270ab1SKenneth D. Merry }
805ef270ab1SKenneth D. Merry 
806ef270ab1SKenneth D. Merry /**
807ef270ab1SKenneth D. Merry  * @brief Create and attach an interrupt handler
808ef270ab1SKenneth D. Merry  *
809ef270ab1SKenneth D. Merry  * @param ocs Pointer to the driver's context
810ef270ab1SKenneth D. Merry  *
811ef270ab1SKenneth D. Merry  * @return 0 on success, non-zero otherwise
812ef270ab1SKenneth D. Merry  */
813ef270ab1SKenneth D. Merry static int32_t
ocs_intr_setup(struct ocs_softc * ocs)814ef270ab1SKenneth D. Merry ocs_intr_setup(struct ocs_softc *ocs)
815ef270ab1SKenneth D. Merry {
816ef270ab1SKenneth D. Merry 	driver_filter_t	*filter = NULL;
817ef270ab1SKenneth D. Merry 
818ef270ab1SKenneth D. Merry 	if (0 == ocs->n_vec) {
819ef270ab1SKenneth D. Merry 		filter = ocs_pci_intx_filter;
820ef270ab1SKenneth D. Merry 	}
821ef270ab1SKenneth D. Merry 
822ef270ab1SKenneth D. Merry 	if (bus_setup_intr(ocs->dev, ocs->irq, INTR_MPSAFE | INTR_TYPE_CAM,
823ef270ab1SKenneth D. Merry 				filter, ocs_pci_intr, &ocs->intr_ctx,
824ef270ab1SKenneth D. Merry 				&ocs->tag)) {
825ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "could not initialize interrupt\n");
826ef270ab1SKenneth D. Merry 		return -1;
827ef270ab1SKenneth D. Merry 	}
828ef270ab1SKenneth D. Merry 
829ef270ab1SKenneth D. Merry 	return 0;
830ef270ab1SKenneth D. Merry }
831ef270ab1SKenneth D. Merry 
832ef270ab1SKenneth D. Merry /**
833ef270ab1SKenneth D. Merry  * @brief Detach an interrupt handler
834ef270ab1SKenneth D. Merry  *
835ef270ab1SKenneth D. Merry  * @param ocs Pointer to the driver's context
836ef270ab1SKenneth D. Merry  *
837ef270ab1SKenneth D. Merry  * @return 0 on success, non-zero otherwise
838ef270ab1SKenneth D. Merry  */
839ef270ab1SKenneth D. Merry static int32_t
ocs_intr_teardown(struct ocs_softc * ocs)840ef270ab1SKenneth D. Merry ocs_intr_teardown(struct ocs_softc *ocs)
841ef270ab1SKenneth D. Merry {
842ef270ab1SKenneth D. Merry 
843ef270ab1SKenneth D. Merry 	if (!ocs) {
844ef270ab1SKenneth D. Merry 		printf("%s: bad driver context?!?\n", __func__);
845ef270ab1SKenneth D. Merry 		return -1;
846ef270ab1SKenneth D. Merry 	}
847ef270ab1SKenneth D. Merry 
848ef270ab1SKenneth D. Merry 	if (ocs->tag) {
849ef270ab1SKenneth D. Merry 		bus_teardown_intr(ocs->dev, ocs->irq, ocs->tag);
850ef270ab1SKenneth D. Merry 		ocs->tag = NULL;
851ef270ab1SKenneth D. Merry 	}
852ef270ab1SKenneth D. Merry 
853ef270ab1SKenneth D. Merry 	return 0;
854ef270ab1SKenneth D. Merry }
855ef270ab1SKenneth D. Merry 
856ef270ab1SKenneth D. Merry /**
857ef270ab1SKenneth D. Merry  * @brief PCI interrupt handler
858ef270ab1SKenneth D. Merry  *
859ef270ab1SKenneth D. Merry  * @param arg pointer to the driver's software context
860ef270ab1SKenneth D. Merry  *
861ef270ab1SKenneth D. Merry  * @return FILTER_HANDLED if interrupt is processed, FILTER_STRAY otherwise
862ef270ab1SKenneth D. Merry  */
863ef270ab1SKenneth D. Merry static int
ocs_pci_intx_filter(void * arg)864ef270ab1SKenneth D. Merry ocs_pci_intx_filter(void *arg)
865ef270ab1SKenneth D. Merry {
866ef270ab1SKenneth D. Merry 	ocs_intr_ctx_t	*intr = arg;
867ef270ab1SKenneth D. Merry 	struct ocs_softc *ocs = NULL;
868ef270ab1SKenneth D. Merry 	uint16_t	val = 0;
869ef270ab1SKenneth D. Merry 
870ef270ab1SKenneth D. Merry 	if (NULL == intr) {
871ef270ab1SKenneth D. Merry 		return FILTER_STRAY;
872ef270ab1SKenneth D. Merry 	}
873ef270ab1SKenneth D. Merry 
874ef270ab1SKenneth D. Merry 	ocs = intr->softc;
875ef270ab1SKenneth D. Merry #ifndef PCIM_STATUS_INTR
876ef270ab1SKenneth D. Merry #define PCIM_STATUS_INTR	0x0008
877ef270ab1SKenneth D. Merry #endif
878ef270ab1SKenneth D. Merry 	val = pci_read_config(ocs->dev, PCIR_STATUS, 2);
879ef270ab1SKenneth D. Merry 	if (0xffff == val) {
880ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: pci_read_config(PCIR_STATUS) failed\n", __func__);
881ef270ab1SKenneth D. Merry 		return FILTER_STRAY;
882ef270ab1SKenneth D. Merry 	}
883ef270ab1SKenneth D. Merry 	if (0 == (val & PCIM_STATUS_INTR)) {
884ef270ab1SKenneth D. Merry 		return FILTER_STRAY;
885ef270ab1SKenneth D. Merry 	}
886ef270ab1SKenneth D. Merry 
887ef270ab1SKenneth D. Merry 	val = pci_read_config(ocs->dev, PCIR_COMMAND, 2);
888ef270ab1SKenneth D. Merry 	val |= PCIM_CMD_INTxDIS;
889ef270ab1SKenneth D. Merry 	pci_write_config(ocs->dev, PCIR_COMMAND, val, 2);
890ef270ab1SKenneth D. Merry 
891ef270ab1SKenneth D. Merry 	return FILTER_SCHEDULE_THREAD;
892ef270ab1SKenneth D. Merry }
893ef270ab1SKenneth D. Merry 
894ef270ab1SKenneth D. Merry /**
895ef270ab1SKenneth D. Merry  * @brief interrupt handler
896ef270ab1SKenneth D. Merry  *
897ef270ab1SKenneth D. Merry  * @param context pointer to the interrupt context
898ef270ab1SKenneth D. Merry  */
899ef270ab1SKenneth D. Merry static void
ocs_pci_intr(void * context)900ef270ab1SKenneth D. Merry ocs_pci_intr(void *context)
901ef270ab1SKenneth D. Merry {
902ef270ab1SKenneth D. Merry 	ocs_intr_ctx_t	*intr = context;
903ef270ab1SKenneth D. Merry 	struct ocs_softc *ocs = intr->softc;
904ef270ab1SKenneth D. Merry 
905ef270ab1SKenneth D. Merry 	mtx_lock(&ocs->sim_lock);
906ef270ab1SKenneth D. Merry 		ocs_hw_process(&ocs->hw, intr->vec, OCS_OS_MAX_ISR_TIME_MSEC);
907ef270ab1SKenneth D. Merry 	mtx_unlock(&ocs->sim_lock);
908ef270ab1SKenneth D. Merry }
909ef270ab1SKenneth D. Merry 
910ef270ab1SKenneth D. Merry /**
911ef270ab1SKenneth D. Merry  * @brief Initialize DMA tag
912ef270ab1SKenneth D. Merry  *
913ef270ab1SKenneth D. Merry  * @param ocs the driver instance's software context
914ef270ab1SKenneth D. Merry  *
915ef270ab1SKenneth D. Merry  * @return 0 on success, non-zero otherwise
916ef270ab1SKenneth D. Merry  */
917ef270ab1SKenneth D. Merry static int32_t
ocs_init_dma_tag(struct ocs_softc * ocs)918ef270ab1SKenneth D. Merry ocs_init_dma_tag(struct ocs_softc *ocs)
919ef270ab1SKenneth D. Merry {
920ef270ab1SKenneth D. Merry 	uint32_t	max_sgl = 0;
921ef270ab1SKenneth D. Merry 	uint32_t	max_sge = 0;
922ef270ab1SKenneth D. Merry 
923ef270ab1SKenneth D. Merry 	/*
924ef270ab1SKenneth D. Merry 	 * IOs can't use the parent DMA tag and must create their
925ef270ab1SKenneth D. Merry 	 * own, based primarily on a restricted number of DMA segments.
926ef270ab1SKenneth D. Merry 	 * This is more of a BSD requirement than a SLI Port requirement
927ef270ab1SKenneth D. Merry 	 */
928ef270ab1SKenneth D. Merry 	ocs_hw_get(&ocs->hw, OCS_HW_N_SGL, &max_sgl);
929ef270ab1SKenneth D. Merry 	ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGE, &max_sge);
930ef270ab1SKenneth D. Merry 
931ef270ab1SKenneth D. Merry 	if (bus_dma_tag_create(ocs->dmat,
932ef270ab1SKenneth D. Merry 				1,		/* byte alignment */
933ef270ab1SKenneth D. Merry 				0,		/* no boundary restrictions */
934ef270ab1SKenneth D. Merry 				BUS_SPACE_MAXADDR, /* no minimum low address */
935ef270ab1SKenneth D. Merry 				BUS_SPACE_MAXADDR, /* no maximum high address */
936ef270ab1SKenneth D. Merry 				NULL,		/* no filter function */
937ef270ab1SKenneth D. Merry 				NULL,		/* or arguments */
938ef270ab1SKenneth D. Merry 				BUS_SPACE_MAXSIZE, /* max size covered by tag */
939ef270ab1SKenneth D. Merry 				max_sgl, 	/* segment count restrictions */
940ef270ab1SKenneth D. Merry 				max_sge,	/* segment length restrictions */
941ef270ab1SKenneth D. Merry 				0,		/* flags */
942ef270ab1SKenneth D. Merry 				NULL,		/* no lock manipulation function */
943ef270ab1SKenneth D. Merry 				NULL,		/* or arguments */
944ef270ab1SKenneth D. Merry 				&ocs->buf_dmat)) {
945ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: bad bus_dma_tag_create(buf_dmat)\n", __func__);
946ef270ab1SKenneth D. Merry 		return -1;
947ef270ab1SKenneth D. Merry 	}
948ef270ab1SKenneth D. Merry 	return 0;
949ef270ab1SKenneth D. Merry }
950ef270ab1SKenneth D. Merry 
951ef270ab1SKenneth D. Merry int32_t
ocs_get_property(const char * prop_name,char * buffer,uint32_t buffer_len)952ef270ab1SKenneth D. Merry ocs_get_property(const char *prop_name, char *buffer, uint32_t buffer_len)
953ef270ab1SKenneth D. Merry {
954ef270ab1SKenneth D. Merry 	return -1;
955ef270ab1SKenneth D. Merry }
956ef270ab1SKenneth D. Merry 
957ef270ab1SKenneth D. Merry /**
958ef270ab1SKenneth D. Merry  * @brief return pointer to ocs structure given instance index
959ef270ab1SKenneth D. Merry  *
960ef270ab1SKenneth D. Merry  * A pointer to an ocs structure is returned given an instance index.
961ef270ab1SKenneth D. Merry  *
962ef270ab1SKenneth D. Merry  * @param index index to ocs_devices array
963ef270ab1SKenneth D. Merry  *
964ef270ab1SKenneth D. Merry  * @return ocs pointer
965ef270ab1SKenneth D. Merry  */
966ef270ab1SKenneth D. Merry 
ocs_get_instance(uint32_t index)967ef270ab1SKenneth D. Merry ocs_t *ocs_get_instance(uint32_t index)
968ef270ab1SKenneth D. Merry {
969ef270ab1SKenneth D. Merry 	if (index < ARRAY_SIZE(ocs_devices)) {
970ef270ab1SKenneth D. Merry 		return ocs_devices[index];
971ef270ab1SKenneth D. Merry 	}
972ef270ab1SKenneth D. Merry 	return NULL;
973ef270ab1SKenneth D. Merry }
974ef270ab1SKenneth D. Merry 
975ef270ab1SKenneth D. Merry /**
976ef270ab1SKenneth D. Merry  * @brief Return instance index of an opaque ocs structure
977ef270ab1SKenneth D. Merry  *
978ef270ab1SKenneth D. Merry  * Returns the ocs instance index
979ef270ab1SKenneth D. Merry  *
980ef270ab1SKenneth D. Merry  * @param os pointer to ocs instance
981ef270ab1SKenneth D. Merry  *
982ef270ab1SKenneth D. Merry  * @return pointer to ocs instance index
983ef270ab1SKenneth D. Merry  */
984ef270ab1SKenneth D. Merry uint32_t
ocs_instance(void * os)985ef270ab1SKenneth D. Merry ocs_instance(void *os)
986ef270ab1SKenneth D. Merry {
987ef270ab1SKenneth D. Merry 	ocs_t *ocs = os;
988ef270ab1SKenneth D. Merry 	return ocs->instance_index;
989ef270ab1SKenneth D. Merry }
990ef270ab1SKenneth D. Merry 
991ef270ab1SKenneth D. Merry static device_method_t ocs_methods[] = {
992ef270ab1SKenneth D. Merry 	DEVMETHOD(device_probe,		ocs_pci_probe),
993ef270ab1SKenneth D. Merry 	DEVMETHOD(device_attach,	ocs_pci_attach),
994ef270ab1SKenneth D. Merry 	DEVMETHOD(device_detach,	ocs_pci_detach),
995ef270ab1SKenneth D. Merry 	DEVMETHOD(device_shutdown,	ocs_pci_shutdown),
996ef270ab1SKenneth D. Merry 	{0, 0}
997ef270ab1SKenneth D. Merry };
998ef270ab1SKenneth D. Merry 
999ef270ab1SKenneth D. Merry static driver_t ocs_driver = {
1000ef270ab1SKenneth D. Merry 	"ocs_fc",
1001ef270ab1SKenneth D. Merry 	ocs_methods,
1002ef270ab1SKenneth D. Merry 	sizeof(struct ocs_softc)
1003ef270ab1SKenneth D. Merry };
1004ef270ab1SKenneth D. Merry 
1005*b64711b6SJohn Baldwin DRIVER_MODULE(ocs_fc, pci, ocs_driver, 0, 0);
1006ef270ab1SKenneth D. Merry MODULE_VERSION(ocs_fc, 1);
1007