xref: /illumos-gate/usr/src/uts/common/io/chxge/ch.c (revision ec71f88e)
1d39a76e7Sxw /*
2d39a76e7Sxw  * CDDL HEADER START
3d39a76e7Sxw  *
4d39a76e7Sxw  * The contents of this file are subject to the terms of the
5d39a76e7Sxw  * Common Development and Distribution License (the "License").
6d39a76e7Sxw  * You may not use this file except in compliance with the License.
7d39a76e7Sxw  *
8d39a76e7Sxw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d39a76e7Sxw  * or http://www.opensolaris.org/os/licensing.
10d39a76e7Sxw  * See the License for the specific language governing permissions
11d39a76e7Sxw  * and limitations under the License.
12d39a76e7Sxw  *
13d39a76e7Sxw  * When distributing Covered Code, include this CDDL HEADER in each
14d39a76e7Sxw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d39a76e7Sxw  * If applicable, add the following below this CDDL HEADER, with the
16d39a76e7Sxw  * fields enclosed by brackets "[]" replaced with your own identifying
17d39a76e7Sxw  * information: Portions Copyright [yyyy] [name of copyright owner]
18d39a76e7Sxw  *
19d39a76e7Sxw  * CDDL HEADER END
20d39a76e7Sxw  */
21d39a76e7Sxw 
22d39a76e7Sxw /*
2319397407SSherry Moore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24d39a76e7Sxw  * Use is subject to license terms.
25*ec71f88eSPatrick Mooney  * Copyright 2018 Joyent, Inc.
26d39a76e7Sxw  */
27d39a76e7Sxw 
28d39a76e7Sxw /*
29d39a76e7Sxw  * This file is part of the Chelsio T1 Ethernet driver.
30d39a76e7Sxw  *
31d39a76e7Sxw  * Copyright (C) 2003-2005 Chelsio Communications.  All rights reserved.
32d39a76e7Sxw  */
33d39a76e7Sxw 
34d39a76e7Sxw /*
35d39a76e7Sxw  * Solaris Multithreaded STREAMS DLPI Chelsio PCI Ethernet Driver
36d39a76e7Sxw  */
37d39a76e7Sxw 
38d39a76e7Sxw /* #define CH_DEBUG 1 */
39d39a76e7Sxw #ifdef CH_DEBUG
40d39a76e7Sxw #define	DEBUG_ENTER(a) debug_enter(a)
41d39a76e7Sxw #define	PRINT(a) printf a
42d39a76e7Sxw #else
43d39a76e7Sxw #define	DEBUG_ENTER(a)
44d39a76e7Sxw #define	PRINT(a)
45d39a76e7Sxw #endif
46d39a76e7Sxw 
47d39a76e7Sxw #include <sys/types.h>
48d39a76e7Sxw #include <sys/conf.h>
49d39a76e7Sxw #include <sys/debug.h>
50d39a76e7Sxw #include <sys/stropts.h>
51d39a76e7Sxw #include <sys/stream.h>
52d39a76e7Sxw #include <sys/strlog.h>
53d39a76e7Sxw #include <sys/kmem.h>
54d39a76e7Sxw #include <sys/stat.h>
55d39a76e7Sxw #include <sys/kstat.h>
56d39a76e7Sxw #include <sys/modctl.h>
57d39a76e7Sxw #include <sys/errno.h>
58d39a76e7Sxw #include <sys/cmn_err.h>
59d39a76e7Sxw #include <sys/ddi.h>
60d39a76e7Sxw #include <sys/sunddi.h>
61d39a76e7Sxw #include <sys/dlpi.h>
62d39a76e7Sxw #include <sys/ethernet.h>
63*ec71f88eSPatrick Mooney #include <sys/mac_provider.h>
64d39a76e7Sxw #include <sys/strsun.h>
65d39a76e7Sxw #include <sys/strsubr.h>
66d39a76e7Sxw #include <inet/common.h>
67d39a76e7Sxw #include <inet/nd.h>
68d39a76e7Sxw #include <inet/ip.h>
69d39a76e7Sxw #include <inet/tcp.h>
70d39a76e7Sxw #include <sys/pattr.h>
71d39a76e7Sxw #include <sys/gld.h>
72d39a76e7Sxw #include "ostypes.h"
73d39a76e7Sxw #include "common.h"
74d39a76e7Sxw #include "oschtoe.h"
75d39a76e7Sxw #include "sge.h"
7619397407SSherry Moore #include "regs.h"
77d39a76e7Sxw #include "ch.h"			/* Chelsio Driver specific parameters */
78d39a76e7Sxw #include "version.h"
79d39a76e7Sxw 
80d39a76e7Sxw /*
81d39a76e7Sxw  * Function prototypes.
82d39a76e7Sxw  */
83d39a76e7Sxw static int ch_attach(dev_info_t *, ddi_attach_cmd_t);
84d39a76e7Sxw static int ch_detach(dev_info_t *, ddi_detach_cmd_t);
8519397407SSherry Moore static int ch_quiesce(dev_info_t *);
86d39a76e7Sxw static void ch_free_dma_handles(ch_t *chp);
87d39a76e7Sxw static void ch_set_name(ch_t *chp, int unit);
88d39a76e7Sxw static void ch_free_name(ch_t *chp);
89d39a76e7Sxw static void ch_get_prop(ch_t *chp);
90d39a76e7Sxw 
91d39a76e7Sxw #if defined(__sparc)
92d39a76e7Sxw static void ch_free_dvma_handles(ch_t *chp);
93d39a76e7Sxw #endif
94d39a76e7Sxw 
95d39a76e7Sxw /* GLD interfaces */
96d39a76e7Sxw static int ch_reset(gld_mac_info_t *);
97d39a76e7Sxw static int ch_start(gld_mac_info_t *);
98d39a76e7Sxw static int ch_stop(gld_mac_info_t *);
99d39a76e7Sxw static int ch_set_mac_address(gld_mac_info_t *, uint8_t *);
100d39a76e7Sxw static int ch_set_multicast(gld_mac_info_t *, uint8_t *, int);
101d39a76e7Sxw static int ch_ioctl(gld_mac_info_t *, queue_t *, mblk_t *);
102d39a76e7Sxw static int ch_set_promiscuous(gld_mac_info_t *, int);
103d39a76e7Sxw static int ch_get_stats(gld_mac_info_t *, struct gld_stats *);
104d39a76e7Sxw static int ch_send(gld_mac_info_t *, mblk_t *);
105d39a76e7Sxw static uint_t ch_intr(gld_mac_info_t *);
106d39a76e7Sxw 
107d39a76e7Sxw /*
108d39a76e7Sxw  * Data access requirements.
109d39a76e7Sxw  */
110d39a76e7Sxw static struct ddi_device_acc_attr le_attr = {
111d39a76e7Sxw 	DDI_DEVICE_ATTR_V0,
112d39a76e7Sxw 	DDI_STRUCTURE_LE_ACC,
113d39a76e7Sxw 	DDI_STRICTORDER_ACC
114d39a76e7Sxw };
115d39a76e7Sxw 
116d39a76e7Sxw /*
117d39a76e7Sxw  * No swap mapping device attributes
118d39a76e7Sxw  */
119d39a76e7Sxw static struct ddi_device_acc_attr null_attr = {
120d39a76e7Sxw 	DDI_DEVICE_ATTR_V0,
121d39a76e7Sxw 	DDI_NEVERSWAP_ACC,
122d39a76e7Sxw 	DDI_STRICTORDER_ACC
123d39a76e7Sxw };
124d39a76e7Sxw 
125d39a76e7Sxw /*
126d39a76e7Sxw  * STREAMS driver identification struture module_info(9s)
127d39a76e7Sxw  *
128d39a76e7Sxw  * driver limit values
129d39a76e7Sxw  */
130d39a76e7Sxw 
131d39a76e7Sxw static	struct module_info ch_minfo = {
132d39a76e7Sxw 	CHIDNUM,	/* mi_idnum */
133d39a76e7Sxw 	CHNAME,		/* mi_idname */
134d39a76e7Sxw 	CHMINPSZ,	/* mi_minpsz */
135d39a76e7Sxw 	CHMAXPSZ,	/* mi_maxpsz */
136d39a76e7Sxw 	CHHIWAT,	/* mi_hiwat */
137d39a76e7Sxw 	CHLOWAT		/* mi_lowat */
138d39a76e7Sxw };
139d39a76e7Sxw 
140d39a76e7Sxw /*
141d39a76e7Sxw  * STREAMS queue processiong procedures qinit(9s)
142d39a76e7Sxw  *
143d39a76e7Sxw  * read queue procedures
144d39a76e7Sxw  */
145d39a76e7Sxw 
146d39a76e7Sxw static struct qinit ch_rinit = {
147d39a76e7Sxw 	(int (*)()) NULL, 	/* qi_putp */
148d39a76e7Sxw 	gld_rsrv,		/* qi_srvp */
149d39a76e7Sxw 	gld_open,		/* qi_qopen */
150d39a76e7Sxw 	gld_close,		/* qi_qclose */
151d39a76e7Sxw 	(int (*)()) NULL, 	/* qi_qadmin */
152d39a76e7Sxw 	&ch_minfo,		/* qi_minfo */
153d39a76e7Sxw 	NULL			/* qi_mstat */
154d39a76e7Sxw };
155d39a76e7Sxw 
156d39a76e7Sxw /*
157d39a76e7Sxw  * STREAMS queue processiong procedures qinit(9s)
158d39a76e7Sxw  *
159d39a76e7Sxw  * write queue procedures
160d39a76e7Sxw  */
161d39a76e7Sxw 
162d39a76e7Sxw static struct qinit ch_winit = {
163d39a76e7Sxw 	gld_wput,		/* qi_putp */
164d39a76e7Sxw 	gld_wsrv,		/* qi_srvp */
165d39a76e7Sxw 	(int (*)()) NULL, 	/* qi_qopen */
166d39a76e7Sxw 	(int (*)()) NULL, 	/* qi_qclose */
167d39a76e7Sxw 	(int (*)()) NULL, 	/* qi_qadmin */
168d39a76e7Sxw 	&ch_minfo,		/* qi_minfo */
169d39a76e7Sxw 	NULL			/* qi_mstat */
170d39a76e7Sxw };
171d39a76e7Sxw 
172d39a76e7Sxw /*
173d39a76e7Sxw  * STREAMS entity declaration structure - streamtab(9s)
174d39a76e7Sxw  */
175d39a76e7Sxw static struct streamtab	chinfo = {
176d39a76e7Sxw 	&ch_rinit,	/* read queue information */
177d39a76e7Sxw 	&ch_winit,	/* write queue information */
178d39a76e7Sxw 	NULL,		/* st_muxrinit */
179d39a76e7Sxw 	NULL		/* st_muxwrinit */
180d39a76e7Sxw };
181d39a76e7Sxw 
182d39a76e7Sxw /*
183d39a76e7Sxw  * Device driver ops vector - cb_ops(9s)
184d39a76e7Sxw  *
185d39a76e7Sxw  * charater/block entry points structure.
186d39a76e7Sxw  * chinfo identifies driver as a STREAMS driver.
187d39a76e7Sxw  */
188d39a76e7Sxw 
189d39a76e7Sxw static struct cb_ops cb_ch_ops = {
190d39a76e7Sxw 	nulldev,	/* cb_open */
191d39a76e7Sxw 	nulldev,	/* cb_close */
192d39a76e7Sxw 	nodev,		/* cb_strategy */
193d39a76e7Sxw 	nodev,		/* cb_print */
194d39a76e7Sxw 	nodev,		/* cb_dump */
195d39a76e7Sxw 	nodev,		/* cb_read */
196d39a76e7Sxw 	nodev,		/* cb_write */
197d39a76e7Sxw 	nodev,		/* cb_ioctl */
198d39a76e7Sxw 	nodev,		/* cb_devmap */
199d39a76e7Sxw 	nodev,		/* cb_mmap */
200d39a76e7Sxw 	nodev,		/* cb_segmap */
201d39a76e7Sxw 	nochpoll,	/* cb_chpoll */
202d39a76e7Sxw 	ddi_prop_op,	/* report driver property information - prop_op(9e) */
203d39a76e7Sxw 	&chinfo,	/* cb_stream */
204d39a76e7Sxw #if defined(__sparc)
205d39a76e7Sxw 	D_MP | D_64BIT,
206d39a76e7Sxw #else
207d39a76e7Sxw 	D_MP,		/* cb_flag (supports multi-threading) */
208d39a76e7Sxw #endif
209d39a76e7Sxw 	CB_REV,		/* cb_rev */
210d39a76e7Sxw 	nodev,		/* cb_aread */
211d39a76e7Sxw 	nodev		/* cb_awrite */
212d39a76e7Sxw };
213d39a76e7Sxw 
214d39a76e7Sxw /*
215d39a76e7Sxw  * dev_ops(9S) structure
216d39a76e7Sxw  *
217d39a76e7Sxw  * Device Operations table, for autoconfiguration
218d39a76e7Sxw  */
219d39a76e7Sxw 
220d39a76e7Sxw static	struct dev_ops ch_ops = {
221d39a76e7Sxw 	DEVO_REV,	/* Driver build version */
222d39a76e7Sxw 	0,		/* Initial driver reference count */
223d39a76e7Sxw 	gld_getinfo,	/* funcp: get driver information - getinfo(9e) */
224d39a76e7Sxw 	nulldev,	/* funcp: entry point obsolute - identify(9e) */
225d39a76e7Sxw 	nulldev,	/* funp: probe for device - probe(9e) */
226d39a76e7Sxw 	ch_attach,	/* funp: attach driver to dev_info - attach(9e) */
227d39a76e7Sxw 	ch_detach,	/* funp: detach driver to unload - detach(9e) */
228d39a76e7Sxw 	nodev,		/* funp: reset device (not supported) - dev_ops(9s) */
229d39a76e7Sxw 	&cb_ch_ops,	/* ptr to cb_ops structure */
230d39a76e7Sxw 	NULL,		/* ptr to nexus bus operations structure (leaf) */
23119397407SSherry Moore 	NULL,		/* funp: change device power level - power(9e) */
23219397407SSherry Moore 	ch_quiesce,	/* devo_quiesce */
233d39a76e7Sxw };
234d39a76e7Sxw 
235d39a76e7Sxw /*
236d39a76e7Sxw  * modldrv(9s) structure
237d39a76e7Sxw  *
238d39a76e7Sxw  * Definition for module specific device driver linkage structures (modctl.h)
239d39a76e7Sxw  */
240d39a76e7Sxw 
241d39a76e7Sxw static struct modldrv modldrv = {
242d39a76e7Sxw 	&mod_driverops,		/* driver module */
243d39a76e7Sxw 	VERSION,
244d39a76e7Sxw 	&ch_ops,		/* driver ops */
245d39a76e7Sxw };
246d39a76e7Sxw 
247d39a76e7Sxw /*
248d39a76e7Sxw  * modlinkage(9s) structure
249d39a76e7Sxw  *
250d39a76e7Sxw  * module linkage base structure (modctl.h)
251d39a76e7Sxw  */
252d39a76e7Sxw 
253d39a76e7Sxw static struct modlinkage modlinkage = {
254d39a76e7Sxw 	MODREV_1,		/* revision # of system */
255d39a76e7Sxw 	&modldrv,		/* NULL terminated list of linkage strucures */
256d39a76e7Sxw 	NULL
257d39a76e7Sxw };
258d39a76e7Sxw 
259d39a76e7Sxw /* ===================== start of STREAMS driver code ================== */
260d39a76e7Sxw 
261d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
262d39a76e7Sxw /*
263d39a76e7Sxw  * global pointer to toe per-driver control structure.
264d39a76e7Sxw  */
265d39a76e7Sxw #define	MAX_CARDS	4
266d39a76e7Sxw ch_t *gchp[MAX_CARDS];
267d39a76e7Sxw #endif
268d39a76e7Sxw 
269d39a76e7Sxw kmutex_t in_use_l;
270d39a76e7Sxw uint32_t buffers_in_use[SZ_INUSE];
271d39a76e7Sxw uint32_t in_use_index;
272d39a76e7Sxw 
273d39a76e7Sxw /*
274d39a76e7Sxw  * Ethernet broadcast address definition.
275d39a76e7Sxw  */
276d39a76e7Sxw static struct ether_addr etherbroadcastaddr = {
277d39a76e7Sxw 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
278d39a76e7Sxw };
279d39a76e7Sxw 
280d39a76e7Sxw /*
281d39a76e7Sxw  * Module initialization functions.
282d39a76e7Sxw  *
283d39a76e7Sxw  *      Routine         Called by
284d39a76e7Sxw  *      _init(9E)       modload(9F)
285d39a76e7Sxw  *      _info(9E)       modinfo(9F)
286d39a76e7Sxw  *      _fini(9E)       modunload(9F)
287d39a76e7Sxw  */
288d39a76e7Sxw 
289d39a76e7Sxw /*
290d39a76e7Sxw  * _init(9E):
291d39a76e7Sxw  *
292d39a76e7Sxw  * Initial, one-time, resource allocation and data initialization.
293d39a76e7Sxw  */
294d39a76e7Sxw 
295d39a76e7Sxw int
_init(void)296d39a76e7Sxw _init(void)
297d39a76e7Sxw {
298d39a76e7Sxw 	int status;
299d39a76e7Sxw 
300d39a76e7Sxw 	status = mod_install(&modlinkage);
301d39a76e7Sxw 
302d39a76e7Sxw 	mutex_init(&in_use_l, NULL, MUTEX_DRIVER, NULL);
303d39a76e7Sxw 
304d39a76e7Sxw 	return (status);
305d39a76e7Sxw }
306d39a76e7Sxw 
307d39a76e7Sxw /*
308d39a76e7Sxw  * _fini(9E): It is here that any device information that was allocated
309d39a76e7Sxw  * during the _init(9E) routine should be released and the module removed
310d39a76e7Sxw  * from the system.  In the case of per-instance information, that information
311d39a76e7Sxw  * should be released in the _detach(9E) routine.
312d39a76e7Sxw  */
313d39a76e7Sxw 
314d39a76e7Sxw int
_fini(void)315d39a76e7Sxw _fini(void)
316d39a76e7Sxw {
317d39a76e7Sxw 	int status;
318d39a76e7Sxw 	int i;
319d39a76e7Sxw 	uint32_t t = 0;
320d39a76e7Sxw 
321d39a76e7Sxw 	for (i = 0; i < SZ_INUSE; i++)
322d39a76e7Sxw 		t += buffers_in_use[i];
323d39a76e7Sxw 
32411abda1eSToomas Soome 	if (t != 0)
325d39a76e7Sxw 		return (DDI_FAILURE);
326d39a76e7Sxw 
327d39a76e7Sxw 	status = mod_remove(&modlinkage);
328d39a76e7Sxw 
329d39a76e7Sxw 	if (status == DDI_SUCCESS)
330d39a76e7Sxw 		mutex_destroy(&in_use_l);
331d39a76e7Sxw 
332d39a76e7Sxw 	return (status);
333d39a76e7Sxw }
334d39a76e7Sxw 
335d39a76e7Sxw int
_info(struct modinfo * modinfop)336d39a76e7Sxw _info(struct modinfo *modinfop)
337d39a76e7Sxw {
338d39a76e7Sxw 	int status;
339d39a76e7Sxw 
340d39a76e7Sxw 
341d39a76e7Sxw 	status = mod_info(&modlinkage, modinfop);
342d39a76e7Sxw 
343d39a76e7Sxw 	return (status);
344d39a76e7Sxw }
345d39a76e7Sxw 
346d39a76e7Sxw /*
347d39a76e7Sxw  * Attach(9E) - This is called on the open to the device.  It creates
348d39a76e7Sxw  * an instance of the driver.  In this routine we create the minor
349d39a76e7Sxw  * device node.  The routine also initializes all per-unit
350d39a76e7Sxw  * mutex's and conditional variables.
351d39a76e7Sxw  *
352d39a76e7Sxw  * If we were resuming a suspended instance of a device due to power
353d39a76e7Sxw  * management, then that would be handled here as well.  For more on
354d39a76e7Sxw  * that subject see the man page for pm(9E)
355d39a76e7Sxw  *
356d39a76e7Sxw  * Interface exists: make available by filling in network interface
357d39a76e7Sxw  * record.  System will initialize the interface when it is ready
358d39a76e7Sxw  * to accept packets.
359d39a76e7Sxw  */
360d39a76e7Sxw int chdebug = 0;
361d39a76e7Sxw int ch_abort_debug = 0;
362d39a76e7Sxw 
363d39a76e7Sxw static int
ch_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)364d39a76e7Sxw ch_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
365d39a76e7Sxw {
366d39a76e7Sxw 	ch_t *chp;
367d39a76e7Sxw 	int rv;
368d39a76e7Sxw 	int unit;
369d39a76e7Sxw #ifdef CH_DEBUG
370d39a76e7Sxw 	int Version;
371d39a76e7Sxw 	int VendorID;
372d39a76e7Sxw 	int DeviceID;
373d39a76e7Sxw 	int SubDeviceID;
374d39a76e7Sxw 	int Command;
375d39a76e7Sxw #endif
376d39a76e7Sxw 	gld_mac_info_t *macinfo;		/* GLD stuff follows */
377d39a76e7Sxw 	char *driver;
378d39a76e7Sxw 
379d39a76e7Sxw 	if (ch_abort_debug)
380d39a76e7Sxw 		debug_enter("ch_attach");
381d39a76e7Sxw 
382d39a76e7Sxw 	if (chdebug)
383d39a76e7Sxw 		return (DDI_FAILURE);
384d39a76e7Sxw 
385d39a76e7Sxw 
386d39a76e7Sxw 	if (cmd == DDI_ATTACH) {
387d39a76e7Sxw 
388d39a76e7Sxw 		unit = ddi_get_instance(dip);
389d39a76e7Sxw 
390d39a76e7Sxw 		driver = (char *)ddi_driver_name(dip);
391d39a76e7Sxw 
392d39a76e7Sxw 		PRINT(("driver %s unit: %d\n", driver, unit));
393d39a76e7Sxw 
394d39a76e7Sxw 		macinfo = gld_mac_alloc(dip);
395d39a76e7Sxw 		if (macinfo == NULL) {
396d39a76e7Sxw 			PRINT(("macinfo allocation failed\n"));
397d39a76e7Sxw 			DEBUG_ENTER("ch_attach");
398d39a76e7Sxw 			return (DDI_FAILURE);
399d39a76e7Sxw 		}
400d39a76e7Sxw 
401d39a76e7Sxw 		chp = (ch_t *)kmem_zalloc(sizeof (ch_t), KM_SLEEP);
402d39a76e7Sxw 
403d39a76e7Sxw 		if (chp == NULL) {
404d39a76e7Sxw 			PRINT(("zalloc of chp failed\n"));
405d39a76e7Sxw 			DEBUG_ENTER("ch_attach");
406d39a76e7Sxw 
407d39a76e7Sxw 			gld_mac_free(macinfo);
408d39a76e7Sxw 
409d39a76e7Sxw 			return (DDI_FAILURE);
410d39a76e7Sxw 		}
411d39a76e7Sxw 
412d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
413d39a76e7Sxw 		/* Solaris TOE support */
414d39a76e7Sxw 		gchp[unit] = chp;
415d39a76e7Sxw #endif
416d39a76e7Sxw 
417d39a76e7Sxw 		PRINT(("attach macinfo: %p chp: %p\n", macinfo, chp));
418d39a76e7Sxw 
419d39a76e7Sxw 		chp->ch_dip  = dip;
420d39a76e7Sxw 		chp->ch_macp = macinfo;
421d39a76e7Sxw 		chp->ch_unit = unit;
422d39a76e7Sxw 		ch_set_name(chp, unit);
423d39a76e7Sxw 
424d39a76e7Sxw 		/*
425d39a76e7Sxw 		 * map in PCI register spaces
426d39a76e7Sxw 		 *
427d39a76e7Sxw 		 * PCI register set 0 - PCI configuration space
428d39a76e7Sxw 		 * PCI register set 1 - T101 card register space #1
429d39a76e7Sxw 		 */
430d39a76e7Sxw 
431d39a76e7Sxw 		/* map in T101 PCI configuration space */
432d39a76e7Sxw 		rv = pci_config_setup(
43319397407SSherry Moore 		    dip,		/* ptr to dev's dev_info struct */
43419397407SSherry Moore 		    &chp->ch_hpci);	/* ptr to data access handle */
435d39a76e7Sxw 
436d39a76e7Sxw 		if (rv != DDI_SUCCESS) {
437d39a76e7Sxw 			PRINT(("PCI config setup failed\n"));
438d39a76e7Sxw 			DEBUG_ENTER("ch_attach");
439d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
440d39a76e7Sxw 			gchp[unit] = NULL;
441d39a76e7Sxw #endif
442d39a76e7Sxw 			cmn_err(CE_WARN, "%s: ddi_config_setup PCI error %d\n",
44319397407SSherry Moore 			    chp->ch_name, rv);
444d39a76e7Sxw 
445d39a76e7Sxw 			ch_free_name(chp);
446d39a76e7Sxw 			kmem_free(chp, sizeof (ch_t));
447d39a76e7Sxw 			gld_mac_free(macinfo);
448d39a76e7Sxw 
449d39a76e7Sxw 			return (DDI_FAILURE);
450d39a76e7Sxw 		}
451d39a76e7Sxw 
452d39a76e7Sxw 		ch_get_prop(chp);
453d39a76e7Sxw 
454d39a76e7Sxw 		macinfo->gldm_devinfo = dip;
455d39a76e7Sxw 		macinfo->gldm_private = (caddr_t)chp;
456d39a76e7Sxw 		macinfo->gldm_reset = ch_reset;
457d39a76e7Sxw 		macinfo->gldm_start = ch_start;
458d39a76e7Sxw 		macinfo->gldm_stop = ch_stop;
459d39a76e7Sxw 		macinfo->gldm_set_mac_addr = ch_set_mac_address;
460d39a76e7Sxw 		macinfo->gldm_send = ch_send;
461d39a76e7Sxw 		macinfo->gldm_set_promiscuous = ch_set_promiscuous;
462d39a76e7Sxw 		macinfo->gldm_get_stats = ch_get_stats;
463d39a76e7Sxw 		macinfo->gldm_ioctl = ch_ioctl;
464d39a76e7Sxw 		macinfo->gldm_set_multicast = ch_set_multicast;
465d39a76e7Sxw 		macinfo->gldm_intr = ch_intr;
466d39a76e7Sxw 		macinfo->gldm_mctl = NULL;
467d39a76e7Sxw 
468d39a76e7Sxw 		macinfo->gldm_ident = driver;
469d39a76e7Sxw 		macinfo->gldm_type = DL_ETHER;
470d39a76e7Sxw 		macinfo->gldm_minpkt = 0;
471d39a76e7Sxw 		macinfo->gldm_maxpkt = chp->ch_mtu;
472d39a76e7Sxw 		macinfo->gldm_addrlen = ETHERADDRL;
473d39a76e7Sxw 		macinfo->gldm_saplen = -2;
474d39a76e7Sxw 		macinfo->gldm_ppa = unit;
475d39a76e7Sxw 		macinfo->gldm_broadcast_addr =
47619397407SSherry Moore 		    etherbroadcastaddr.ether_addr_octet;
477d39a76e7Sxw 
478d39a76e7Sxw 
479d39a76e7Sxw 		/*
480d39a76e7Sxw 		 * do a power reset of card
481d39a76e7Sxw 		 *
482d39a76e7Sxw 		 * 1. set PwrState to D3hot (3)
483d39a76e7Sxw 		 * 2. clear PwrState flags
484d39a76e7Sxw 		 */
485d39a76e7Sxw 		pci_config_put32(chp->ch_hpci, 0x44, 3);
486d39a76e7Sxw 		pci_config_put32(chp->ch_hpci, 0x44, 0);
487d39a76e7Sxw 
488d39a76e7Sxw 		/* delay .5 sec */
489d39a76e7Sxw 		DELAY(500000);
490d39a76e7Sxw 
491d39a76e7Sxw #ifdef CH_DEBUG
492d39a76e7Sxw 		VendorID    = pci_config_get16(chp->ch_hpci, 0);
493d39a76e7Sxw 		DeviceID    = pci_config_get16(chp->ch_hpci, 2);
494d39a76e7Sxw 		SubDeviceID = pci_config_get16(chp->ch_hpci, 0x2e);
495d39a76e7Sxw 		Command = pci_config_get16(chp->ch_hpci, 4);
496d39a76e7Sxw 
497d39a76e7Sxw 		PRINT(("IDs: %x,%x,%x\n", VendorID, DeviceID, SubDeviceID));
498d39a76e7Sxw 		PRINT(("Command: %x\n", Command));
499d39a76e7Sxw #endif
500d39a76e7Sxw 		/* map in T101 register space (BAR0) */
501d39a76e7Sxw 		rv = ddi_regs_map_setup(
50219397407SSherry Moore 		    dip,		/* ptr to dev's dev_info struct */
50319397407SSherry Moore 		    BAR0,		/* register address space */
50419397407SSherry Moore 		    &chp->ch_bar0,	/* address of offset */
50519397407SSherry Moore 		    0,		/* offset into register address space */
50619397407SSherry Moore 		    0,		/* length mapped (everything) */
50719397407SSherry Moore 		    &le_attr,	/* ptr to device attr structure */
50819397407SSherry Moore 		    &chp->ch_hbar0);	/* ptr to data access handle */
509d39a76e7Sxw 
510d39a76e7Sxw 		if (rv != DDI_SUCCESS) {
511d39a76e7Sxw 			PRINT(("map registers failed\n"));
512d39a76e7Sxw 			DEBUG_ENTER("ch_attach");
513d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
514d39a76e7Sxw 			gchp[unit] = NULL;
515d39a76e7Sxw #endif
516d39a76e7Sxw 			cmn_err(CE_WARN,
51719397407SSherry Moore 			    "%s: ddi_regs_map_setup BAR0 error %d\n",
51819397407SSherry Moore 			    chp->ch_name, rv);
519d39a76e7Sxw 
520d39a76e7Sxw 			pci_config_teardown(&chp->ch_hpci);
521d39a76e7Sxw 			ch_free_name(chp);
522d39a76e7Sxw 			kmem_free(chp, sizeof (ch_t));
523d39a76e7Sxw 			gld_mac_free(macinfo);
524d39a76e7Sxw 
525d39a76e7Sxw 			return (DDI_FAILURE);
526d39a76e7Sxw 		}
527d39a76e7Sxw 
528d39a76e7Sxw #ifdef CH_DEBUG
529d39a76e7Sxw 		Version  = ddi_get32(chp->ch_hbar0,
53019397407SSherry Moore 		    (uint32_t *)(chp->ch_bar0+0x6c));
531d39a76e7Sxw #endif
532d39a76e7Sxw 
533d39a76e7Sxw 		(void) ddi_dev_regsize(dip, 1, &chp->ch_bar0sz);
534d39a76e7Sxw 
535d39a76e7Sxw 		PRINT(("PCI BAR0 space addr: %p\n", chp->ch_bar0));
536d39a76e7Sxw 		PRINT(("PCI BAR0 space size: %x\n", chp->ch_bar0sz));
537d39a76e7Sxw 		PRINT(("PE Version: %x\n", Version));
538d39a76e7Sxw 
539d39a76e7Sxw 		/*
540d39a76e7Sxw 		 * Add interrupt to system.
541d39a76e7Sxw 		 */
542d39a76e7Sxw 		rv = ddi_get_iblock_cookie(
54319397407SSherry Moore 		    dip,		   /* ptr to dev's dev_info struct */
54419397407SSherry Moore 		    0,		   /* interrupt # (0) */
54519397407SSherry Moore 		    &chp->ch_icookp); /* ptr to interrupt block cookie */
546d39a76e7Sxw 
547d39a76e7Sxw 		if (rv != DDI_SUCCESS) {
548d39a76e7Sxw 			PRINT(("iblock cookie failed\n"));
549d39a76e7Sxw 			DEBUG_ENTER("ch_attach");
550d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
551d39a76e7Sxw 			gchp[unit] = NULL;
552d39a76e7Sxw #endif
553d39a76e7Sxw 			cmn_err(CE_WARN,
55419397407SSherry Moore 			    "%s: ddi_get_iblock_cookie error %d\n",
55519397407SSherry Moore 			    chp->ch_name, rv);
556d39a76e7Sxw 
557d39a76e7Sxw 			ddi_regs_map_free(&chp->ch_hbar0);
558d39a76e7Sxw 			pci_config_teardown(&chp->ch_hpci);
559d39a76e7Sxw 			ch_free_name(chp);
560d39a76e7Sxw 			kmem_free(chp, sizeof (ch_t));
561d39a76e7Sxw 			gld_mac_free(macinfo);
562d39a76e7Sxw 
563d39a76e7Sxw 			return (DDI_FAILURE);
564d39a76e7Sxw 		}
565d39a76e7Sxw 
566d39a76e7Sxw 		/*
567d39a76e7Sxw 		 * add interrupt handler before card setup.
568d39a76e7Sxw 		 */
569d39a76e7Sxw 		rv = ddi_add_intr(
57019397407SSherry Moore 		    dip,		/* ptr to dev's dev_info struct */
57119397407SSherry Moore 		    0,		/* interrupt # (0) */
57219397407SSherry Moore 		    0,		/* iblock cookie ptr (NULL) */
57319397407SSherry Moore 		    0,		/* idevice cookie ptr (NULL) */
57419397407SSherry Moore 		    gld_intr,	/* function ptr to interrupt handler */
57519397407SSherry Moore 		    (caddr_t)macinfo);	/* handler argument */
576d39a76e7Sxw 
577d39a76e7Sxw 		if (rv != DDI_SUCCESS) {
578d39a76e7Sxw 			PRINT(("add_intr failed\n"));
579d39a76e7Sxw 			DEBUG_ENTER("ch_attach");
580d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
581d39a76e7Sxw 			gchp[unit] = NULL;
582d39a76e7Sxw #endif
583d39a76e7Sxw 			cmn_err(CE_WARN, "%s: ddi_add_intr error %d\n",
58419397407SSherry Moore 			    chp->ch_name, rv);
585d39a76e7Sxw 
586d39a76e7Sxw 			ddi_regs_map_free(&chp->ch_hbar0);
587d39a76e7Sxw 			pci_config_teardown(&chp->ch_hpci);
588d39a76e7Sxw 			ch_free_name(chp);
589d39a76e7Sxw 			kmem_free(chp, sizeof (ch_t));
590d39a76e7Sxw 			gld_mac_free(macinfo);
591d39a76e7Sxw 
592d39a76e7Sxw 			return (DDI_FAILURE);
593d39a76e7Sxw 		}
594d39a76e7Sxw 
595d39a76e7Sxw 		/* initalize all the remaining per-card locks */
596d39a76e7Sxw 		mutex_init(&chp->ch_lock, NULL, MUTEX_DRIVER,
59719397407SSherry Moore 		    (void *)chp->ch_icookp);
598d39a76e7Sxw 		mutex_init(&chp->ch_intr, NULL, MUTEX_DRIVER,
59919397407SSherry Moore 		    (void *)chp->ch_icookp);
600d39a76e7Sxw 		mutex_init(&chp->ch_mc_lck, NULL, MUTEX_DRIVER, NULL);
601d39a76e7Sxw 		mutex_init(&chp->ch_dh_lck, NULL, MUTEX_DRIVER, NULL);
602d39a76e7Sxw 		mutex_init(&chp->mac_lock, NULL, MUTEX_DRIVER, NULL);
603d39a76e7Sxw 
604d39a76e7Sxw 		/* ------- initialize Chelsio card ------- */
605d39a76e7Sxw 
606d39a76e7Sxw 		if (pe_attach(chp)) {
607d39a76e7Sxw 			PRINT(("card initialization failed\n"));
608d39a76e7Sxw 			DEBUG_ENTER("ch_attach");
609d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
610d39a76e7Sxw 			gchp[unit] = NULL;
611d39a76e7Sxw #endif
612d39a76e7Sxw 			cmn_err(CE_WARN, "%s: pe_attach failed\n",
61319397407SSherry Moore 			    chp->ch_name);
614d39a76e7Sxw 
615d39a76e7Sxw 			mutex_destroy(&chp->ch_lock);
616d39a76e7Sxw 			mutex_destroy(&chp->ch_intr);
617d39a76e7Sxw 			mutex_destroy(&chp->ch_mc_lck);
618d39a76e7Sxw 			mutex_destroy(&chp->ch_dh_lck);
619d39a76e7Sxw 			mutex_destroy(&chp->mac_lock);
620d39a76e7Sxw 			ddi_remove_intr(dip, 0, chp->ch_icookp);
621d39a76e7Sxw 			ddi_regs_map_free(&chp->ch_hbar0);
622d39a76e7Sxw 			pci_config_teardown(&chp->ch_hpci);
623d39a76e7Sxw 			ch_free_name(chp);
624d39a76e7Sxw 			kmem_free(chp, sizeof (ch_t));
625d39a76e7Sxw 			gld_mac_free(macinfo);
626d39a76e7Sxw 
627d39a76e7Sxw 			return (DDI_FAILURE);
628d39a76e7Sxw 		}
629d39a76e7Sxw 
630d39a76e7Sxw 		/* ------- done with Chelsio card ------- */
631d39a76e7Sxw 
632d39a76e7Sxw 		/* now can  set mac address */
633d39a76e7Sxw 		macinfo->gldm_vendor_addr = pe_get_mac(chp);
634d39a76e7Sxw 
635d39a76e7Sxw 		macinfo->gldm_cookie = chp->ch_icookp;
636d39a76e7Sxw 
637d39a76e7Sxw 		/*
638d39a76e7Sxw 		 * We only active checksum offload for T2 architectures.
639d39a76e7Sxw 		 */
640d39a76e7Sxw 		if (is_T2(chp)) {
641d39a76e7Sxw 			if (chp->ch_config.cksum_enabled)
642d39a76e7Sxw 				macinfo->gldm_capabilities |=
643d39a76e7Sxw 				    GLD_CAP_CKSUM_FULL_V4;
644d39a76e7Sxw 		} else
645d39a76e7Sxw 			chp->ch_config.cksum_enabled = 0;
646d39a76e7Sxw 
647d39a76e7Sxw 		rv = gld_register(
64819397407SSherry Moore 		    dip,		/* ptr to dev's dev_info struct */
64919397407SSherry Moore 		    (char *)ddi_driver_name(dip),	/* driver name */
65019397407SSherry Moore 		    macinfo);	/* ptr to gld macinfo buffer */
651d39a76e7Sxw 
652d39a76e7Sxw 		/*
653d39a76e7Sxw 		 * The Jumbo frames capability is not yet available
654d39a76e7Sxw 		 * in Solaris 10 so registration will fail. MTU > 1500 is
655d39a76e7Sxw 		 * supported in Update 1.
656d39a76e7Sxw 		 */
657d39a76e7Sxw 		if (rv != DDI_SUCCESS) {
658d39a76e7Sxw 			cmn_err(CE_NOTE, "MTU > 1500 not supported by GLD.\n");
659d39a76e7Sxw 			cmn_err(CE_NOTE, "Setting MTU to 1500. \n");
660d39a76e7Sxw 			macinfo->gldm_maxpkt = chp->ch_mtu = 1500;
661d39a76e7Sxw 			rv = gld_register(
66219397407SSherry Moore 			    dip,	/* ptr to dev's dev_info struct */
66319397407SSherry Moore 			    (char *)ddi_driver_name(dip), /* driver name */
66419397407SSherry Moore 			    macinfo); /* ptr to gld macinfo buffer */
665d39a76e7Sxw 		}
666d39a76e7Sxw 
667d39a76e7Sxw 
668d39a76e7Sxw 		if (rv != DDI_SUCCESS) {
669d39a76e7Sxw 			PRINT(("gld_register failed\n"));
670d39a76e7Sxw 			DEBUG_ENTER("ch_attach");
671d39a76e7Sxw 
672d39a76e7Sxw 			cmn_err(CE_WARN, "%s: gld_register error %d\n",
67319397407SSherry Moore 			    chp->ch_name, rv);
674d39a76e7Sxw 
675d39a76e7Sxw 			pe_detach(chp);
676d39a76e7Sxw 
677d39a76e7Sxw 			mutex_destroy(&chp->ch_lock);
678d39a76e7Sxw 			mutex_destroy(&chp->ch_intr);
679d39a76e7Sxw 			mutex_destroy(&chp->ch_mc_lck);
680d39a76e7Sxw 			mutex_destroy(&chp->ch_dh_lck);
681d39a76e7Sxw 			mutex_destroy(&chp->mac_lock);
682d39a76e7Sxw 			ddi_remove_intr(dip, 0, chp->ch_icookp);
683d39a76e7Sxw 			ddi_regs_map_free(&chp->ch_hbar0);
684d39a76e7Sxw 			pci_config_teardown(&chp->ch_hpci);
685d39a76e7Sxw 			ch_free_name(chp);
686d39a76e7Sxw 			kmem_free(chp, sizeof (ch_t));
687d39a76e7Sxw 			gld_mac_free(macinfo);
688d39a76e7Sxw 
689d39a76e7Sxw 			return (DDI_FAILURE);
690d39a76e7Sxw 		}
691d39a76e7Sxw 
692d39a76e7Sxw 		/*
693d39a76e7Sxw 		 * print a banner at boot time (verbose mode), announcing
694d39a76e7Sxw 		 * the device pointed to by dip
695d39a76e7Sxw 		 */
696d39a76e7Sxw 		ddi_report_dev(dip);
697d39a76e7Sxw 
698d39a76e7Sxw 		if (ch_abort_debug)
699d39a76e7Sxw 			debug_enter("ch_attach");
700d39a76e7Sxw 
701d39a76e7Sxw 		return (DDI_SUCCESS);
702d39a76e7Sxw 
703d39a76e7Sxw 	} else if (cmd == DDI_RESUME) {
704d39a76e7Sxw 		PRINT(("attach resume\n"));
705d39a76e7Sxw 		DEBUG_ENTER("ch_attach");
706d39a76e7Sxw 		if ((chp = (ch_t *)ddi_get_driver_private(dip)) == NULL)
707d39a76e7Sxw 			return (DDI_FAILURE);
708d39a76e7Sxw 
709d39a76e7Sxw 		mutex_enter(&chp->ch_lock);
710d39a76e7Sxw 		chp->ch_flags &= ~PESUSPENDED;
711d39a76e7Sxw 		mutex_exit(&chp->ch_lock);
712d39a76e7Sxw 		return (DDI_SUCCESS);
713d39a76e7Sxw 	} else {
714d39a76e7Sxw 		PRINT(("attach: bad command\n"));
715d39a76e7Sxw 		DEBUG_ENTER("ch_attach");
716d39a76e7Sxw 
717d39a76e7Sxw 		return (DDI_FAILURE);
718d39a76e7Sxw 	}
719d39a76e7Sxw }
720d39a76e7Sxw 
72119397407SSherry Moore /*
72219397407SSherry Moore  * quiesce(9E) entry point.
72319397407SSherry Moore  *
72419397407SSherry Moore  * This function is called when the system is single-threaded at high
72519397407SSherry Moore  * PIL with preemption disabled. Therefore, this function must not be
72619397407SSherry Moore  * blocked.
72719397407SSherry Moore  *
72819397407SSherry Moore  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
72919397407SSherry Moore  * DDI_FAILURE indicates an error condition and should almost never happen.
73019397407SSherry Moore  */
73119397407SSherry Moore static int
ch_quiesce(dev_info_t * dip)73219397407SSherry Moore ch_quiesce(dev_info_t *dip)
73319397407SSherry Moore {
73419397407SSherry Moore 	ch_t *chp;
73519397407SSherry Moore 	gld_mac_info_t *macinfo =
73619397407SSherry Moore 	    (gld_mac_info_t *)ddi_get_driver_private(dip);
73719397407SSherry Moore 
73819397407SSherry Moore 	chp = (ch_t *)macinfo->gldm_private;
73919397407SSherry Moore 	chdebug = 0;
74019397407SSherry Moore 	ch_abort_debug = 0;
74119397407SSherry Moore 
74219397407SSherry Moore #ifdef CONFIG_CHELSIO_T1_OFFLOAD
74319397407SSherry Moore 	gchp[chp->ch_unit] = NULL;
74419397407SSherry Moore #endif
74519397407SSherry Moore 
74619397407SSherry Moore 	/* Set driver state for this card to IDLE */
74719397407SSherry Moore 	chp->ch_state = PEIDLE;
74819397407SSherry Moore 
74919397407SSherry Moore 	/*
75019397407SSherry Moore 	 * Do a power reset of card
75119397407SSherry Moore 	 * 1. set PwrState to D3hot (3)
75219397407SSherry Moore 	 * 2. clear PwrState flags
75319397407SSherry Moore 	 */
75419397407SSherry Moore 	pci_config_put32(chp->ch_hpci, 0x44, 3);
75519397407SSherry Moore 	pci_config_put32(chp->ch_hpci, 0x44, 0);
75619397407SSherry Moore 
75719397407SSherry Moore 	/* Wait 0.5 sec */
75819397407SSherry Moore 	drv_usecwait(500000);
75919397407SSherry Moore 
76019397407SSherry Moore 	/*
76119397407SSherry Moore 	 * Now stop the chip
76219397407SSherry Moore 	 */
76319397407SSherry Moore 	chp->ch_refcnt = 0;
76419397407SSherry Moore 	chp->ch_state = PESTOP;
76519397407SSherry Moore 
76619397407SSherry Moore 	/* Disables all interrupts */
76719397407SSherry Moore 	t1_interrupts_disable(chp);
76819397407SSherry Moore 
76919397407SSherry Moore 	/* Disables SGE queues */
77019397407SSherry Moore 	t1_write_reg_4(chp->sge->obj, A_SG_CONTROL, 0x0);
77119397407SSherry Moore 	t1_write_reg_4(chp->sge->obj, A_SG_INT_CAUSE, 0x0);
77219397407SSherry Moore 
77319397407SSherry Moore 	return (DDI_SUCCESS);
77419397407SSherry Moore }
77519397407SSherry Moore 
776d39a76e7Sxw static int
ch_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)777d39a76e7Sxw ch_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
778d39a76e7Sxw {
779d39a76e7Sxw 	gld_mac_info_t *macinfo;
780d39a76e7Sxw 	ch_t *chp;
781d39a76e7Sxw 
782d39a76e7Sxw 	if (cmd == DDI_DETACH) {
783d39a76e7Sxw 		macinfo = (gld_mac_info_t *)ddi_get_driver_private(dip);
784d39a76e7Sxw 		chp = (ch_t *)macinfo->gldm_private;
785d39a76e7Sxw 
786d39a76e7Sxw 		/*
787d39a76e7Sxw 		 * fail detach if there are outstanding mblks still
788d39a76e7Sxw 		 * in use somewhere.
789d39a76e7Sxw 		 */
790d39a76e7Sxw 		DEBUG_ENTER("ch_detach");
791d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
792d39a76e7Sxw 		mutex_enter(&chp->ch_lock);
793d39a76e7Sxw 		if (chp->ch_refcnt > 0) {
794d39a76e7Sxw 			mutex_exit(&chp->ch_lock);
795d39a76e7Sxw 			return (DDI_FAILURE);
796d39a76e7Sxw 		}
797d39a76e7Sxw 		mutex_exit(&chp->ch_lock);
798d39a76e7Sxw 		gchp[chp->ch_unit] = NULL;
799d39a76e7Sxw #endif
800d39a76e7Sxw 		/*
801d39a76e7Sxw 		 * set driver state for this card to IDLE. We're
802d39a76e7Sxw 		 * shutting down.
803d39a76e7Sxw 		 */
804d39a76e7Sxw 		mutex_enter(&chp->ch_lock);
805d39a76e7Sxw 		chp->ch_state = PEIDLE;
806d39a76e7Sxw 		mutex_exit(&chp->ch_lock);
807d39a76e7Sxw 
808d39a76e7Sxw 		/*
809d39a76e7Sxw 		 * do a power reset of card
810d39a76e7Sxw 		 *
811d39a76e7Sxw 		 * 1. set PwrState to D3hot (3)
812d39a76e7Sxw 		 * 2. clear PwrState flags
813d39a76e7Sxw 		 */
814d39a76e7Sxw 		pci_config_put32(chp->ch_hpci, 0x44, 3);
815d39a76e7Sxw 		pci_config_put32(chp->ch_hpci, 0x44, 0);
816d39a76e7Sxw 
817d39a76e7Sxw 		/* delay .5 sec */
818d39a76e7Sxw 		DELAY(500000);
819d39a76e7Sxw 
820d39a76e7Sxw 		/* free register resources */
821d39a76e7Sxw 		(void) gld_unregister(macinfo);
822d39a76e7Sxw 
823d39a76e7Sxw 		/* make sure no interrupts while shutting down card */
824d39a76e7Sxw 		ddi_remove_intr(dip, 0, chp->ch_icookp);
825d39a76e7Sxw 
826d39a76e7Sxw 		/*
827d39a76e7Sxw 		 * reset device and recover resources
828d39a76e7Sxw 		 */
829d39a76e7Sxw 		pe_detach(chp);
830d39a76e7Sxw 
831d39a76e7Sxw 		ddi_regs_map_free(&chp->ch_hbar0);
832d39a76e7Sxw 		pci_config_teardown(&chp->ch_hpci);
833d39a76e7Sxw 		mutex_destroy(&chp->ch_lock);
834d39a76e7Sxw 		mutex_destroy(&chp->ch_intr);
835d39a76e7Sxw 		mutex_destroy(&chp->ch_mc_lck);
836d39a76e7Sxw 		mutex_destroy(&chp->ch_dh_lck);
837d39a76e7Sxw 		mutex_destroy(&chp->mac_lock);
838d39a76e7Sxw 		ch_free_dma_handles(chp);
839d39a76e7Sxw #if defined(__sparc)
840d39a76e7Sxw 		ch_free_dvma_handles(chp);
841d39a76e7Sxw #endif
842d39a76e7Sxw 		ch_free_name(chp);
843d39a76e7Sxw 		kmem_free(chp, sizeof (ch_t));
844d39a76e7Sxw 		gld_mac_free(macinfo);
845d39a76e7Sxw 
846d39a76e7Sxw 		DEBUG_ENTER("ch_detach end");
847d39a76e7Sxw 
848d39a76e7Sxw 		return (DDI_SUCCESS);
849d39a76e7Sxw 
850d39a76e7Sxw 	} else if ((cmd == DDI_SUSPEND) || (cmd == DDI_PM_SUSPEND)) {
851d39a76e7Sxw 		DEBUG_ENTER("suspend");
852d39a76e7Sxw 		if ((chp = (ch_t *)ddi_get_driver_private(dip)) == NULL)
853d39a76e7Sxw 			return (DDI_FAILURE);
854d39a76e7Sxw 		mutex_enter(&chp->ch_lock);
855d39a76e7Sxw 		chp->ch_flags |= PESUSPENDED;
856d39a76e7Sxw 		mutex_exit(&chp->ch_lock);
857d39a76e7Sxw #ifdef TODO
858d39a76e7Sxw 		/* Un-initialize (STOP) T101 */
859d39a76e7Sxw #endif
860d39a76e7Sxw 		return (DDI_SUCCESS);
861d39a76e7Sxw 	} else
862d39a76e7Sxw 		return (DDI_FAILURE);
863d39a76e7Sxw }
864d39a76e7Sxw 
865d39a76e7Sxw /*
866d39a76e7Sxw  * ch_alloc_dma_mem
867d39a76e7Sxw  *
868d39a76e7Sxw  * allocates DMA handle
869d39a76e7Sxw  * allocates kernel memory
870d39a76e7Sxw  * allocates DMA access handle
871d39a76e7Sxw  *
872d39a76e7Sxw  * chp - per-board descriptor
873d39a76e7Sxw  * type - byteswap mapping?
874d39a76e7Sxw  * flags - type of mapping
875d39a76e7Sxw  * size - # bytes mapped
876d39a76e7Sxw  * paddr - physical address
877d39a76e7Sxw  * dh - ddi dma handle
878d39a76e7Sxw  * ah - ddi access handle
879d39a76e7Sxw  */
880d39a76e7Sxw 
881d39a76e7Sxw void *
ch_alloc_dma_mem(ch_t * chp,int type,int flags,int size,uint64_t * paddr,ulong_t * dh,ulong_t * ah)882d39a76e7Sxw ch_alloc_dma_mem(ch_t *chp, int type, int flags, int size, uint64_t *paddr,
883d39a76e7Sxw 	ulong_t *dh, ulong_t *ah)
884d39a76e7Sxw {
885d39a76e7Sxw 	ddi_dma_attr_t ch_dma_attr;
886d39a76e7Sxw 	ddi_dma_cookie_t cookie;
887d39a76e7Sxw 	ddi_dma_handle_t ch_dh;
888d39a76e7Sxw 	ddi_acc_handle_t ch_ah;
889d39a76e7Sxw 	ddi_device_acc_attr_t *dev_attrp;
890d39a76e7Sxw 	caddr_t ch_vaddr;
891d39a76e7Sxw 	size_t rlen;
892d39a76e7Sxw 	uint_t count;
893d39a76e7Sxw 	uint_t mapping;
894d39a76e7Sxw 	uint_t align;
895d39a76e7Sxw 	uint_t rv;
896d39a76e7Sxw 	uint_t direction;
897d39a76e7Sxw 
898