1119418Sobrien/*-
265312Smsmith * Copyright (c) 1996-2000 Distributed Processing Technology Corporation
382092Sscottl * Copyright (c) 2000-2001 Adaptec Corporation
465312Smsmith * All rights reserved.
565312Smsmith *
665312Smsmith * TERMS AND CONDITIONS OF USE
765312Smsmith *
865312Smsmith * Redistribution and use in source form, with or without modification, are
965312Smsmith * permitted provided that redistributions of source code must retain the
1065312Smsmith * above copyright notice, this list of conditions and the following disclaimer.
1165312Smsmith *
1265312Smsmith * This software is provided `as is' by Adaptec and any express or implied
1365312Smsmith * warranties, including, but not limited to, the implied warranties of
1465312Smsmith * merchantability and fitness for a particular purpose, are disclaimed. In no
1565312Smsmith * event shall Adaptec be liable for any direct, indirect, incidental, special,
1665312Smsmith * exemplary or consequential damages (including, but not limited to,
1765312Smsmith * procurement of substitute goods or services; loss of use, data, or profits;
1865312Smsmith * or business interruptions) however caused and on any theory of liability,
1965312Smsmith * whether in contract, strict liability, or tort (including negligence or
2065312Smsmith * otherwise) arising in any way out of the use of this driver software, even
2165312Smsmith * if advised of the possibility of such damage.
2265312Smsmith *
2365312Smsmith * SCSI I2O host adapter driver
2465312Smsmith *
25128964Sscottl *	V1.10 2004/05/05 scottl@freebsd.org
26128964Sscottl *		- Massive cleanup of the driver to remove dead code and
27128964Sscottl *		  non-conformant style.
28128964Sscottl *		- Removed most i386-specific code to make it more portable.
29128964Sscottl *		- Converted to the bus_space API.
3096554Sobrien *	V1.08 2001/08/21 Mark_Salyzyn@adaptec.com
3196554Sobrien *		- The 2000S and 2005S do not initialize on some machines,
3282092Sscottl *		  increased timeout to 255ms from 50ms for the StatusGet
3382092Sscottl *		  command.
3496554Sobrien *	V1.07 2001/05/22 Mark_Salyzyn@adaptec.com
3596554Sobrien *		- I knew this one was too good to be true. The error return
3696554Sobrien *		  on ioctl commands needs to be compared to CAM_REQ_CMP, not
3796554Sobrien *		  to the bit masked status.
3896554Sobrien *	V1.06 2001/05/08 Mark_Salyzyn@adaptec.com
3996554Sobrien *		- The 2005S that was supported is affectionately called the
4096554Sobrien *		  Conjoined BAR Firmware. In order to support RAID-5 in a
4196554Sobrien *		  16MB low-cost configuration, Firmware was forced to go
4296554Sobrien *		  to a Split BAR Firmware. This requires a separate IOP and
4396554Sobrien *		  Messaging base address.
4496554Sobrien *	V1.05 2001/04/25 Mark_Salyzyn@adaptec.com
4596554Sobrien *		- Handle support for 2005S Zero Channel RAID solution.
4696554Sobrien *		- System locked up if the Adapter locked up. Do not try
4796554Sobrien *		  to send other commands if the resetIOP command fails. The
4896554Sobrien *		  fail outstanding command discovery loop was flawed as the
4996554Sobrien *		  removal of the command from the list prevented discovering
5096554Sobrien *		  all the commands.
5196554Sobrien *		- Comment changes to clarify driver.
5296554Sobrien *		- SysInfo searched for an EATA SmartROM, not an I2O SmartROM.
5396554Sobrien *		- We do not use the AC_FOUND_DEV event because of I2O.
5496554Sobrien *		  Removed asr_async.
5596554Sobrien *	V1.04 2000/09/22 Mark_Salyzyn@adaptec.com, msmith@freebsd.org,
5696554Sobrien *			 lampa@fee.vutbr.cz and Scott_Long@adaptec.com.
5796554Sobrien *		- Removed support for PM1554, PM2554 and PM2654 in Mode-0
5896554Sobrien *		  mode as this is confused with competitor adapters in run
5996554Sobrien *		  mode.
6096554Sobrien *		- critical locking needed in ASR_ccbAdd and ASR_ccbRemove
6196554Sobrien *		  to prevent operating system panic.
6296554Sobrien *		- moved default major number to 154 from 97.
6396554Sobrien *	V1.03 2000/07/12 Mark_Salyzyn@adaptec.com
6496554Sobrien *		- The controller is not actually an ASR (Adaptec SCSI RAID)
6596554Sobrien *		  series that is visible, it's more of an internal code name.
6696554Sobrien *		  remove any visible references within reason for now.
6796554Sobrien *		- bus_ptr->LUN was not correctly zeroed when initially
6896554Sobrien *		  allocated causing a possible panic of the operating system
6996554Sobrien *		  during boot.
7096554Sobrien *	V1.02 2000/06/26 Mark_Salyzyn@adaptec.com
7196554Sobrien *		- Code always fails for ASR_getTid affecting performance.
7296554Sobrien *		- initiated a set of changes that resulted from a formal
7396554Sobrien *		  code inspection by Mark_Salyzyn@adaptec.com,
7496554Sobrien *		  George_Dake@adaptec.com, Jeff_Zeak@adaptec.com,
7596554Sobrien *		  Martin_Wilson@adaptec.com and Vincent_Trandoan@adaptec.com.
7696554Sobrien *		  Their findings were focussed on the LCT & TID handler, and
7796554Sobrien *		  all resulting changes were to improve code readability,
7896554Sobrien *		  consistency or have a positive effect on performance.
7996554Sobrien *	V1.01 2000/06/14 Mark_Salyzyn@adaptec.com
8096554Sobrien *		- Passthrough returned an incorrect error.
8196554Sobrien *		- Passthrough did not migrate the intrinsic scsi layer wakeup
8296554Sobrien *		  on command completion.
8396554Sobrien *		- generate control device nodes using make_dev and delete_dev.
8496554Sobrien *		- Performance affected by TID caching reallocing.
8596554Sobrien *		- Made suggested changes by Justin_Gibbs@adaptec.com
8696554Sobrien *			- use splcam instead of splbio.
8796554Sobrien *			- use cam_imask instead of bio_imask.
8896554Sobrien *			- use u_int8_t instead of u_char.
8996554Sobrien *			- use u_int16_t instead of u_short.
9096554Sobrien *			- use u_int32_t instead of u_long where appropriate.
9196554Sobrien *			- use 64 bit context handler instead of 32 bit.
9296554Sobrien *			- create_ccb should only allocate the worst case
9396554Sobrien *			  requirements for the driver since CAM may evolve
9496554Sobrien *			  making union ccb much larger than needed here.
9596554Sobrien *			  renamed create_ccb to asr_alloc_ccb.
9696554Sobrien *			- go nutz justifying all debug prints as macros
9796554Sobrien *			  defined at the top and remove unsightly ifdefs.
9896554Sobrien *			- INLINE STATIC viewed as confusing. Historically
9996554Sobrien *			  utilized to affect code performance and debug
10096554Sobrien *			  issues in OS, Compiler or OEM specific situations.
10196554Sobrien *	V1.00 2000/05/31 Mark_Salyzyn@adaptec.com
10296554Sobrien *		- Ported from FreeBSD 2.2.X DPT I2O driver.
10396554Sobrien *			changed struct scsi_xfer to union ccb/struct ccb_hdr
10496554Sobrien *			changed variable name xs to ccb
10596554Sobrien *			changed struct scsi_link to struct cam_path
10696554Sobrien *			changed struct scsibus_data to struct cam_sim
10796554Sobrien *			stopped using fordriver for holding on to the TID
10896554Sobrien *			use proprietary packet creation instead of scsi_inquire
10996554Sobrien *			CAM layer sends synchronize commands.
11065312Smsmith */
11165312Smsmith
112119418Sobrien#include <sys/cdefs.h>
113128786Sscottl#include <sys/param.h>	/* TRUE=1 and FALSE=0 defined here */
114128786Sscottl#include <sys/kernel.h>
115129879Sphk#include <sys/module.h>
116128786Sscottl#include <sys/systm.h>
117128786Sscottl#include <sys/malloc.h>
118128786Sscottl#include <sys/conf.h>
119128786Sscottl#include <sys/ioccom.h>
120164033Srwatson#include <sys/priv.h>
121128786Sscottl#include <sys/proc.h>
122128786Sscottl#include <sys/bus.h>
123128786Sscottl#include <machine/resource.h>
124128786Sscottl#include <machine/bus.h>
125128786Sscottl#include <sys/rman.h>
126128786Sscottl#include <sys/stat.h>
127155286Sscottl#include <sys/bus_dma.h>
128128786Sscottl
129128786Sscottl#include <cam/cam.h>
130128786Sscottl#include <cam/cam_ccb.h>
131128786Sscottl#include <cam/cam_sim.h>
132128786Sscottl#include <cam/cam_xpt_sim.h>
133128786Sscottl
134128786Sscottl#include <cam/scsi/scsi_all.h>
135128786Sscottl#include <cam/scsi/scsi_message.h>
136128786Sscottl
137128786Sscottl#include <vm/vm.h>
138128786Sscottl#include <vm/pmap.h>
139128786Sscottl
140128786Sscottl#if defined(__i386__)
141143729Scognet#include "opt_asr.h"
142128786Sscottl#include <i386/include/cputypes.h>
143143729Scognet
144143729Scognet#if defined(ASR_COMPAT)
145143729Scognet#define ASR_IOCTL_COMPAT
146143729Scognet#endif /* ASR_COMPAT */
147128786Sscottl#endif
148128786Sscottl#include <machine/vmparam.h>
149128786Sscottl
150128786Sscottl#include <dev/pci/pcivar.h>
151128786Sscottl#include <dev/pci/pcireg.h>
152128786Sscottl
153128786Sscottl#define	osdSwap4(x) ((u_long)ntohl((u_long)(x)))
154128786Sscottl#define	KVTOPHYS(x) vtophys(x)
155155286Sscottl#include	<dev/asr/dptalign.h>
156155286Sscottl#include	<dev/asr/i2oexec.h>
157155286Sscottl#include	<dev/asr/i2obscsi.h>
158155286Sscottl#include	<dev/asr/i2odpt.h>
159155286Sscottl#include	<dev/asr/i2oadptr.h>
160128786Sscottl
161155286Sscottl#include	<dev/asr/sys_info.h>
162128786Sscottl
163119418Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/dev/asr/asr.c 275982 2014-12-21 03:06:11Z smh $");
164119418Sobrien
16596615Sobrien#define	ASR_VERSION	1
166128964Sscottl#define	ASR_REVISION	'1'
167128964Sscottl#define	ASR_SUBREVISION '0'
168128964Sscottl#define	ASR_MONTH	5
169128964Sscottl#define	ASR_DAY		5
170128964Sscottl#define	ASR_YEAR	(2004 - 1980)
17165312Smsmith
17265312Smsmith/*
17396554Sobrien *	Debug macros to reduce the unsightly ifdefs
17465312Smsmith */
17565312Smsmith#if (defined(DEBUG_ASR) || defined(DEBUG_ASR_USR_CMD) || defined(DEBUG_ASR_CMD))
176128786Sscottlstatic __inline void
177128786Sscottldebug_asr_message(PI2O_MESSAGE_FRAME message)
178128786Sscottl{
179128786Sscottl	u_int32_t * pointer = (u_int32_t *)message;
180128786Sscottl	u_int32_t   length = I2O_MESSAGE_FRAME_getMessageSize(message);
181128786Sscottl	u_int32_t   counter = 0;
182128786Sscottl
183128786Sscottl	while (length--) {
184128786Sscottl		printf("%08lx%c", (u_long)*(pointer++),
185128786Sscottl		  (((++counter & 7) == 0) || (length == 0)) ? '\n' : ' ');
18696554Sobrien	}
187128786Sscottl}
18865312Smsmith#endif /* DEBUG_ASR || DEBUG_ASR_USR_CMD || DEBUG_ASR_CMD */
18965312Smsmith
190128786Sscottl#ifdef DEBUG_ASR
19165312Smsmith  /* Breaks on none STDC based compilers :-( */
192128786Sscottl#define debug_asr_printf(fmt,args...)	printf(fmt, ##args)
193128786Sscottl#define debug_asr_dump_message(message)	debug_asr_message(message)
194128786Sscottl#define debug_asr_print_path(ccb)	xpt_print_path(ccb->ccb_h.path);
19565312Smsmith#else /* DEBUG_ASR */
196128535Sscottl#define debug_asr_printf(fmt,args...)
197128535Sscottl#define debug_asr_dump_message(message)
198128535Sscottl#define debug_asr_print_path(ccb)
19965312Smsmith#endif /* DEBUG_ASR */
20065312Smsmith
20165312Smsmith/*
20296554Sobrien *	If DEBUG_ASR_CMD is defined:
20396554Sobrien *		0 - Display incoming SCSI commands
20496554Sobrien *		1 - add in a quick character before queueing.
20596554Sobrien *		2 - add in outgoing message frames.
20665312Smsmith */
20765312Smsmith#if (defined(DEBUG_ASR_CMD))
208128535Sscottl#define debug_asr_cmd_printf(fmt,args...)     printf(fmt,##args)
209128786Sscottlstatic __inline void
210128786Sscottldebug_asr_dump_ccb(union ccb *ccb)
211128786Sscottl{
212128786Sscottl	u_int8_t	*cp = (unsigned char *)&(ccb->csio.cdb_io);
213128786Sscottl	int		len = ccb->csio.cdb_len;
214128786Sscottl
215128786Sscottl	while (len) {
216128786Sscottl		debug_asr_cmd_printf (" %02x", *(cp++));
217128786Sscottl		--len;
21896554Sobrien	}
219128786Sscottl}
220128535Sscottl#if (DEBUG_ASR_CMD > 0)
221128535Sscottl#define debug_asr_cmd1_printf		       debug_asr_cmd_printf
222128535Sscottl#else
223128535Sscottl#define debug_asr_cmd1_printf(fmt,args...)
224128535Sscottl#endif
225128535Sscottl#if (DEBUG_ASR_CMD > 1)
226128786Sscottl#define debug_asr_cmd2_printf			debug_asr_cmd_printf
227128786Sscottl#define debug_asr_cmd2_dump_message(message)	debug_asr_message(message)
228128535Sscottl#else
229128535Sscottl#define debug_asr_cmd2_printf(fmt,args...)
230128535Sscottl#define debug_asr_cmd2_dump_message(message)
231128535Sscottl#endif
23265312Smsmith#else /* DEBUG_ASR_CMD */
233128535Sscottl#define debug_asr_cmd_printf(fmt,args...)
234128786Sscottl#define debug_asr_dump_ccb(ccb)
235128535Sscottl#define debug_asr_cmd1_printf(fmt,args...)
236128535Sscottl#define debug_asr_cmd2_printf(fmt,args...)
237128535Sscottl#define debug_asr_cmd2_dump_message(message)
23865312Smsmith#endif /* DEBUG_ASR_CMD */
23965312Smsmith
24065312Smsmith#if (defined(DEBUG_ASR_USR_CMD))
241128535Sscottl#define debug_usr_cmd_printf(fmt,args...)   printf(fmt,##args)
242128535Sscottl#define debug_usr_cmd_dump_message(message) debug_usr_message(message)
24365312Smsmith#else /* DEBUG_ASR_USR_CMD */
244128535Sscottl#define debug_usr_cmd_printf(fmt,args...)
245128535Sscottl#define debug_usr_cmd_dump_message(message)
24665312Smsmith#endif /* DEBUG_ASR_USR_CMD */
24765312Smsmith
248143729Scognet#ifdef ASR_IOCTL_COMPAT
249143729Scognet#define	dsDescription_size 46	/* Snug as a bug in a rug */
250143729Scognet#endif /* ASR_IOCTL_COMPAT */
251143729Scognet
25265312Smsmith#include "dev/asr/dptsig.h"
25365312Smsmith
25465312Smsmithstatic dpt_sig_S ASR_sig = {
25596554Sobrien	{ 'd', 'P', 't', 'S', 'i', 'G'}, SIG_VERSION, PROC_INTEL,
25696554Sobrien	PROC_386 | PROC_486 | PROC_PENTIUM | PROC_SEXIUM, FT_HBADRVR, 0,
257128945Sscottl	OEM_DPT, OS_FREE_BSD, CAP_ABOVE16MB, DEV_ALL, ADF_ALL_SC5,
25896554Sobrien	0, 0, ASR_VERSION, ASR_REVISION, ASR_SUBREVISION,
25996554Sobrien	ASR_MONTH, ASR_DAY, ASR_YEAR,
26096554Sobrien/*	 01234567890123456789012345678901234567890123456789	< 50 chars */
26196554Sobrien	"Adaptec FreeBSD 4.0.0 Unix SCSI I2O HBA Driver"
26296554Sobrien	/*		 ^^^^^ asr_attach alters these to match OS */
26365312Smsmith};
26465312Smsmith
26565312Smsmith/* Configuration Definitions */
26665312Smsmith
26796615Sobrien#define	SG_SIZE		 58	/* Scatter Gather list Size		 */
26896615Sobrien#define	MAX_TARGET_ID	 126	/* Maximum Target ID supported		 */
26996615Sobrien#define	MAX_LUN		 255	/* Maximum LUN Supported		 */
27096615Sobrien#define	MAX_CHANNEL	 7	/* Maximum Channel # Supported by driver */
27196615Sobrien#define	MAX_INBOUND	 2000	/* Max CCBs, Also Max Queue Size	 */
27296615Sobrien#define	MAX_OUTBOUND	 256	/* Maximum outbound frames/adapter	 */
27396615Sobrien#define	MAX_INBOUND_SIZE 512	/* Maximum inbound frame size		 */
27496615Sobrien#define	MAX_MAP		 4194304L /* Maximum mapping size of IOP	 */
27596554Sobrien				/* Also serves as the minimum map for	 */
27696554Sobrien				/* the 2005S zero channel RAID product	 */
27765312Smsmith
27865312Smsmith/* I2O register set */
279128944Sscottl#define	I2O_REG_STATUS		0x30
280128944Sscottl#define	I2O_REG_MASK		0x34
281128944Sscottl#define	I2O_REG_TOFIFO		0x40
282128944Sscottl#define	I2O_REG_FROMFIFO	0x44
28365312Smsmith
284128944Sscottl#define	Mask_InterruptsDisabled	0x08
285128944Sscottl
28665312Smsmith/*
28765312Smsmith * A MIX of performance and space considerations for TID lookups
28865312Smsmith */
28965312Smsmithtypedef u_int16_t tid_t;
29065312Smsmith
29165312Smsmithtypedef struct {
29296554Sobrien	u_int32_t size;		/* up to MAX_LUN    */
29396554Sobrien	tid_t	  TID[1];
29465312Smsmith} lun2tid_t;
29565312Smsmith
29665312Smsmithtypedef struct {
29796554Sobrien	u_int32_t   size;	/* up to MAX_TARGET */
29896554Sobrien	lun2tid_t * LUN[1];
29965312Smsmith} target2lun_t;
30065312Smsmith
30165312Smsmith/*
30296554Sobrien *	To ensure that we only allocate and use the worst case ccb here, lets
30396554Sobrien *	make our own local ccb union. If asr_alloc_ccb is utilized for another
30496554Sobrien *	ccb type, ensure that you add the additional structures into our local
30596554Sobrien *	ccb union. To ensure strict type checking, we will utilize the local
30696554Sobrien *	ccb definition wherever possible.
30765312Smsmith */
30865312Smsmithunion asr_ccb {
30996554Sobrien	struct ccb_hdr	    ccb_h;  /* For convenience */
31096554Sobrien	struct ccb_scsiio   csio;
31196554Sobrien	struct ccb_setasync csa;
31265312Smsmith};
31365312Smsmith
314155307Sscottlstruct Asr_status_mem {
315155307Sscottl	I2O_EXEC_STATUS_GET_REPLY	status;
316155307Sscottl	U32				rstatus;
317155307Sscottl};
318155307Sscottl
319128944Sscottl/**************************************************************************
320128944Sscottl** ASR Host Adapter structure - One Structure For Each Host Adapter That **
321128944Sscottl**  Is Configured Into The System.  The Structure Supplies Configuration **
322128944Sscottl**  Information, Status Info, Queue Info And An Active CCB List Pointer. **
323128944Sscottl***************************************************************************/
324128944Sscottl
32565312Smsmithtypedef struct Asr_softc {
326155286Sscottl	device_t		ha_dev;
32796554Sobrien	u_int16_t		ha_irq;
328128944Sscottl	u_long			ha_Base;       /* base port for each board */
329128944Sscottl	bus_size_t		ha_blinkLED;
330128944Sscottl	bus_space_handle_t	ha_i2o_bhandle;
331128944Sscottl	bus_space_tag_t		ha_i2o_btag;
332128944Sscottl	bus_space_handle_t	ha_frame_bhandle;
333128944Sscottl	bus_space_tag_t		ha_frame_btag;
33496554Sobrien	I2O_IOP_ENTRY		ha_SystemTable;
33596554Sobrien	LIST_HEAD(,ccb_hdr)	ha_ccb;	       /* ccbs in use		   */
336155286Sscottl
337155286Sscottl	bus_dma_tag_t		ha_parent_dmat;
338155307Sscottl	bus_dma_tag_t		ha_statusmem_dmat;
339155307Sscottl	bus_dmamap_t		ha_statusmem_dmamap;
340155307Sscottl	struct Asr_status_mem * ha_statusmem;
341155307Sscottl	u_int32_t		ha_rstatus_phys;
342155286Sscottl	u_int32_t		ha_status_phys;
34396554Sobrien	struct cam_path	      * ha_path[MAX_CHANNEL+1];
34496554Sobrien	struct cam_sim	      * ha_sim[MAX_CHANNEL+1];
34596554Sobrien	struct resource	      * ha_mem_res;
34696554Sobrien	struct resource	      * ha_mes_res;
34796554Sobrien	struct resource	      * ha_irq_res;
34896554Sobrien	void		      * ha_intr;
34996554Sobrien	PI2O_LCT		ha_LCT;	       /* Complete list of devices */
350128535Sscottl#define le_type	  IdentityTag[0]
351128535Sscottl#define I2O_BSA	    0x20
352128535Sscottl#define I2O_FCA	    0x40
353128535Sscottl#define I2O_SCSI    0x00
354128535Sscottl#define I2O_PORT    0x80
355128535Sscottl#define I2O_UNKNOWN 0x7F
356128535Sscottl#define le_bus	  IdentityTag[1]
357128535Sscottl#define le_target IdentityTag[2]
358128535Sscottl#define le_lun	  IdentityTag[3]
35996554Sobrien	target2lun_t	      * ha_targets[MAX_CHANNEL+1];
36096554Sobrien	PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME ha_Msgs;
36196554Sobrien	u_long			ha_Msgs_Phys;
36265312Smsmith
36396554Sobrien	u_int8_t		ha_in_reset;
364128535Sscottl#define HA_OPERATIONAL	    0
365128535Sscottl#define HA_IN_RESET	    1
366128535Sscottl#define HA_OFF_LINE	    2
367128535Sscottl#define HA_OFF_LINE_RECOVERY 3
36896554Sobrien	/* Configuration information */
36996554Sobrien	/* The target id maximums we take */
37096554Sobrien	u_int8_t		ha_MaxBus;     /* Maximum bus */
37196554Sobrien	u_int8_t		ha_MaxId;      /* Maximum target ID */
37296554Sobrien	u_int8_t		ha_MaxLun;     /* Maximum target LUN */
37396554Sobrien	u_int8_t		ha_SgSize;     /* Max SG elements */
37496554Sobrien	u_int8_t		ha_pciBusNum;
37596554Sobrien	u_int8_t		ha_pciDeviceNum;
37696554Sobrien	u_int8_t		ha_adapter_target[MAX_CHANNEL+1];
37796554Sobrien	u_int16_t		ha_QueueSize;  /* Max outstanding commands */
37896554Sobrien	u_int16_t		ha_Msgs_Count;
37965312Smsmith
38096554Sobrien	/* Links into other parents and HBAs */
381234503Sdim	STAILQ_ENTRY(Asr_softc) ha_next;       /* HBA list */
382130585Sphk	struct cdev *ha_devt;
38365312Smsmith} Asr_softc_t;
38465312Smsmith
385234503Sdimstatic STAILQ_HEAD(, Asr_softc) Asr_softc_list =
386234503Sdim	STAILQ_HEAD_INITIALIZER(Asr_softc_list);
38765312Smsmith/*
38896554Sobrien *	Prototypes of the routines we have in this object.
38965312Smsmith */
39065312Smsmith
39165312Smsmith/* I2O HDM interface */
392154363Sscottlstatic int	asr_probe(device_t dev);
393154363Sscottlstatic int	asr_attach(device_t dev);
39465312Smsmith
395130585Sphkstatic int	asr_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
396128784Sscottl			  struct thread *td);
397130585Sphkstatic int	asr_open(struct cdev *dev, int32_t flags, int32_t ifmt,
398128784Sscottl			 struct thread *td);
399130585Sphkstatic int	asr_close(struct cdev *dev, int flags, int ifmt, struct thread *td);
400128784Sscottlstatic int	asr_intr(Asr_softc_t *sc);
401128784Sscottlstatic void	asr_timeout(void *arg);
402128784Sscottlstatic int	ASR_init(Asr_softc_t *sc);
403128784Sscottlstatic int	ASR_acquireLct(Asr_softc_t *sc);
404128784Sscottlstatic int	ASR_acquireHrt(Asr_softc_t *sc);
405128784Sscottlstatic void	asr_action(struct cam_sim *sim, union ccb *ccb);
406128784Sscottlstatic void	asr_poll(struct cam_sim *sim);
407128784Sscottlstatic int	ASR_queue(Asr_softc_t *sc, PI2O_MESSAGE_FRAME Message);
40865312Smsmith
409275982Ssmhstatic __inline void
410275982Ssmhset_ccb_timeout_ch(union asr_ccb *ccb)
411275982Ssmh{
412275982Ssmh	struct callout_handle ch;
413275982Ssmh
414275982Ssmh	ch = timeout(asr_timeout, (caddr_t)ccb,
415275982Ssmh	    (int)((u_int64_t)(ccb->ccb_h.timeout) * (u_int32_t)hz / 1000));
416275982Ssmh	ccb->ccb_h.sim_priv.entries[0].ptr = ch.callout;
417275982Ssmh}
418275982Ssmh
419275982Ssmhstatic __inline struct callout_handle
420275982Ssmhget_ccb_timeout_ch(union asr_ccb *ccb)
421275982Ssmh{
422275982Ssmh	struct callout_handle ch;
423275982Ssmh
424275982Ssmh	ch.callout = ccb->ccb_h.sim_priv.entries[0].ptr;
425275982Ssmh	return ch;
426275982Ssmh}
427275982Ssmh
42865312Smsmith/*
42996554Sobrien *	Here is the auto-probe structure used to nest our tests appropriately
43096554Sobrien *	during the startup phase of the operating system.
43165312Smsmith */
432128784Sscottlstatic device_method_t asr_methods[] = {
43396554Sobrien	DEVMETHOD(device_probe,	 asr_probe),
43496554Sobrien	DEVMETHOD(device_attach, asr_attach),
43596554Sobrien	{ 0, 0 }
43665312Smsmith};
43765312Smsmith
438128784Sscottlstatic driver_t asr_driver = {
43996554Sobrien	"asr",
44096554Sobrien	asr_methods,
44196554Sobrien	sizeof(Asr_softc_t)
44265312Smsmith};
44365312Smsmith
444128784Sscottlstatic devclass_t asr_devclass;
44565312SmsmithDRIVER_MODULE(asr, pci, asr_driver, asr_devclass, 0, 0);
446165102SmjacobMODULE_DEPEND(asr, pci, 1, 1, 1);
447165102SmjacobMODULE_DEPEND(asr, cam, 1, 1, 1);
44865312Smsmith
44965312Smsmith/*
45065312Smsmith * devsw for asr hba driver
45165312Smsmith *
45265312Smsmith * only ioctl is used. the sd driver provides all other access.
45365312Smsmith */
454128784Sscottlstatic struct cdevsw asr_cdevsw = {
455126080Sphk	.d_version =	D_VERSION,
456126080Sphk	.d_flags =	D_NEEDGIANT,
457111815Sphk	.d_open =	asr_open,
458111815Sphk	.d_close =	asr_close,
459111815Sphk	.d_ioctl =	asr_ioctl,
460111815Sphk	.d_name =	"asr",
46165312Smsmith};
46265312Smsmith
46365312Smsmith/* I2O support routines */
46465312Smsmith
465128944Sscottlstatic __inline u_int32_t
466128944Sscottlasr_get_FromFIFO(Asr_softc_t *sc)
467128944Sscottl{
468128944Sscottl	return (bus_space_read_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle,
469128944Sscottl				 I2O_REG_FROMFIFO));
470128944Sscottl}
471128944Sscottl
472128944Sscottlstatic __inline u_int32_t
473128944Sscottlasr_get_ToFIFO(Asr_softc_t *sc)
474128944Sscottl{
475128944Sscottl	return (bus_space_read_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle,
476128944Sscottl				 I2O_REG_TOFIFO));
477128944Sscottl}
478128944Sscottl
479128944Sscottlstatic __inline u_int32_t
480128944Sscottlasr_get_intr(Asr_softc_t *sc)
481128944Sscottl{
482128944Sscottl	return (bus_space_read_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle,
483128944Sscottl				 I2O_REG_MASK));
484128944Sscottl}
485128944Sscottl
486128944Sscottlstatic __inline u_int32_t
487128944Sscottlasr_get_status(Asr_softc_t *sc)
488128944Sscottl{
489128944Sscottl	return (bus_space_read_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle,
490128944Sscottl				 I2O_REG_STATUS));
491128944Sscottl}
492128944Sscottl
493128944Sscottlstatic __inline void
494128944Sscottlasr_set_FromFIFO(Asr_softc_t *sc, u_int32_t val)
495128944Sscottl{
496128944Sscottl	bus_space_write_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle, I2O_REG_FROMFIFO,
497128944Sscottl			  val);
498128944Sscottl}
499128944Sscottl
500128944Sscottlstatic __inline void
501128944Sscottlasr_set_ToFIFO(Asr_softc_t *sc, u_int32_t val)
502128944Sscottl{
503128944Sscottl	bus_space_write_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle, I2O_REG_TOFIFO,
504128944Sscottl			  val);
505128944Sscottl}
506128944Sscottl
507128944Sscottlstatic __inline void
508128944Sscottlasr_set_intr(Asr_softc_t *sc, u_int32_t val)
509128944Sscottl{
510128944Sscottl	bus_space_write_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle, I2O_REG_MASK,
511128944Sscottl			  val);
512128944Sscottl}
513128944Sscottl
514128944Sscottlstatic __inline void
515128944Sscottlasr_set_frame(Asr_softc_t *sc, void *frame, u_int32_t offset, int len)
516128944Sscottl{
517128944Sscottl	bus_space_write_region_4(sc->ha_frame_btag, sc->ha_frame_bhandle,
518128944Sscottl				 offset, (u_int32_t *)frame, len);
519128944Sscottl}
520128944Sscottl
52165312Smsmith/*
52296554Sobrien *	Fill message with default.
52365312Smsmith */
524128784Sscottlstatic PI2O_MESSAGE_FRAME
525128812SscottlASR_fillMessage(void *Message, u_int16_t size)
52665312Smsmith{
527128784Sscottl	PI2O_MESSAGE_FRAME Message_Ptr;
52865312Smsmith
529128812Sscottl	Message_Ptr = (I2O_MESSAGE_FRAME *)Message;
530128787Sscottl	bzero(Message_Ptr, size);
53196554Sobrien	I2O_MESSAGE_FRAME_setVersionOffset(Message_Ptr, I2O_VERSION_11);
53296554Sobrien	I2O_MESSAGE_FRAME_setMessageSize(Message_Ptr,
53396554Sobrien	  (size + sizeof(U32) - 1) >> 2);
53496554Sobrien	I2O_MESSAGE_FRAME_setInitiatorAddress (Message_Ptr, 1);
535128908Sscottl	KASSERT(Message_Ptr != NULL, ("Message_Ptr == NULL"));
53696554Sobrien	return (Message_Ptr);
53765312Smsmith} /* ASR_fillMessage */
53865312Smsmith
539155284Sscottl#define	EMPTY_QUEUE (0xffffffff)
54065312Smsmith
541128784Sscottlstatic __inline U32
542128944SscottlASR_getMessage(Asr_softc_t *sc)
54365312Smsmith{
544128784Sscottl	U32	MessageOffset;
54565312Smsmith
546128944Sscottl	MessageOffset = asr_get_ToFIFO(sc);
547128944Sscottl	if (MessageOffset == EMPTY_QUEUE)
548128944Sscottl		MessageOffset = asr_get_ToFIFO(sc);
549128944Sscottl
55096554Sobrien	return (MessageOffset);
55165312Smsmith} /* ASR_getMessage */
55265312Smsmith
55365312Smsmith/* Issue a polled command */
554128784Sscottlstatic U32
555128944SscottlASR_initiateCp(Asr_softc_t *sc, PI2O_MESSAGE_FRAME Message)
55665312Smsmith{
557155331Sscottl	U32	Mask = 0xffffffff;
558128784Sscottl	U32	MessageOffset;
559128784Sscottl	u_int	Delay = 1500;
56065312Smsmith
56196554Sobrien	/*
56296554Sobrien	 * ASR_initiateCp is only used for synchronous commands and will
56396554Sobrien	 * be made more resiliant to adapter delays since commands like
56496554Sobrien	 * resetIOP can cause the adapter to be deaf for a little time.
56596554Sobrien	 */
566128944Sscottl	while (((MessageOffset = ASR_getMessage(sc)) == EMPTY_QUEUE)
56796554Sobrien	 && (--Delay != 0)) {
56896554Sobrien		DELAY (10000);
56996554Sobrien	}
57096554Sobrien	if (MessageOffset != EMPTY_QUEUE) {
571128944Sscottl		asr_set_frame(sc, Message, MessageOffset,
572128944Sscottl			      I2O_MESSAGE_FRAME_getMessageSize(Message));
57396554Sobrien		/*
57496554Sobrien		 *	Disable the Interrupts
57596554Sobrien		 */
576128944Sscottl		Mask = asr_get_intr(sc);
577128944Sscottl		asr_set_intr(sc, Mask | Mask_InterruptsDisabled);
578128944Sscottl		asr_set_ToFIFO(sc, MessageOffset);
57996554Sobrien	}
58096554Sobrien	return (Mask);
58165312Smsmith} /* ASR_initiateCp */
58265312Smsmith
58365312Smsmith/*
58496554Sobrien *	Reset the adapter.
58565312Smsmith */
586128784Sscottlstatic U32
587128944SscottlASR_resetIOP(Asr_softc_t *sc)
58865312Smsmith{
589155307Sscottl	I2O_EXEC_IOP_RESET_MESSAGE	 Message;
59096554Sobrien	PI2O_EXEC_IOP_RESET_MESSAGE	 Message_Ptr;
591155286Sscottl	U32			       * Reply_Ptr;
59296554Sobrien	U32				 Old;
59365312Smsmith
59496554Sobrien	/*
59596554Sobrien	 *  Build up our copy of the Message.
59696554Sobrien	 */
597128812Sscottl	Message_Ptr = (PI2O_EXEC_IOP_RESET_MESSAGE)ASR_fillMessage(&Message,
59896554Sobrien	  sizeof(I2O_EXEC_IOP_RESET_MESSAGE));
59996554Sobrien	I2O_EXEC_IOP_RESET_MESSAGE_setFunction(Message_Ptr, I2O_EXEC_IOP_RESET);
60096554Sobrien	/*
60196554Sobrien	 *  Reset the Reply Status
60296554Sobrien	 */
603155307Sscottl	Reply_Ptr = &sc->ha_statusmem->rstatus;
604155286Sscottl	*Reply_Ptr = 0;
60596554Sobrien	I2O_EXEC_IOP_RESET_MESSAGE_setStatusWordLowAddress(Message_Ptr,
606155307Sscottl	    sc->ha_rstatus_phys);
60796554Sobrien	/*
60896554Sobrien	 *	Send the Message out
60996554Sobrien	 */
610155284Sscottl	if ((Old = ASR_initiateCp(sc, (PI2O_MESSAGE_FRAME)Message_Ptr)) !=
611155284Sscottl	     0xffffffff) {
61296554Sobrien		/*
613128786Sscottl		 * Wait for a response (Poll), timeouts are dangerous if
61496554Sobrien		 * the card is truly responsive. We assume response in 2s.
61596554Sobrien		 */
61696554Sobrien		u_int8_t Delay = 200;
61765312Smsmith
61896554Sobrien		while ((*Reply_Ptr == 0) && (--Delay != 0)) {
61996554Sobrien			DELAY (10000);
62096554Sobrien		}
62196554Sobrien		/*
62296554Sobrien		 *	Re-enable the interrupts.
62396554Sobrien		 */
624128944Sscottl		asr_set_intr(sc, Old);
625128794Sscottl		KASSERT(*Reply_Ptr != 0, ("*Reply_Ptr == 0"));
626128786Sscottl		return(*Reply_Ptr);
62796554Sobrien	}
628155331Sscottl	KASSERT(Old != 0xffffffff, ("Old == -1"));
62996554Sobrien	return (0);
63065312Smsmith} /* ASR_resetIOP */
63165312Smsmith
63265312Smsmith/*
63396554Sobrien *	Get the curent state of the adapter
63465312Smsmith */
635128784Sscottlstatic PI2O_EXEC_STATUS_GET_REPLY
636155307SscottlASR_getStatus(Asr_softc_t *sc)
63765312Smsmith{
638128812Sscottl	I2O_EXEC_STATUS_GET_MESSAGE	Message;
639128812Sscottl	PI2O_EXEC_STATUS_GET_MESSAGE	Message_Ptr;
640155307Sscottl	PI2O_EXEC_STATUS_GET_REPLY	buffer;
641128812Sscottl	U32				Old;
64265312Smsmith
64396554Sobrien	/*
64496554Sobrien	 *  Build up our copy of the Message.
64596554Sobrien	 */
646128812Sscottl	Message_Ptr = (PI2O_EXEC_STATUS_GET_MESSAGE)ASR_fillMessage(&Message,
647128786Sscottl	    sizeof(I2O_EXEC_STATUS_GET_MESSAGE));
64896554Sobrien	I2O_EXEC_STATUS_GET_MESSAGE_setFunction(Message_Ptr,
649128786Sscottl	    I2O_EXEC_STATUS_GET);
65096554Sobrien	I2O_EXEC_STATUS_GET_MESSAGE_setReplyBufferAddressLow(Message_Ptr,
651155307Sscottl	    sc->ha_status_phys);
65296554Sobrien	/* This one is a Byte Count */
65396554Sobrien	I2O_EXEC_STATUS_GET_MESSAGE_setReplyBufferLength(Message_Ptr,
654128786Sscottl	    sizeof(I2O_EXEC_STATUS_GET_REPLY));
65596554Sobrien	/*
65696554Sobrien	 *  Reset the Reply Status
65796554Sobrien	 */
658155307Sscottl	buffer = &sc->ha_statusmem->status;
659128787Sscottl	bzero(buffer, sizeof(I2O_EXEC_STATUS_GET_REPLY));
66096554Sobrien	/*
66196554Sobrien	 *	Send the Message out
66296554Sobrien	 */
663155284Sscottl	if ((Old = ASR_initiateCp(sc, (PI2O_MESSAGE_FRAME)Message_Ptr)) !=
664155284Sscottl	    0xffffffff) {
66596554Sobrien		/*
66696554Sobrien		 *	Wait for a response (Poll), timeouts are dangerous if
66796554Sobrien		 * the card is truly responsive. We assume response in 50ms.
66896554Sobrien		 */
66996554Sobrien		u_int8_t Delay = 255;
67065312Smsmith
67196554Sobrien		while (*((U8 * volatile)&(buffer->SyncByte)) == 0) {
67296554Sobrien			if (--Delay == 0) {
673128511Sscottl				buffer = NULL;
67496554Sobrien				break;
67596554Sobrien			}
67696554Sobrien			DELAY (1000);
67796554Sobrien		}
67896554Sobrien		/*
67996554Sobrien		 *	Re-enable the interrupts.
68096554Sobrien		 */
681128944Sscottl		asr_set_intr(sc, Old);
68296554Sobrien		return (buffer);
68396554Sobrien	}
684128511Sscottl	return (NULL);
68565312Smsmith} /* ASR_getStatus */
68665312Smsmith
68765312Smsmith/*
68896554Sobrien *	Check if the device is a SCSI I2O HBA, and add it to the list.
68965312Smsmith */
69065312Smsmith
69165312Smsmith/*
69265312Smsmith * Probe for ASR controller.  If we find it, we will use it.
69365312Smsmith * virtual adapters.
69465312Smsmith */
695128791Sscottlstatic int
696154363Sscottlasr_probe(device_t dev)
69765312Smsmith{
698128791Sscottl	u_int32_t id;
699128791Sscottl
700154363Sscottl	id = (pci_get_device(dev) << 16) | pci_get_vendor(dev);
70196554Sobrien	if ((id == 0xA5011044) || (id == 0xA5111044)) {
702154363Sscottl		device_set_desc(dev, "Adaptec Caching SCSI RAID");
703143163Simp		return (BUS_PROBE_DEFAULT);
70496554Sobrien	}
705128791Sscottl	return (ENXIO);
70665312Smsmith} /* asr_probe */
70765312Smsmith
708128784Sscottlstatic __inline union asr_ccb *
709128784Sscottlasr_alloc_ccb(Asr_softc_t *sc)
71065312Smsmith{
711128784Sscottl	union asr_ccb *new_ccb;
71265312Smsmith
71396554Sobrien	if ((new_ccb = (union asr_ccb *)malloc(sizeof(*new_ccb),
714128511Sscottl	  M_DEVBUF, M_WAITOK | M_ZERO)) != NULL) {
71596554Sobrien		new_ccb->ccb_h.pinfo.priority = 1;
71696554Sobrien		new_ccb->ccb_h.pinfo.index = CAM_UNQUEUED_INDEX;
71796554Sobrien		new_ccb->ccb_h.spriv_ptr0 = sc;
71896554Sobrien	}
71996554Sobrien	return (new_ccb);
72065312Smsmith} /* asr_alloc_ccb */
72165312Smsmith
722128784Sscottlstatic __inline void
723128784Sscottlasr_free_ccb(union asr_ccb *free_ccb)
72465312Smsmith{
72596554Sobrien	free(free_ccb, M_DEVBUF);
72665312Smsmith} /* asr_free_ccb */
72765312Smsmith
72865312Smsmith/*
72996554Sobrien *	Print inquiry data `carefully'
73065312Smsmith */
731128784Sscottlstatic void
732128784SscottlASR_prstring(u_int8_t *s, int len)
73365312Smsmith{
73496554Sobrien	while ((--len >= 0) && (*s) && (*s != ' ') && (*s != '-')) {
73596554Sobrien		printf ("%c", *(s++));
73696554Sobrien	}
73765312Smsmith} /* ASR_prstring */
73865312Smsmith
73965312Smsmith/*
74096554Sobrien *	Send a message synchronously and without Interrupt to a ccb.
74165312Smsmith */
742128784Sscottlstatic int
743128784SscottlASR_queue_s(union asr_ccb *ccb, PI2O_MESSAGE_FRAME Message)
74465312Smsmith{
745128784Sscottl	int		s;
746128784Sscottl	U32		Mask;
747128784Sscottl	Asr_softc_t	*sc = (Asr_softc_t *)(ccb->ccb_h.spriv_ptr0);
74865312Smsmith
74996554Sobrien	/*
75096554Sobrien	 * We do not need any (optional byteswapping) method access to
75196554Sobrien	 * the Initiator context field.
75296554Sobrien	 */
75396554Sobrien	I2O_MESSAGE_FRAME_setInitiatorContext64(Message, (long)ccb);
75465312Smsmith
75596554Sobrien	/* Prevent interrupt service */
75696554Sobrien	s = splcam ();
757128944Sscottl	Mask = asr_get_intr(sc);
758128944Sscottl	asr_set_intr(sc, Mask | Mask_InterruptsDisabled);
75965312Smsmith
760128944Sscottl	if (ASR_queue(sc, Message) == EMPTY_QUEUE) {
76196554Sobrien		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
76296554Sobrien		ccb->ccb_h.status |= CAM_REQUEUE_REQ;
76396554Sobrien	}
76465312Smsmith
76596554Sobrien	/*
76696554Sobrien	 * Wait for this board to report a finished instruction.
76796554Sobrien	 */
76896554Sobrien	while ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
76996554Sobrien		(void)asr_intr (sc);
77096554Sobrien	}
77165312Smsmith
77296554Sobrien	/* Re-enable Interrupts */
773128944Sscottl	asr_set_intr(sc, Mask);
77496554Sobrien	splx(s);
77565312Smsmith
77696554Sobrien	return (ccb->ccb_h.status);
77765312Smsmith} /* ASR_queue_s */
77865312Smsmith
77965312Smsmith/*
780108533Sschweikh *	Send a message synchronously to an Asr_softc_t.
78165312Smsmith */
782128784Sscottlstatic int
783128784SscottlASR_queue_c(Asr_softc_t *sc, PI2O_MESSAGE_FRAME Message)
78465312Smsmith{
785128784Sscottl	union asr_ccb	*ccb;
786128784Sscottl	int		status;
78765312Smsmith
788128511Sscottl	if ((ccb = asr_alloc_ccb (sc)) == NULL) {
78996554Sobrien		return (CAM_REQUEUE_REQ);
79096554Sobrien	}
79165312Smsmith
79296554Sobrien	status = ASR_queue_s (ccb, Message);
79365312Smsmith
79496554Sobrien	asr_free_ccb(ccb);
79565312Smsmith
79696554Sobrien	return (status);
79765312Smsmith} /* ASR_queue_c */
79865312Smsmith
79965312Smsmith/*
80096554Sobrien *	Add the specified ccb to the active queue
80165312Smsmith */
802128784Sscottlstatic __inline void
803128784SscottlASR_ccbAdd(Asr_softc_t *sc, union asr_ccb *ccb)
80465312Smsmith{
80596554Sobrien	int s;
80666190Smsmith
80796554Sobrien	s = splcam();
80896554Sobrien	LIST_INSERT_HEAD(&(sc->ha_ccb), &(ccb->ccb_h), sim_links.le);
80996554Sobrien	if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
81096554Sobrien		if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT) {
81196554Sobrien			/*
81296554Sobrien			 * RAID systems can take considerable time to
81396554Sobrien			 * complete some commands given the large cache
81496554Sobrien			 * flashes switching from write back to write thru.
81596554Sobrien			 */
81696554Sobrien			ccb->ccb_h.timeout = 6 * 60 * 1000;
81796554Sobrien		}
818275982Ssmh		set_ccb_timeout_ch(ccb);
81996554Sobrien	}
82096554Sobrien	splx(s);
82165312Smsmith} /* ASR_ccbAdd */
82265312Smsmith
82365312Smsmith/*
82496554Sobrien *	Remove the specified ccb from the active queue.
82565312Smsmith */
826128784Sscottlstatic __inline void
827128784SscottlASR_ccbRemove(Asr_softc_t *sc, union asr_ccb *ccb)
82865312Smsmith{
82996554Sobrien	int s;
83066190Smsmith
83196554Sobrien	s = splcam();
832255871Sscottl	untimeout(asr_timeout, (caddr_t)ccb, get_ccb_timeout_ch(ccb));
83396554Sobrien	LIST_REMOVE(&(ccb->ccb_h), sim_links.le);
83496554Sobrien	splx(s);
83565312Smsmith} /* ASR_ccbRemove */
83665312Smsmith
83765312Smsmith/*
83896554Sobrien *	Fail all the active commands, so they get re-issued by the operating
83996554Sobrien *	system.
84065312Smsmith */
841128784Sscottlstatic void
842128784SscottlASR_failActiveCommands(Asr_softc_t *sc)
84365312Smsmith{
844128784Sscottl	struct ccb_hdr	*ccb;
845128784Sscottl	int		s;
84682092Sscottl
84796554Sobrien	s = splcam();
84896554Sobrien	/*
84996554Sobrien	 *	We do not need to inform the CAM layer that we had a bus
85096554Sobrien	 * reset since we manage it on our own, this also prevents the
85196554Sobrien	 * SCSI_DELAY settling that would be required on other systems.
85296554Sobrien	 * The `SCSI_DELAY' has already been handled by the card via the
85396554Sobrien	 * acquisition of the LCT table while we are at CAM priority level.
85496554Sobrien	 *  for (int bus = 0; bus <= sc->ha_MaxBus; ++bus) {
85596554Sobrien	 *	xpt_async (AC_BUS_RESET, sc->ha_path[bus], NULL);
85696554Sobrien	 *  }
85796554Sobrien	 */
858128511Sscottl	while ((ccb = LIST_FIRST(&(sc->ha_ccb))) != NULL) {
85996554Sobrien		ASR_ccbRemove (sc, (union asr_ccb *)ccb);
86065312Smsmith
86196554Sobrien		ccb->status &= ~CAM_STATUS_MASK;
86296554Sobrien		ccb->status |= CAM_REQUEUE_REQ;
86396554Sobrien		/* Nothing Transfered */
86496554Sobrien		((struct ccb_scsiio *)ccb)->resid
86596554Sobrien		  = ((struct ccb_scsiio *)ccb)->dxfer_len;
86665312Smsmith
86796554Sobrien		if (ccb->path) {
86896554Sobrien			xpt_done ((union ccb *)ccb);
86996554Sobrien		} else {
870111748Sdes			wakeup (ccb);
87196554Sobrien		}
87296554Sobrien	}
87396554Sobrien	splx(s);
87465312Smsmith} /* ASR_failActiveCommands */
87565312Smsmith
87665312Smsmith/*
87796554Sobrien *	The following command causes the HBA to reset the specific bus
87865312Smsmith */
879128784Sscottlstatic void
880128784SscottlASR_resetBus(Asr_softc_t *sc, int bus)
88165312Smsmith{
882128812Sscottl	I2O_HBA_BUS_RESET_MESSAGE	Message;
883128812Sscottl	I2O_HBA_BUS_RESET_MESSAGE	*Message_Ptr;
884128812Sscottl	PI2O_LCT_ENTRY			Device;
88565312Smsmith
886128812Sscottl	Message_Ptr = (I2O_HBA_BUS_RESET_MESSAGE *)ASR_fillMessage(&Message,
88796554Sobrien	  sizeof(I2O_HBA_BUS_RESET_MESSAGE));
88896554Sobrien	I2O_MESSAGE_FRAME_setFunction(&Message_Ptr->StdMessageFrame,
88996554Sobrien	  I2O_HBA_BUS_RESET);
89096554Sobrien	for (Device = sc->ha_LCT->LCTEntry; Device < (PI2O_LCT_ENTRY)
89196554Sobrien	  (((U32 *)sc->ha_LCT)+I2O_LCT_getTableSize(sc->ha_LCT));
89296554Sobrien	  ++Device) {
89396554Sobrien		if (((Device->le_type & I2O_PORT) != 0)
89496554Sobrien		 && (Device->le_bus == bus)) {
89596554Sobrien			I2O_MESSAGE_FRAME_setTargetAddress(
89696554Sobrien			  &Message_Ptr->StdMessageFrame,
89796554Sobrien			  I2O_LCT_ENTRY_getLocalTID(Device));
89896554Sobrien			/* Asynchronous command, with no expectations */
89996554Sobrien			(void)ASR_queue(sc, (PI2O_MESSAGE_FRAME)Message_Ptr);
90096554Sobrien			break;
90196554Sobrien		}
90296554Sobrien	}
90365312Smsmith} /* ASR_resetBus */
90465312Smsmith
905128784Sscottlstatic __inline int
906128784SscottlASR_getBlinkLedCode(Asr_softc_t *sc)
90765312Smsmith{
908128944Sscottl	U8	blink;
909128944Sscottl
910128944Sscottl	if (sc == NULL)
911128944Sscottl		return (0);
912128944Sscottl
913128944Sscottl	blink = bus_space_read_1(sc->ha_frame_btag,
914128944Sscottl				 sc->ha_frame_bhandle, sc->ha_blinkLED + 1);
915128944Sscottl	if (blink != 0xBC)
916128944Sscottl		return (0);
917128944Sscottl
918128944Sscottl	blink = bus_space_read_1(sc->ha_frame_btag,
919128944Sscottl				 sc->ha_frame_bhandle, sc->ha_blinkLED);
920128944Sscottl	return (blink);
92165312Smsmith} /* ASR_getBlinkCode */
92265312Smsmith
92365312Smsmith/*
92496554Sobrien *	Determine the address of an TID lookup. Must be done at high priority
92596554Sobrien *	since the address can be changed by other threads of execution.
92665312Smsmith *
92796554Sobrien *	Returns NULL pointer if not indexible (but will attempt to generate
92896554Sobrien *	an index if `new_entry' flag is set to TRUE).
92965312Smsmith *
93096554Sobrien *	All addressible entries are to be guaranteed zero if never initialized.
93165312Smsmith */
932128784Sscottlstatic tid_t *
933128784SscottlASR_getTidAddress(Asr_softc_t *sc, int bus, int target, int lun, int new_entry)
93465312Smsmith{
935128784Sscottl	target2lun_t	*bus_ptr;
936128784Sscottl	lun2tid_t	*target_ptr;
937128784Sscottl	unsigned	new_size;
93865312Smsmith
93996554Sobrien	/*
94096554Sobrien	 *	Validity checking of incoming parameters. More of a bound
94196554Sobrien	 * expansion limit than an issue with the code dealing with the
94296554Sobrien	 * values.
94396554Sobrien	 *
94496554Sobrien	 *	sc must be valid before it gets here, so that check could be
94596554Sobrien	 * dropped if speed a critical issue.
94696554Sobrien	 */
947128511Sscottl	if ((sc == NULL)
94896554Sobrien	 || (bus > MAX_CHANNEL)
94996554Sobrien	 || (target > sc->ha_MaxId)
95096554Sobrien	 || (lun > sc->ha_MaxLun)) {
95196554Sobrien		debug_asr_printf("(%lx,%d,%d,%d) target out of range\n",
95296554Sobrien		  (u_long)sc, bus, target, lun);
953128511Sscottl		return (NULL);
95496554Sobrien	}
95596554Sobrien	/*
95696554Sobrien	 *	See if there is an associated bus list.
95796554Sobrien	 *
95896554Sobrien	 *	for performance, allocate in size of BUS_CHUNK chunks.
95996554Sobrien	 *	BUS_CHUNK must be a power of two. This is to reduce
96096554Sobrien	 *	fragmentation effects on the allocations.
96196554Sobrien	 */
962128535Sscottl#define BUS_CHUNK 8
96396554Sobrien	new_size = ((target + BUS_CHUNK - 1) & ~(BUS_CHUNK - 1));
964128511Sscottl	if ((bus_ptr = sc->ha_targets[bus]) == NULL) {
96596554Sobrien		/*
96696554Sobrien		 *	Allocate a new structure?
96796554Sobrien		 *		Since one element in structure, the +1
96896554Sobrien		 *		needed for size has been abstracted.
96996554Sobrien		 */
97096554Sobrien		if ((new_entry == FALSE)
97196554Sobrien		 || ((sc->ha_targets[bus] = bus_ptr = (target2lun_t *)malloc (
97296554Sobrien		    sizeof(*bus_ptr) + (sizeof(bus_ptr->LUN) * new_size),
973111119Simp		    M_TEMP, M_WAITOK | M_ZERO))
974128511Sscottl		   == NULL)) {
97596554Sobrien			debug_asr_printf("failed to allocate bus list\n");
976128511Sscottl			return (NULL);
97796554Sobrien		}
97896554Sobrien		bus_ptr->size = new_size + 1;
97996554Sobrien	} else if (bus_ptr->size <= new_size) {
98096554Sobrien		target2lun_t * new_bus_ptr;
98165312Smsmith
98296554Sobrien		/*
98396554Sobrien		 *	Reallocate a new structure?
98496554Sobrien		 *		Since one element in structure, the +1
98596554Sobrien		 *		needed for size has been abstracted.
98696554Sobrien		 */
98796554Sobrien		if ((new_entry == FALSE)
98896554Sobrien		 || ((new_bus_ptr = (target2lun_t *)malloc (
98996554Sobrien		    sizeof(*bus_ptr) + (sizeof(bus_ptr->LUN) * new_size),
990128511Sscottl		    M_TEMP, M_WAITOK | M_ZERO)) == NULL)) {
99196554Sobrien			debug_asr_printf("failed to reallocate bus list\n");
992128511Sscottl			return (NULL);
99396554Sobrien		}
99496554Sobrien		/*
99596554Sobrien		 *	Copy the whole thing, safer, simpler coding
99696554Sobrien		 * and not really performance critical at this point.
99796554Sobrien		 */
998128786Sscottl		bcopy(bus_ptr, new_bus_ptr, sizeof(*bus_ptr)
999128786Sscottl		    + (sizeof(bus_ptr->LUN) * (bus_ptr->size - 1)));
100096554Sobrien		sc->ha_targets[bus] = new_bus_ptr;
1001128812Sscottl		free(bus_ptr, M_TEMP);
100296554Sobrien		bus_ptr = new_bus_ptr;
100396554Sobrien		bus_ptr->size = new_size + 1;
100496554Sobrien	}
100596554Sobrien	/*
100696554Sobrien	 *	We now have the bus list, lets get to the target list.
100796554Sobrien	 *	Since most systems have only *one* lun, we do not allocate
100896554Sobrien	 *	in chunks as above, here we allow one, then in chunk sizes.
100996554Sobrien	 *	TARGET_CHUNK must be a power of two. This is to reduce
101096554Sobrien	 *	fragmentation effects on the allocations.
101196554Sobrien	 */
1012128535Sscottl#define TARGET_CHUNK 8
101396554Sobrien	if ((new_size = lun) != 0) {
101496554Sobrien		new_size = ((lun + TARGET_CHUNK - 1) & ~(TARGET_CHUNK - 1));
101596554Sobrien	}
1016128511Sscottl	if ((target_ptr = bus_ptr->LUN[target]) == NULL) {
101796554Sobrien		/*
101896554Sobrien		 *	Allocate a new structure?
101996554Sobrien		 *		Since one element in structure, the +1
102096554Sobrien		 *		needed for size has been abstracted.
102196554Sobrien		 */
102296554Sobrien		if ((new_entry == FALSE)
102396554Sobrien		 || ((bus_ptr->LUN[target] = target_ptr = (lun2tid_t *)malloc (
102496554Sobrien		    sizeof(*target_ptr) + (sizeof(target_ptr->TID) * new_size),
1025128511Sscottl		    M_TEMP, M_WAITOK | M_ZERO)) == NULL)) {
102696554Sobrien			debug_asr_printf("failed to allocate target list\n");
1027128511Sscottl			return (NULL);
102896554Sobrien		}
102996554Sobrien		target_ptr->size = new_size + 1;
103096554Sobrien	} else if (target_ptr->size <= new_size) {
103196554Sobrien		lun2tid_t * new_target_ptr;
103265312Smsmith
103396554Sobrien		/*
103496554Sobrien		 *	Reallocate a new structure?
103596554Sobrien		 *		Since one element in structure, the +1
103696554Sobrien		 *		needed for size has been abstracted.
103796554Sobrien		 */
103896554Sobrien		if ((new_entry == FALSE)
103996554Sobrien		 || ((new_target_ptr = (lun2tid_t *)malloc (
104096554Sobrien		    sizeof(*target_ptr) + (sizeof(target_ptr->TID) * new_size),
1041128511Sscottl		    M_TEMP, M_WAITOK | M_ZERO)) == NULL)) {
104296554Sobrien			debug_asr_printf("failed to reallocate target list\n");
1043128511Sscottl			return (NULL);
104496554Sobrien		}
104596554Sobrien		/*
104696554Sobrien		 *	Copy the whole thing, safer, simpler coding
104796554Sobrien		 * and not really performance critical at this point.
104896554Sobrien		 */
1049128786Sscottl		bcopy(target_ptr, new_target_ptr, sizeof(*target_ptr)
1050128786Sscottl		    + (sizeof(target_ptr->TID) * (target_ptr->size - 1)));
105196554Sobrien		bus_ptr->LUN[target] = new_target_ptr;
1052128812Sscottl		free(target_ptr, M_TEMP);
105396554Sobrien		target_ptr = new_target_ptr;
105496554Sobrien		target_ptr->size = new_size + 1;
105596554Sobrien	}
105696554Sobrien	/*
105796554Sobrien	 *	Now, acquire the TID address from the LUN indexed list.
105896554Sobrien	 */
105996554Sobrien	return (&(target_ptr->TID[lun]));
106065312Smsmith} /* ASR_getTidAddress */
106165312Smsmith
106265312Smsmith/*
106396554Sobrien *	Get a pre-existing TID relationship.
106465312Smsmith *
106596554Sobrien *	If the TID was never set, return (tid_t)-1.
106665312Smsmith *
106796554Sobrien *	should use mutex rather than spl.
106865312Smsmith */
1069128784Sscottlstatic __inline tid_t
1070128784SscottlASR_getTid(Asr_softc_t *sc, int bus, int target, int lun)
107165312Smsmith{
1072128784Sscottl	tid_t	*tid_ptr;
1073128784Sscottl	int	s;
1074128784Sscottl	tid_t	retval;
107565312Smsmith
107696554Sobrien	s = splcam();
1077128511Sscottl	if (((tid_ptr = ASR_getTidAddress(sc, bus, target, lun, FALSE)) == NULL)
107896554Sobrien	/* (tid_t)0 or (tid_t)-1 indicate no TID */
107996554Sobrien	 || (*tid_ptr == (tid_t)0)) {
108096554Sobrien		splx(s);
108196554Sobrien		return ((tid_t)-1);
108296554Sobrien	}
108396554Sobrien	retval = *tid_ptr;
108496554Sobrien	splx(s);
108596554Sobrien	return (retval);
108665312Smsmith} /* ASR_getTid */
108765312Smsmith
108865312Smsmith/*
108996554Sobrien *	Set a TID relationship.
109065312Smsmith *
109196554Sobrien *	If the TID was not set, return (tid_t)-1.
109265312Smsmith *
109396554Sobrien *	should use mutex rather than spl.
109465312Smsmith */
1095128784Sscottlstatic __inline tid_t
1096128784SscottlASR_setTid(Asr_softc_t *sc, int bus, int target, int lun, tid_t	TID)
109765312Smsmith{
1098128784Sscottl	tid_t	*tid_ptr;
1099128784Sscottl	int	s;
110065312Smsmith
110196554Sobrien	if (TID != (tid_t)-1) {
110296554Sobrien		if (TID == 0) {
110396554Sobrien			return ((tid_t)-1);
110496554Sobrien		}
110596554Sobrien		s = splcam();
1106128784Sscottl		if ((tid_ptr = ASR_getTidAddress(sc, bus, target, lun, TRUE))
1107128511Sscottl		 == NULL) {
110896554Sobrien			splx(s);
110996554Sobrien			return ((tid_t)-1);
111096554Sobrien		}
111196554Sobrien		*tid_ptr = TID;
111296554Sobrien		splx(s);
111396554Sobrien	}
111496554Sobrien	return (TID);
111565312Smsmith} /* ASR_setTid */
111665312Smsmith
111765312Smsmith/*-------------------------------------------------------------------------*/
111896554Sobrien/*		      Function ASR_rescan				   */
111965312Smsmith/*-------------------------------------------------------------------------*/
112096554Sobrien/* The Parameters Passed To This Function Are :				   */
112196554Sobrien/*     Asr_softc_t *	 : HBA miniport driver's adapter data storage.	   */
112296554Sobrien/*									   */
112396554Sobrien/* This Function Will rescan the adapter and resynchronize any data	   */
112496554Sobrien/*									   */
112596554Sobrien/* Return : 0 For OK, Error Code Otherwise				   */
112665312Smsmith/*-------------------------------------------------------------------------*/
112765312Smsmith
1128128784Sscottlstatic int
1129128784SscottlASR_rescan(Asr_softc_t *sc)
113065312Smsmith{
1131128784Sscottl	int bus;
1132128784Sscottl	int error;
113365312Smsmith
113496554Sobrien	/*
113596554Sobrien	 * Re-acquire the LCT table and synchronize us to the adapter.
113696554Sobrien	 */
113796554Sobrien	if ((error = ASR_acquireLct(sc)) == 0) {
113896554Sobrien		error = ASR_acquireHrt(sc);
113996554Sobrien	}
114065312Smsmith
114196554Sobrien	if (error != 0) {
114296554Sobrien		return error;
114396554Sobrien	}
114465312Smsmith
114596554Sobrien	bus = sc->ha_MaxBus;
114696554Sobrien	/* Reset all existing cached TID lookups */
114796554Sobrien	do {
114896554Sobrien		int target, event = 0;
114965312Smsmith
115096554Sobrien		/*
115196554Sobrien		 *	Scan for all targets on this bus to see if they
115296554Sobrien		 * got affected by the rescan.
115396554Sobrien		 */
115496554Sobrien		for (target = 0; target <= sc->ha_MaxId; ++target) {
115596554Sobrien			int lun;
115665312Smsmith
115796554Sobrien			/* Stay away from the controller ID */
115896554Sobrien			if (target == sc->ha_adapter_target[bus]) {
115996554Sobrien				continue;
116096554Sobrien			}
116196554Sobrien			for (lun = 0; lun <= sc->ha_MaxLun; ++lun) {
116296554Sobrien				PI2O_LCT_ENTRY Device;
116396554Sobrien				tid_t	       TID = (tid_t)-1;
116496554Sobrien				tid_t	       LastTID;
116565312Smsmith
116696554Sobrien				/*
116796554Sobrien				 * See if the cached TID changed. Search for
116896554Sobrien				 * the device in our new LCT.
116996554Sobrien				 */
117096554Sobrien				for (Device = sc->ha_LCT->LCTEntry;
117196554Sobrien				  Device < (PI2O_LCT_ENTRY)(((U32 *)sc->ha_LCT)
117296554Sobrien				   + I2O_LCT_getTableSize(sc->ha_LCT));
117396554Sobrien				  ++Device) {
117496554Sobrien					if ((Device->le_type != I2O_UNKNOWN)
117596554Sobrien					 && (Device->le_bus == bus)
117696554Sobrien					 && (Device->le_target == target)
117796554Sobrien					 && (Device->le_lun == lun)
117896554Sobrien					 && (I2O_LCT_ENTRY_getUserTID(Device)
117996554Sobrien					  == 0xFFF)) {
118096554Sobrien						TID = I2O_LCT_ENTRY_getLocalTID(
118196554Sobrien						  Device);
118296554Sobrien						break;
118396554Sobrien					}
118496554Sobrien				}
118596554Sobrien				/*
118696554Sobrien				 * Indicate to the OS that the label needs
118796554Sobrien				 * to be recalculated, or that the specific
118896554Sobrien				 * open device is no longer valid (Merde)
118996554Sobrien				 * because the cached TID changed.
119096554Sobrien				 */
119196554Sobrien				LastTID = ASR_getTid (sc, bus, target, lun);
119296554Sobrien				if (LastTID != TID) {
119396554Sobrien					struct cam_path * path;
119482092Sscottl
119596554Sobrien					if (xpt_create_path(&path,
119696554Sobrien					  /*periph*/NULL,
119796554Sobrien					  cam_sim_path(sc->ha_sim[bus]),
119896554Sobrien					  target, lun) != CAM_REQ_CMP) {
119996554Sobrien						if (TID == (tid_t)-1) {
120096554Sobrien							event |= AC_LOST_DEVICE;
120196554Sobrien						} else {
120296554Sobrien							event |= AC_INQ_CHANGED
120396554Sobrien							       | AC_GETDEV_CHANGED;
120496554Sobrien						}
120596554Sobrien					} else {
120696554Sobrien						if (TID == (tid_t)-1) {
120796554Sobrien							xpt_async(
120896554Sobrien							  AC_LOST_DEVICE,
120996554Sobrien							  path, NULL);
121096554Sobrien						} else if (LastTID == (tid_t)-1) {
121196554Sobrien							struct ccb_getdev ccb;
121282092Sscottl
121396554Sobrien							xpt_setup_ccb(
121496554Sobrien							  &(ccb.ccb_h),
121596554Sobrien							  path, /*priority*/5);
121696554Sobrien							xpt_async(
121796554Sobrien							  AC_FOUND_DEVICE,
121896554Sobrien							  path,
121996554Sobrien							  &ccb);
122096554Sobrien						} else {
122196554Sobrien							xpt_async(
122296554Sobrien							  AC_INQ_CHANGED,
122396554Sobrien							  path, NULL);
122496554Sobrien							xpt_async(
122596554Sobrien							  AC_GETDEV_CHANGED,
122696554Sobrien							  path, NULL);
122796554Sobrien						}
122896554Sobrien					}
122996554Sobrien				}
123096554Sobrien				/*
123196554Sobrien				 *	We have the option of clearing the
123296554Sobrien				 * cached TID for it to be rescanned, or to
123396554Sobrien				 * set it now even if the device never got
123496554Sobrien				 * accessed. We chose the later since we
123596554Sobrien				 * currently do not use the condition that
123696554Sobrien				 * the TID ever got cached.
123796554Sobrien				 */
123896554Sobrien				ASR_setTid (sc, bus, target, lun, TID);
123996554Sobrien			}
124096554Sobrien		}
124196554Sobrien		/*
124296554Sobrien		 *	The xpt layer can not handle multiple events at the
124396554Sobrien		 * same call.
124496554Sobrien		 */
124596554Sobrien		if (event & AC_LOST_DEVICE) {
124696554Sobrien			xpt_async(AC_LOST_DEVICE, sc->ha_path[bus], NULL);
124796554Sobrien		}
124896554Sobrien		if (event & AC_INQ_CHANGED) {
124996554Sobrien			xpt_async(AC_INQ_CHANGED, sc->ha_path[bus], NULL);
125096554Sobrien		}
125196554Sobrien		if (event & AC_GETDEV_CHANGED) {
125296554Sobrien			xpt_async(AC_GETDEV_CHANGED, sc->ha_path[bus], NULL);
125396554Sobrien		}
125496554Sobrien	} while (--bus >= 0);
125596554Sobrien	return (error);
125665312Smsmith} /* ASR_rescan */
125765312Smsmith
125865312Smsmith/*-------------------------------------------------------------------------*/
125996554Sobrien/*		      Function ASR_reset				   */
126065312Smsmith/*-------------------------------------------------------------------------*/
126196554Sobrien/* The Parameters Passed To This Function Are :				   */
126296554Sobrien/*     Asr_softc_t *	  : HBA miniport driver's adapter data storage.	   */
126396554Sobrien/*									   */
126496554Sobrien/* This Function Will reset the adapter and resynchronize any data	   */
126596554Sobrien/*									   */
126696554Sobrien/* Return : None							   */
126765312Smsmith/*-------------------------------------------------------------------------*/
126865312Smsmith
1269128784Sscottlstatic int
1270128784SscottlASR_reset(Asr_softc_t *sc)
127165312Smsmith{
1272128784Sscottl	int s, retVal;
127382092Sscottl
127496554Sobrien	s = splcam();
127596554Sobrien	if ((sc->ha_in_reset == HA_IN_RESET)
127696554Sobrien	 || (sc->ha_in_reset == HA_OFF_LINE_RECOVERY)) {
127796554Sobrien		splx (s);
127896554Sobrien		return (EBUSY);
127996554Sobrien	}
128096554Sobrien	/*
128196554Sobrien	 *	Promotes HA_OPERATIONAL to HA_IN_RESET,
128296554Sobrien	 * or HA_OFF_LINE to HA_OFF_LINE_RECOVERY.
128396554Sobrien	 */
128496554Sobrien	++(sc->ha_in_reset);
1285128944Sscottl	if (ASR_resetIOP(sc) == 0) {
128696554Sobrien		debug_asr_printf ("ASR_resetIOP failed\n");
128796554Sobrien		/*
128896554Sobrien		 *	We really need to take this card off-line, easier said
128996554Sobrien		 * than make sense. Better to keep retrying for now since if a
129096554Sobrien		 * UART cable is connected the blinkLEDs the adapter is now in
129196554Sobrien		 * a hard state requiring action from the monitor commands to
129296554Sobrien		 * the HBA to continue. For debugging waiting forever is a
129396554Sobrien		 * good thing. In a production system, however, one may wish
129496554Sobrien		 * to instead take the card off-line ...
129596554Sobrien		 */
1296128536Sscottl		/* Wait Forever */
1297128944Sscottl		while (ASR_resetIOP(sc) == 0);
129896554Sobrien	}
129996554Sobrien	retVal = ASR_init (sc);
130096554Sobrien	splx (s);
130196554Sobrien	if (retVal != 0) {
130296554Sobrien		debug_asr_printf ("ASR_init failed\n");
130396554Sobrien		sc->ha_in_reset = HA_OFF_LINE;
130496554Sobrien		return (ENXIO);
130596554Sobrien	}
130696554Sobrien	if (ASR_rescan (sc) != 0) {
130796554Sobrien		debug_asr_printf ("ASR_rescan failed\n");
130896554Sobrien	}
130996554Sobrien	ASR_failActiveCommands (sc);
131096554Sobrien	if (sc->ha_in_reset == HA_OFF_LINE_RECOVERY) {
131196554Sobrien		printf ("asr%d: Brining adapter back on-line\n",
131296554Sobrien		  sc->ha_path[0]
131396554Sobrien		    ? cam_sim_unit(xpt_path_sim(sc->ha_path[0]))
131496554Sobrien		    : 0);
131596554Sobrien	}
131696554Sobrien	sc->ha_in_reset = HA_OPERATIONAL;
131796554Sobrien	return (0);
131865312Smsmith} /* ASR_reset */
131965312Smsmith
132065312Smsmith/*
132196554Sobrien *	Device timeout handler.
132265312Smsmith */
1323128784Sscottlstatic void
1324128784Sscottlasr_timeout(void *arg)
132565312Smsmith{
1326128784Sscottl	union asr_ccb	*ccb = (union asr_ccb *)arg;
1327128784Sscottl	Asr_softc_t	*sc = (Asr_softc_t *)(ccb->ccb_h.spriv_ptr0);
132896554Sobrien	int		s;
132965312Smsmith
133096554Sobrien	debug_asr_print_path(ccb);
133196554Sobrien	debug_asr_printf("timed out");
133265312Smsmith
133396554Sobrien	/*
133496554Sobrien	 *	Check if the adapter has locked up?
133596554Sobrien	 */
133696554Sobrien	if ((s = ASR_getBlinkLedCode(sc)) != 0) {
133796554Sobrien		/* Reset Adapter */
133896554Sobrien		printf ("asr%d: Blink LED 0x%x resetting adapter\n",
133996554Sobrien		  cam_sim_unit(xpt_path_sim(ccb->ccb_h.path)), s);
134096554Sobrien		if (ASR_reset (sc) == ENXIO) {
134196554Sobrien			/* Try again later */
1342275982Ssmh			set_ccb_timeout_ch(ccb);
134396554Sobrien		}
134496554Sobrien		return;
134596554Sobrien	}
134696554Sobrien	/*
134796554Sobrien	 *	Abort does not function on the ASR card!!! Walking away from
134896554Sobrien	 * the SCSI command is also *very* dangerous. A SCSI BUS reset is
134996554Sobrien	 * our best bet, followed by a complete adapter reset if that fails.
135096554Sobrien	 */
135196554Sobrien	s = splcam();
135296554Sobrien	/* Check if we already timed out once to raise the issue */
135396554Sobrien	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_CMD_TIMEOUT) {
135496554Sobrien		debug_asr_printf (" AGAIN\nreinitializing adapter\n");
135596554Sobrien		if (ASR_reset (sc) == ENXIO) {
1356275982Ssmh			set_ccb_timeout_ch(ccb);
135796554Sobrien		}
135896554Sobrien		splx(s);
135996554Sobrien		return;
136096554Sobrien	}
136196554Sobrien	debug_asr_printf ("\nresetting bus\n");
136296554Sobrien	/* If the BUS reset does not take, then an adapter reset is next! */
136396554Sobrien	ccb->ccb_h.status &= ~CAM_STATUS_MASK;
136496554Sobrien	ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
1365275982Ssmh	set_ccb_timeout_ch(ccb);
136696554Sobrien	ASR_resetBus (sc, cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)));
136796554Sobrien	xpt_async (AC_BUS_RESET, ccb->ccb_h.path, NULL);
136896554Sobrien	splx(s);
136965312Smsmith} /* asr_timeout */
137065312Smsmith
137165312Smsmith/*
137265312Smsmith * send a message asynchronously
137365312Smsmith */
1374128784Sscottlstatic int
1375128784SscottlASR_queue(Asr_softc_t *sc, PI2O_MESSAGE_FRAME Message)
137665312Smsmith{
1377128784Sscottl	U32		MessageOffset;
1378128784Sscottl	union asr_ccb	*ccb;
137965312Smsmith
1380128786Sscottl	debug_asr_printf("Host Command Dump:\n");
1381128786Sscottl	debug_asr_dump_message(Message);
138265312Smsmith
138396554Sobrien	ccb = (union asr_ccb *)(long)
138496554Sobrien	  I2O_MESSAGE_FRAME_getInitiatorContext64(Message);
138565312Smsmith
1386128944Sscottl	if ((MessageOffset = ASR_getMessage(sc)) != EMPTY_QUEUE) {
1387128944Sscottl		asr_set_frame(sc, Message, MessageOffset,
1388128944Sscottl			      I2O_MESSAGE_FRAME_getMessageSize(Message));
138996554Sobrien		if (ccb) {
139096554Sobrien			ASR_ccbAdd (sc, ccb);
139196554Sobrien		}
139296554Sobrien		/* Post the command */
1393128944Sscottl		asr_set_ToFIFO(sc, MessageOffset);
139496554Sobrien	} else {
139596554Sobrien		if (ASR_getBlinkLedCode(sc)) {
139696554Sobrien			/*
139796554Sobrien			 *	Unlikely we can do anything if we can't grab a
139896554Sobrien			 * message frame :-(, but lets give it a try.
139996554Sobrien			 */
1400128784Sscottl			(void)ASR_reset(sc);
140196554Sobrien		}
140296554Sobrien	}
140396554Sobrien	return (MessageOffset);
140465312Smsmith} /* ASR_queue */
140565312Smsmith
140665312Smsmith
140765312Smsmith/* Simple Scatter Gather elements */
140896615Sobrien#define	SG(SGL,Index,Flags,Buffer,Size)				   \
140996554Sobrien	I2O_FLAGS_COUNT_setCount(				   \
141096554Sobrien	  &(((PI2O_SG_ELEMENT)(SGL))->u.Simple[Index].FlagsCount), \
141196554Sobrien	  Size);						   \
141296554Sobrien	I2O_FLAGS_COUNT_setFlags(				   \
141396554Sobrien	  &(((PI2O_SG_ELEMENT)(SGL))->u.Simple[Index].FlagsCount), \
141496554Sobrien	  I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT | (Flags));	   \
141596554Sobrien	I2O_SGE_SIMPLE_ELEMENT_setPhysicalAddress(		   \
141696554Sobrien	  &(((PI2O_SG_ELEMENT)(SGL))->u.Simple[Index]),		   \
1417102291Sarchie	  (Buffer == NULL) ? 0 : KVTOPHYS(Buffer))
141865312Smsmith
141965312Smsmith/*
142096554Sobrien *	Retrieve Parameter Group.
142165312Smsmith */
1422128784Sscottlstatic void *
1423128784SscottlASR_getParams(Asr_softc_t *sc, tid_t TID, int Group, void *Buffer,
1424128784Sscottl	      unsigned BufferSize)
142565312Smsmith{
142696554Sobrien	struct paramGetMessage {
142796554Sobrien		I2O_UTIL_PARAMS_GET_MESSAGE M;
1428128784Sscottl		char
1429128784Sscottl		   F[sizeof(I2O_SGE_SIMPLE_ELEMENT)*2 - sizeof(I2O_SG_ELEMENT)];
143096554Sobrien		struct Operations {
143196554Sobrien			I2O_PARAM_OPERATIONS_LIST_HEADER Header;
143296554Sobrien			I2O_PARAM_OPERATION_ALL_TEMPLATE Template[1];
143396554Sobrien		}			     O;
1434128812Sscottl	}				Message;
1435128812Sscottl	struct Operations		*Operations_Ptr;
1436128812Sscottl	I2O_UTIL_PARAMS_GET_MESSAGE	*Message_Ptr;
143796554Sobrien	struct ParamBuffer {
143896554Sobrien		I2O_PARAM_RESULTS_LIST_HEADER	    Header;
143996554Sobrien		I2O_PARAM_READ_OPERATION_RESULT	    Read;
144096554Sobrien		char				    Info[1];
1441128812Sscottl	}				*Buffer_Ptr;
144265312Smsmith
1443128812Sscottl	Message_Ptr = (I2O_UTIL_PARAMS_GET_MESSAGE *)ASR_fillMessage(&Message,
144496554Sobrien	  sizeof(I2O_UTIL_PARAMS_GET_MESSAGE)
144596554Sobrien	    + sizeof(I2O_SGE_SIMPLE_ELEMENT)*2 - sizeof(I2O_SG_ELEMENT));
144696554Sobrien	Operations_Ptr = (struct Operations *)((char *)Message_Ptr
144796554Sobrien	  + sizeof(I2O_UTIL_PARAMS_GET_MESSAGE)
144896554Sobrien	  + sizeof(I2O_SGE_SIMPLE_ELEMENT)*2 - sizeof(I2O_SG_ELEMENT));
1449128787Sscottl	bzero(Operations_Ptr, sizeof(struct Operations));
145096554Sobrien	I2O_PARAM_OPERATIONS_LIST_HEADER_setOperationCount(
145196554Sobrien	  &(Operations_Ptr->Header), 1);
145296554Sobrien	I2O_PARAM_OPERATION_ALL_TEMPLATE_setOperation(
145396554Sobrien	  &(Operations_Ptr->Template[0]), I2O_PARAMS_OPERATION_FIELD_GET);
145496554Sobrien	I2O_PARAM_OPERATION_ALL_TEMPLATE_setFieldCount(
145596554Sobrien	  &(Operations_Ptr->Template[0]), 0xFFFF);
145696554Sobrien	I2O_PARAM_OPERATION_ALL_TEMPLATE_setGroupNumber(
145796554Sobrien	  &(Operations_Ptr->Template[0]), Group);
1458128812Sscottl	Buffer_Ptr = (struct ParamBuffer *)Buffer;
1459128787Sscottl	bzero(Buffer_Ptr, BufferSize);
146065312Smsmith
146196554Sobrien	I2O_MESSAGE_FRAME_setVersionOffset(&(Message_Ptr->StdMessageFrame),
146296554Sobrien	  I2O_VERSION_11
146396554Sobrien	  + (((sizeof(I2O_UTIL_PARAMS_GET_MESSAGE) - sizeof(I2O_SG_ELEMENT))
146496554Sobrien	    / sizeof(U32)) << 4));
146596554Sobrien	I2O_MESSAGE_FRAME_setTargetAddress (&(Message_Ptr->StdMessageFrame),
146696554Sobrien	  TID);
146796554Sobrien	I2O_MESSAGE_FRAME_setFunction (&(Message_Ptr->StdMessageFrame),
146896554Sobrien	  I2O_UTIL_PARAMS_GET);
146996554Sobrien	/*
147096554Sobrien	 *  Set up the buffers as scatter gather elements.
147196554Sobrien	 */
147296554Sobrien	SG(&(Message_Ptr->SGL), 0,
147396554Sobrien	  I2O_SGL_FLAGS_DIR | I2O_SGL_FLAGS_END_OF_BUFFER,
147496554Sobrien	  Operations_Ptr, sizeof(struct Operations));
147596554Sobrien	SG(&(Message_Ptr->SGL), 1,
147696554Sobrien	  I2O_SGL_FLAGS_LAST_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER,
147796554Sobrien	  Buffer_Ptr, BufferSize);
147865312Smsmith
147996554Sobrien	if ((ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr) == CAM_REQ_CMP)
148096554Sobrien	 && (Buffer_Ptr->Header.ResultCount)) {
148196554Sobrien		return ((void *)(Buffer_Ptr->Info));
148296554Sobrien	}
1483128511Sscottl	return (NULL);
148465312Smsmith} /* ASR_getParams */
148565312Smsmith
148665312Smsmith/*
148796554Sobrien *	Acquire the LCT information.
148865312Smsmith */
1489128784Sscottlstatic int
1490128784SscottlASR_acquireLct(Asr_softc_t *sc)
149165312Smsmith{
1492128784Sscottl	PI2O_EXEC_LCT_NOTIFY_MESSAGE	Message_Ptr;
1493128784Sscottl	PI2O_SGE_SIMPLE_ELEMENT		sg;
1494128784Sscottl	int				MessageSizeInBytes;
1495128784Sscottl	caddr_t				v;
1496128784Sscottl	int				len;
1497128784Sscottl	I2O_LCT				Table;
1498128784Sscottl	PI2O_LCT_ENTRY			Entry;
149965312Smsmith
150096554Sobrien	/*
150196554Sobrien	 *	sc value assumed valid
150296554Sobrien	 */
1503128908Sscottl	MessageSizeInBytes = sizeof(I2O_EXEC_LCT_NOTIFY_MESSAGE) -
1504128908Sscottl	    sizeof(I2O_SG_ELEMENT) + sizeof(I2O_SGE_SIMPLE_ELEMENT);
1505128908Sscottl	if ((Message_Ptr = (PI2O_EXEC_LCT_NOTIFY_MESSAGE)malloc(
1506128908Sscottl	    MessageSizeInBytes, M_TEMP, M_WAITOK)) == NULL) {
150796554Sobrien		return (ENOMEM);
150896554Sobrien	}
1509128812Sscottl	(void)ASR_fillMessage((void *)Message_Ptr, MessageSizeInBytes);
151096554Sobrien	I2O_MESSAGE_FRAME_setVersionOffset(&(Message_Ptr->StdMessageFrame),
1511128908Sscottl	    (I2O_VERSION_11 + (((sizeof(I2O_EXEC_LCT_NOTIFY_MESSAGE) -
1512128908Sscottl	    sizeof(I2O_SG_ELEMENT)) / sizeof(U32)) << 4)));
151396554Sobrien	I2O_MESSAGE_FRAME_setFunction(&(Message_Ptr->StdMessageFrame),
1514128908Sscottl	    I2O_EXEC_LCT_NOTIFY);
151596554Sobrien	I2O_EXEC_LCT_NOTIFY_MESSAGE_setClassIdentifier(Message_Ptr,
1516128908Sscottl	    I2O_CLASS_MATCH_ANYCLASS);
151796554Sobrien	/*
151896554Sobrien	 *	Call the LCT table to determine the number of device entries
151996554Sobrien	 * to reserve space for.
152096554Sobrien	 */
152196554Sobrien	SG(&(Message_Ptr->SGL), 0,
152296554Sobrien	  I2O_SGL_FLAGS_LAST_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER, &Table,
152396554Sobrien	  sizeof(I2O_LCT));
152496554Sobrien	/*
152596554Sobrien	 *	since this code is reused in several systems, code efficiency
152696554Sobrien	 * is greater by using a shift operation rather than a divide by
152796554Sobrien	 * sizeof(u_int32_t).
152896554Sobrien	 */
152996554Sobrien	I2O_LCT_setTableSize(&Table,
153096554Sobrien	  (sizeof(I2O_LCT) - sizeof(I2O_LCT_ENTRY)) >> 2);
153196554Sobrien	(void)ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr);
153296554Sobrien	/*
153396554Sobrien	 *	Determine the size of the LCT table.
153496554Sobrien	 */
153596554Sobrien	if (sc->ha_LCT) {
1536128812Sscottl		free(sc->ha_LCT, M_TEMP);
153796554Sobrien	}
153896554Sobrien	/*
153996554Sobrien	 *	malloc only generates contiguous memory when less than a
154096554Sobrien	 * page is expected. We must break the request up into an SG list ...
154196554Sobrien	 */
154296554Sobrien	if (((len = (I2O_LCT_getTableSize(&Table) << 2)) <=
154396554Sobrien	  (sizeof(I2O_LCT) - sizeof(I2O_LCT_ENTRY)))
154496554Sobrien	 || (len > (128 * 1024))) {	/* Arbitrary */
1545128812Sscottl		free(Message_Ptr, M_TEMP);
154696554Sobrien		return (EINVAL);
154796554Sobrien	}
1548128511Sscottl	if ((sc->ha_LCT = (PI2O_LCT)malloc (len, M_TEMP, M_WAITOK)) == NULL) {
1549128812Sscottl		free(Message_Ptr, M_TEMP);
155096554Sobrien		return (ENOMEM);
155196554Sobrien	}
155296554Sobrien	/*
155396554Sobrien	 *	since this code is reused in several systems, code efficiency
155496554Sobrien	 * is greater by using a shift operation rather than a divide by
155596554Sobrien	 * sizeof(u_int32_t).
155696554Sobrien	 */
155796554Sobrien	I2O_LCT_setTableSize(sc->ha_LCT,
155896554Sobrien	  (sizeof(I2O_LCT) - sizeof(I2O_LCT_ENTRY)) >> 2);
155996554Sobrien	/*
156096554Sobrien	 *	Convert the access to the LCT table into a SG list.
156196554Sobrien	 */
156296554Sobrien	sg = Message_Ptr->SGL.u.Simple;
156396554Sobrien	v = (caddr_t)(sc->ha_LCT);
156496554Sobrien	for (;;) {
156596554Sobrien		int next, base, span;
156665312Smsmith
156796554Sobrien		span = 0;
156896554Sobrien		next = base = KVTOPHYS(v);
156996554Sobrien		I2O_SGE_SIMPLE_ELEMENT_setPhysicalAddress(sg, base);
157065312Smsmith
157196554Sobrien		/* How far can we go contiguously */
157296554Sobrien		while ((len > 0) && (base == next)) {
157396554Sobrien			int size;
157465312Smsmith
157596554Sobrien			next = trunc_page(base) + PAGE_SIZE;
157696554Sobrien			size = next - base;
157796554Sobrien			if (size > len) {
157896554Sobrien				size = len;
157996554Sobrien			}
158096554Sobrien			span += size;
158196554Sobrien			v += size;
158296554Sobrien			len -= size;
158396554Sobrien			base = KVTOPHYS(v);
158496554Sobrien		}
158565312Smsmith
158696554Sobrien		/* Construct the Flags */
158796554Sobrien		I2O_FLAGS_COUNT_setCount(&(sg->FlagsCount), span);
158896554Sobrien		{
158996554Sobrien			int rw = I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT;
159096554Sobrien			if (len <= 0) {
159196554Sobrien				rw = (I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT
159296554Sobrien				    | I2O_SGL_FLAGS_LAST_ELEMENT
159396554Sobrien				    | I2O_SGL_FLAGS_END_OF_BUFFER);
159496554Sobrien			}
159596554Sobrien			I2O_FLAGS_COUNT_setFlags(&(sg->FlagsCount), rw);
159696554Sobrien		}
159765312Smsmith
159896554Sobrien		if (len <= 0) {
159996554Sobrien			break;
160096554Sobrien		}
160165312Smsmith
160296554Sobrien		/*
160396554Sobrien		 * Incrementing requires resizing of the packet.
160496554Sobrien		 */
160596554Sobrien		++sg;
160696554Sobrien		MessageSizeInBytes += sizeof(*sg);
160796554Sobrien		I2O_MESSAGE_FRAME_setMessageSize(
160896554Sobrien		  &(Message_Ptr->StdMessageFrame),
160996554Sobrien		  I2O_MESSAGE_FRAME_getMessageSize(
161096554Sobrien		    &(Message_Ptr->StdMessageFrame))
161196554Sobrien		  + (sizeof(*sg) / sizeof(U32)));
161296554Sobrien		{
161396554Sobrien			PI2O_EXEC_LCT_NOTIFY_MESSAGE NewMessage_Ptr;
161465312Smsmith
161596554Sobrien			if ((NewMessage_Ptr = (PI2O_EXEC_LCT_NOTIFY_MESSAGE)
1616128511Sscottl			    malloc(MessageSizeInBytes, M_TEMP, M_WAITOK))
1617128511Sscottl			    == NULL) {
1618128812Sscottl				free(sc->ha_LCT, M_TEMP);
1619128511Sscottl				sc->ha_LCT = NULL;
1620128812Sscottl				free(Message_Ptr, M_TEMP);
162196554Sobrien				return (ENOMEM);
162296554Sobrien			}
162396554Sobrien			span = ((caddr_t)sg) - (caddr_t)Message_Ptr;
1624128786Sscottl			bcopy(Message_Ptr, NewMessage_Ptr, span);
1625128786Sscottl			free(Message_Ptr, M_TEMP);
162696554Sobrien			sg = (PI2O_SGE_SIMPLE_ELEMENT)
162796554Sobrien			  (((caddr_t)NewMessage_Ptr) + span);
162896554Sobrien			Message_Ptr = NewMessage_Ptr;
162996554Sobrien		}
163096554Sobrien	}
163196554Sobrien	{	int retval;
163265312Smsmith
163396554Sobrien		retval = ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr);
1634128812Sscottl		free(Message_Ptr, M_TEMP);
163596554Sobrien		if (retval != CAM_REQ_CMP) {
163696554Sobrien			return (ENODEV);
163796554Sobrien		}
163896554Sobrien	}
163996554Sobrien	/* If the LCT table grew, lets truncate accesses */
164096554Sobrien	if (I2O_LCT_getTableSize(&Table) < I2O_LCT_getTableSize(sc->ha_LCT)) {
164196554Sobrien		I2O_LCT_setTableSize(sc->ha_LCT, I2O_LCT_getTableSize(&Table));
164296554Sobrien	}
164396554Sobrien	for (Entry = sc->ha_LCT->LCTEntry; Entry < (PI2O_LCT_ENTRY)
164496554Sobrien	  (((U32 *)sc->ha_LCT)+I2O_LCT_getTableSize(sc->ha_LCT));
164596554Sobrien	  ++Entry) {
164696554Sobrien		Entry->le_type = I2O_UNKNOWN;
164796554Sobrien		switch (I2O_CLASS_ID_getClass(&(Entry->ClassID))) {
164865312Smsmith
164996554Sobrien		case I2O_CLASS_RANDOM_BLOCK_STORAGE:
165096554Sobrien			Entry->le_type = I2O_BSA;
165196554Sobrien			break;
165265312Smsmith
165396554Sobrien		case I2O_CLASS_SCSI_PERIPHERAL:
165496554Sobrien			Entry->le_type = I2O_SCSI;
165596554Sobrien			break;
165665312Smsmith
165796554Sobrien		case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL:
165896554Sobrien			Entry->le_type = I2O_FCA;
165996554Sobrien			break;
166065312Smsmith
166196554Sobrien		case I2O_CLASS_BUS_ADAPTER_PORT:
166296554Sobrien			Entry->le_type = I2O_PORT | I2O_SCSI;
166396554Sobrien			/* FALLTHRU */
166496554Sobrien		case I2O_CLASS_FIBRE_CHANNEL_PORT:
166596554Sobrien			if (I2O_CLASS_ID_getClass(&(Entry->ClassID)) ==
166696554Sobrien			  I2O_CLASS_FIBRE_CHANNEL_PORT) {
166796554Sobrien				Entry->le_type = I2O_PORT | I2O_FCA;
166896554Sobrien			}
166996554Sobrien		{	struct ControllerInfo {
167096554Sobrien				I2O_PARAM_RESULTS_LIST_HEADER	    Header;
167196554Sobrien				I2O_PARAM_READ_OPERATION_RESULT	    Read;
167296554Sobrien				I2O_HBA_SCSI_CONTROLLER_INFO_SCALAR Info;
1673128812Sscottl			} Buffer;
167496554Sobrien			PI2O_HBA_SCSI_CONTROLLER_INFO_SCALAR Info;
167565312Smsmith
167696554Sobrien			Entry->le_bus = 0xff;
167796554Sobrien			Entry->le_target = 0xff;
167896554Sobrien			Entry->le_lun = 0xff;
167965312Smsmith
168096554Sobrien			if ((Info = (PI2O_HBA_SCSI_CONTROLLER_INFO_SCALAR)
168196554Sobrien			  ASR_getParams(sc,
168296554Sobrien			    I2O_LCT_ENTRY_getLocalTID(Entry),
168396554Sobrien			    I2O_HBA_SCSI_CONTROLLER_INFO_GROUP_NO,
1684128812Sscottl			    &Buffer, sizeof(struct ControllerInfo))) == NULL) {
168596554Sobrien				continue;
168696554Sobrien			}
168796554Sobrien			Entry->le_target
168896554Sobrien			  = I2O_HBA_SCSI_CONTROLLER_INFO_SCALAR_getInitiatorID(
168996554Sobrien			    Info);
169096554Sobrien			Entry->le_lun = 0;
169196554Sobrien		}	/* FALLTHRU */
169296554Sobrien		default:
169396554Sobrien			continue;
169496554Sobrien		}
169596554Sobrien		{	struct DeviceInfo {
169696554Sobrien				I2O_PARAM_RESULTS_LIST_HEADER	Header;
169796554Sobrien				I2O_PARAM_READ_OPERATION_RESULT Read;
169896554Sobrien				I2O_DPT_DEVICE_INFO_SCALAR	Info;
1699128812Sscottl			} Buffer;
170096554Sobrien			PI2O_DPT_DEVICE_INFO_SCALAR	 Info;
170165312Smsmith
170296554Sobrien			Entry->le_bus = 0xff;
170396554Sobrien			Entry->le_target = 0xff;
170496554Sobrien			Entry->le_lun = 0xff;
170565312Smsmith
170696554Sobrien			if ((Info = (PI2O_DPT_DEVICE_INFO_SCALAR)
170796554Sobrien			  ASR_getParams(sc,
170896554Sobrien			    I2O_LCT_ENTRY_getLocalTID(Entry),
170996554Sobrien			    I2O_DPT_DEVICE_INFO_GROUP_NO,
1710128812Sscottl			    &Buffer, sizeof(struct DeviceInfo))) == NULL) {
171196554Sobrien				continue;
171296554Sobrien			}
171396554Sobrien			Entry->le_type
171496554Sobrien			  |= I2O_DPT_DEVICE_INFO_SCALAR_getDeviceType(Info);
171596554Sobrien			Entry->le_bus
171696554Sobrien			  = I2O_DPT_DEVICE_INFO_SCALAR_getBus(Info);
171796554Sobrien			if ((Entry->le_bus > sc->ha_MaxBus)
171896554Sobrien			 && (Entry->le_bus <= MAX_CHANNEL)) {
171996554Sobrien				sc->ha_MaxBus = Entry->le_bus;
172096554Sobrien			}
172196554Sobrien			Entry->le_target
172296554Sobrien			  = I2O_DPT_DEVICE_INFO_SCALAR_getIdentifier(Info);
172396554Sobrien			Entry->le_lun
172496554Sobrien			  = I2O_DPT_DEVICE_INFO_SCALAR_getLunInfo(Info);
172596554Sobrien		}
172696554Sobrien	}
172796554Sobrien	/*
172896554Sobrien	 *	A zero return value indicates success.
172996554Sobrien	 */
173096554Sobrien	return (0);
173165312Smsmith} /* ASR_acquireLct */
173265312Smsmith
173365312Smsmith/*
173465312Smsmith * Initialize a message frame.
173565312Smsmith * We assume that the CDB has already been set up, so all we do here is
173665312Smsmith * generate the Scatter Gather list.
173765312Smsmith */
1738128784Sscottlstatic PI2O_MESSAGE_FRAME
1739128784SscottlASR_init_message(union asr_ccb *ccb, PI2O_MESSAGE_FRAME	Message)
174065312Smsmith{
1741128784Sscottl	PI2O_MESSAGE_FRAME	Message_Ptr;
174296554Sobrien	PI2O_SGE_SIMPLE_ELEMENT sg;
1743128784Sscottl	Asr_softc_t		*sc = (Asr_softc_t *)(ccb->ccb_h.spriv_ptr0);
1744128784Sscottl	vm_size_t		size, len;
174596554Sobrien	caddr_t			v;
174696554Sobrien	U32			MessageSize;
1747128784Sscottl	int			next, span, base, rw;
1748128784Sscottl	int			target = ccb->ccb_h.target_id;
1749128784Sscottl	int			lun = ccb->ccb_h.target_lun;
1750128784Sscottl	int			bus =cam_sim_bus(xpt_path_sim(ccb->ccb_h.path));
1751128784Sscottl	tid_t			TID;
175265312Smsmith
175396554Sobrien	/* We only need to zero out the PRIVATE_SCSI_SCB_EXECUTE_MESSAGE */
1754128812Sscottl	Message_Ptr = (I2O_MESSAGE_FRAME *)Message;
1755128784Sscottl	bzero(Message_Ptr, (sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) -
1756128784Sscottl	      sizeof(I2O_SG_ELEMENT)));
175765312Smsmith
1758128784Sscottl	if ((TID = ASR_getTid (sc, bus, target, lun)) == (tid_t)-1) {
1759128784Sscottl		PI2O_LCT_ENTRY Device;
176065312Smsmith
1761128784Sscottl		TID = 0;
1762128784Sscottl		for (Device = sc->ha_LCT->LCTEntry; Device < (PI2O_LCT_ENTRY)
1763128784Sscottl		    (((U32 *)sc->ha_LCT) + I2O_LCT_getTableSize(sc->ha_LCT));
1764128784Sscottl		    ++Device) {
1765128784Sscottl			if ((Device->le_type != I2O_UNKNOWN)
1766128784Sscottl			 && (Device->le_bus == bus)
1767128784Sscottl			 && (Device->le_target == target)
1768128784Sscottl			 && (Device->le_lun == lun)
1769128784Sscottl			 && (I2O_LCT_ENTRY_getUserTID(Device) == 0xFFF)) {
1770128784Sscottl				TID = I2O_LCT_ENTRY_getLocalTID(Device);
1771128784Sscottl				ASR_setTid(sc, Device->le_bus,
1772128784Sscottl					   Device->le_target, Device->le_lun,
1773128784Sscottl					   TID);
1774128784Sscottl				break;
177596554Sobrien			}
177696554Sobrien		}
177796554Sobrien	}
1778128784Sscottl	if (TID == (tid_t)0) {
1779128784Sscottl		return (NULL);
1780128784Sscottl	}
1781128784Sscottl	I2O_MESSAGE_FRAME_setTargetAddress(Message_Ptr, TID);
1782128784Sscottl	PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setTID(
1783128784Sscottl	    (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr, TID);
178496554Sobrien	I2O_MESSAGE_FRAME_setVersionOffset(Message_Ptr, I2O_VERSION_11 |
178596554Sobrien	  (((sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) - sizeof(I2O_SG_ELEMENT))
178696554Sobrien		/ sizeof(U32)) << 4));
178796554Sobrien	I2O_MESSAGE_FRAME_setMessageSize(Message_Ptr,
178896554Sobrien	  (sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE)
178996554Sobrien	  - sizeof(I2O_SG_ELEMENT)) / sizeof(U32));
179096554Sobrien	I2O_MESSAGE_FRAME_setInitiatorAddress (Message_Ptr, 1);
179196554Sobrien	I2O_MESSAGE_FRAME_setFunction(Message_Ptr, I2O_PRIVATE_MESSAGE);
179296554Sobrien	I2O_PRIVATE_MESSAGE_FRAME_setXFunctionCode (
179396554Sobrien	  (PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr, I2O_SCSI_SCB_EXEC);
179496554Sobrien	PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setSCBFlags (
179596554Sobrien	  (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr,
179696554Sobrien	    I2O_SCB_FLAG_ENABLE_DISCONNECT
179796554Sobrien	  | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG
179896554Sobrien	  | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER);
179996554Sobrien	/*
180096554Sobrien	 * We do not need any (optional byteswapping) method access to
180196554Sobrien	 * the Initiator & Transaction context field.
180296554Sobrien	 */
180396554Sobrien	I2O_MESSAGE_FRAME_setInitiatorContext64(Message, (long)ccb);
180465312Smsmith
180596554Sobrien	I2O_PRIVATE_MESSAGE_FRAME_setOrganizationID(
180696554Sobrien	  (PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr, DPT_ORGANIZATION_ID);
180796554Sobrien	/*
180896554Sobrien	 * copy the cdb over
180996554Sobrien	 */
181096554Sobrien	PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setCDBLength(
1811128786Sscottl	    (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr, ccb->csio.cdb_len);
1812128786Sscottl	bcopy(&(ccb->csio.cdb_io),
1813128786Sscottl	    ((PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr)->CDB,
1814128786Sscottl	    ccb->csio.cdb_len);
181565312Smsmith
181696554Sobrien	/*
181796554Sobrien	 * Given a buffer describing a transfer, set up a scatter/gather map
181896554Sobrien	 * in a ccb to map that SCSI transfer.
181996554Sobrien	 */
182065312Smsmith
182196554Sobrien	rw = (ccb->ccb_h.flags & CAM_DIR_IN) ? 0 : I2O_SGL_FLAGS_DIR;
182265312Smsmith
182396554Sobrien	PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setSCBFlags (
182496554Sobrien	  (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr,
182596554Sobrien	  (ccb->csio.dxfer_len)
182696554Sobrien	    ? ((rw) ? (I2O_SCB_FLAG_XFER_TO_DEVICE
182796554Sobrien		     | I2O_SCB_FLAG_ENABLE_DISCONNECT
182896554Sobrien		     | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG
182996554Sobrien		     | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER)
183096554Sobrien		    : (I2O_SCB_FLAG_XFER_FROM_DEVICE
183196554Sobrien		     | I2O_SCB_FLAG_ENABLE_DISCONNECT
183296554Sobrien		     | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG
183396554Sobrien		     | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER))
183496554Sobrien	    :	      (I2O_SCB_FLAG_ENABLE_DISCONNECT
183596554Sobrien		     | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG
183696554Sobrien		     | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER));
183765312Smsmith
183896554Sobrien	/*
183996554Sobrien	 * Given a transfer described by a `data', fill in the SG list.
184096554Sobrien	 */
184196554Sobrien	sg = &((PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr)->SGL.u.Simple[0];
184265312Smsmith
184396554Sobrien	len = ccb->csio.dxfer_len;
184496554Sobrien	v = ccb->csio.data_ptr;
1845128786Sscottl	KASSERT(ccb->csio.dxfer_len >= 0, ("csio.dxfer_len < 0"));
184696554Sobrien	MessageSize = I2O_MESSAGE_FRAME_getMessageSize(Message_Ptr);
184796554Sobrien	PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setByteCount(
184896554Sobrien	  (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr, len);
184996554Sobrien	while ((len > 0) && (sg < &((PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)
185096554Sobrien	  Message_Ptr)->SGL.u.Simple[SG_SIZE])) {
185196554Sobrien		span = 0;
185296554Sobrien		next = base = KVTOPHYS(v);
185396554Sobrien		I2O_SGE_SIMPLE_ELEMENT_setPhysicalAddress(sg, base);
185465312Smsmith
185596554Sobrien		/* How far can we go contiguously */
185696554Sobrien		while ((len > 0) && (base == next)) {
185796554Sobrien			next = trunc_page(base) + PAGE_SIZE;
185896554Sobrien			size = next - base;
185996554Sobrien			if (size > len) {
186096554Sobrien				size = len;
186196554Sobrien			}
186296554Sobrien			span += size;
186396554Sobrien			v += size;
186496554Sobrien			len -= size;
186596554Sobrien			base = KVTOPHYS(v);
186696554Sobrien		}
186765312Smsmith
186896554Sobrien		I2O_FLAGS_COUNT_setCount(&(sg->FlagsCount), span);
186996554Sobrien		if (len == 0) {
187096554Sobrien			rw |= I2O_SGL_FLAGS_LAST_ELEMENT;
187196554Sobrien		}
187296554Sobrien		I2O_FLAGS_COUNT_setFlags(&(sg->FlagsCount),
187396554Sobrien		  I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT | rw);
187496554Sobrien		++sg;
187596554Sobrien		MessageSize += sizeof(*sg) / sizeof(U32);
187696554Sobrien	}
187796554Sobrien	/* We always do the request sense ... */
187896554Sobrien	if ((span = ccb->csio.sense_len) == 0) {
187996554Sobrien		span = sizeof(ccb->csio.sense_data);
188096554Sobrien	}
188196554Sobrien	SG(sg, 0, I2O_SGL_FLAGS_LAST_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER,
188296554Sobrien	  &(ccb->csio.sense_data), span);
188396554Sobrien	I2O_MESSAGE_FRAME_setMessageSize(Message_Ptr,
188496554Sobrien	  MessageSize + (sizeof(*sg) / sizeof(U32)));
188596554Sobrien	return (Message_Ptr);
188665312Smsmith} /* ASR_init_message */
188765312Smsmith
188865312Smsmith/*
188996554Sobrien *	Reset the adapter.
189065312Smsmith */
1891128784Sscottlstatic U32
1892128784SscottlASR_initOutBound(Asr_softc_t *sc)
189365312Smsmith{
189496554Sobrien	struct initOutBoundMessage {
189596554Sobrien		I2O_EXEC_OUTBOUND_INIT_MESSAGE M;
189696554Sobrien		U32			       R;
1897128812Sscottl	}				Message;
1898128812Sscottl	PI2O_EXEC_OUTBOUND_INIT_MESSAGE	Message_Ptr;
1899128812Sscottl	U32				*volatile Reply_Ptr;
1900128812Sscottl	U32				Old;
190165312Smsmith
190296554Sobrien	/*
190396554Sobrien	 *  Build up our copy of the Message.
190496554Sobrien	 */
1905128812Sscottl	Message_Ptr = (PI2O_EXEC_OUTBOUND_INIT_MESSAGE)ASR_fillMessage(&Message,
190696554Sobrien	  sizeof(I2O_EXEC_OUTBOUND_INIT_MESSAGE));
190796554Sobrien	I2O_MESSAGE_FRAME_setFunction(&(Message_Ptr->StdMessageFrame),
190896554Sobrien	  I2O_EXEC_OUTBOUND_INIT);
190996554Sobrien	I2O_EXEC_OUTBOUND_INIT_MESSAGE_setHostPageFrameSize(Message_Ptr, PAGE_SIZE);
191096554Sobrien	I2O_EXEC_OUTBOUND_INIT_MESSAGE_setOutboundMFrameSize(Message_Ptr,
191196554Sobrien	  sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME));
191296554Sobrien	/*
191396554Sobrien	 *  Reset the Reply Status
191496554Sobrien	 */
191596554Sobrien	*(Reply_Ptr = (U32 *)((char *)Message_Ptr
191696554Sobrien	  + sizeof(I2O_EXEC_OUTBOUND_INIT_MESSAGE))) = 0;
191796554Sobrien	SG (&(Message_Ptr->SGL), 0, I2O_SGL_FLAGS_LAST_ELEMENT, Reply_Ptr,
191896554Sobrien	  sizeof(U32));
191996554Sobrien	/*
192096554Sobrien	 *	Send the Message out
192196554Sobrien	 */
1922155284Sscottl	if ((Old = ASR_initiateCp(sc, (PI2O_MESSAGE_FRAME)Message_Ptr)) !=
1923155284Sscottl	    0xffffffff) {
192496554Sobrien		u_long size, addr;
192565312Smsmith
192696554Sobrien		/*
192796554Sobrien		 *	Wait for a response (Poll).
192896554Sobrien		 */
192996554Sobrien		while (*Reply_Ptr < I2O_EXEC_OUTBOUND_INIT_REJECTED);
193096554Sobrien		/*
193196554Sobrien		 *	Re-enable the interrupts.
193296554Sobrien		 */
1933128944Sscottl		asr_set_intr(sc, Old);
193496554Sobrien		/*
193596554Sobrien		 *	Populate the outbound table.
193696554Sobrien		 */
1937128511Sscottl		if (sc->ha_Msgs == NULL) {
193865312Smsmith
193996554Sobrien			/* Allocate the reply frames */
194096554Sobrien			size = sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)
194196554Sobrien			  * sc->ha_Msgs_Count;
194265312Smsmith
194396554Sobrien			/*
194496554Sobrien			 *	contigmalloc only works reliably at
194596554Sobrien			 * initialization time.
194696554Sobrien			 */
194796554Sobrien			if ((sc->ha_Msgs = (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)
1948111119Simp			  contigmalloc (size, M_DEVBUF, M_WAITOK, 0ul,
1949128511Sscottl			    0xFFFFFFFFul, (u_long)sizeof(U32), 0ul)) != NULL) {
1950128787Sscottl				bzero(sc->ha_Msgs, size);
195196554Sobrien				sc->ha_Msgs_Phys = KVTOPHYS(sc->ha_Msgs);
195296554Sobrien			}
195396554Sobrien		}
195465312Smsmith
195596554Sobrien		/* Initialize the outbound FIFO */
1956128511Sscottl		if (sc->ha_Msgs != NULL)
1957128944Sscottl		for(size = sc->ha_Msgs_Count, addr = sc->ha_Msgs_Phys;
1958128944Sscottl		    size; --size) {
1959128944Sscottl			asr_set_FromFIFO(sc, addr);
196096554Sobrien			addr += sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME);
196196554Sobrien		}
196296554Sobrien		return (*Reply_Ptr);
196396554Sobrien	}
196496554Sobrien	return (0);
196565312Smsmith} /* ASR_initOutBound */
196665312Smsmith
196765312Smsmith/*
196896554Sobrien *	Set the system table
196965312Smsmith */
1970128784Sscottlstatic int
1971128784SscottlASR_setSysTab(Asr_softc_t *sc)
197265312Smsmith{
197396554Sobrien	PI2O_EXEC_SYS_TAB_SET_MESSAGE Message_Ptr;
197496554Sobrien	PI2O_SET_SYSTAB_HEADER	      SystemTable;
1975234503Sdim	Asr_softc_t		    * ha, *next;
197696554Sobrien	PI2O_SGE_SIMPLE_ELEMENT	      sg;
197796554Sobrien	int			      retVal;
197865312Smsmith
197996554Sobrien	if ((SystemTable = (PI2O_SET_SYSTAB_HEADER)malloc (
1980128511Sscottl	  sizeof(I2O_SET_SYSTAB_HEADER), M_TEMP, M_WAITOK | M_ZERO)) == NULL) {
198196554Sobrien		return (ENOMEM);
198296554Sobrien	}
1983234503Sdim	STAILQ_FOREACH(ha, &Asr_softc_list, ha_next) {
198496554Sobrien		++SystemTable->NumberEntries;
198596554Sobrien	}
198696554Sobrien	if ((Message_Ptr = (PI2O_EXEC_SYS_TAB_SET_MESSAGE)malloc (
198796554Sobrien	  sizeof(I2O_EXEC_SYS_TAB_SET_MESSAGE) - sizeof(I2O_SG_ELEMENT)
198896554Sobrien	   + ((3+SystemTable->NumberEntries) * sizeof(I2O_SGE_SIMPLE_ELEMENT)),
1989128511Sscottl	  M_TEMP, M_WAITOK)) == NULL) {
1990128812Sscottl		free(SystemTable, M_TEMP);
199196554Sobrien		return (ENOMEM);
199296554Sobrien	}
1993128908Sscottl	(void)ASR_fillMessage((void *)Message_Ptr,
199496554Sobrien	  sizeof(I2O_EXEC_SYS_TAB_SET_MESSAGE) - sizeof(I2O_SG_ELEMENT)
199596554Sobrien	   + ((3+SystemTable->NumberEntries) * sizeof(I2O_SGE_SIMPLE_ELEMENT)));
199696554Sobrien	I2O_MESSAGE_FRAME_setVersionOffset(&(Message_Ptr->StdMessageFrame),
199796554Sobrien	  (I2O_VERSION_11 +
199896554Sobrien	  (((sizeof(I2O_EXEC_SYS_TAB_SET_MESSAGE) - sizeof(I2O_SG_ELEMENT))
199996554Sobrien			/ sizeof(U32)) << 4)));
200096554Sobrien	I2O_MESSAGE_FRAME_setFunction(&(Message_Ptr->StdMessageFrame),
200196554Sobrien	  I2O_EXEC_SYS_TAB_SET);
200296554Sobrien	/*
200396554Sobrien	 *	Call the LCT table to determine the number of device entries
200496554Sobrien	 * to reserve space for.
200596554Sobrien	 *	since this code is reused in several systems, code efficiency
200696554Sobrien	 * is greater by using a shift operation rather than a divide by
200796554Sobrien	 * sizeof(u_int32_t).
200896554Sobrien	 */
200996554Sobrien	sg = (PI2O_SGE_SIMPLE_ELEMENT)((char *)Message_Ptr
201096554Sobrien	  + ((I2O_MESSAGE_FRAME_getVersionOffset(
201196554Sobrien	      &(Message_Ptr->StdMessageFrame)) & 0xF0) >> 2));
201296554Sobrien	SG(sg, 0, I2O_SGL_FLAGS_DIR, SystemTable, sizeof(I2O_SET_SYSTAB_HEADER));
201396554Sobrien	++sg;
2014234503Sdim	STAILQ_FOREACH_SAFE(ha, &Asr_softc_list, ha_next, next) {
201596554Sobrien		SG(sg, 0,
2016234503Sdim		  ((next)
201796554Sobrien		    ? (I2O_SGL_FLAGS_DIR)
201896554Sobrien		    : (I2O_SGL_FLAGS_DIR | I2O_SGL_FLAGS_END_OF_BUFFER)),
201996554Sobrien		  &(ha->ha_SystemTable), sizeof(ha->ha_SystemTable));
202096554Sobrien		++sg;
202196554Sobrien	}
202296554Sobrien	SG(sg, 0, I2O_SGL_FLAGS_DIR | I2O_SGL_FLAGS_END_OF_BUFFER, NULL, 0);
202396554Sobrien	SG(sg, 1, I2O_SGL_FLAGS_DIR | I2O_SGL_FLAGS_LAST_ELEMENT
202496554Sobrien	    | I2O_SGL_FLAGS_END_OF_BUFFER, NULL, 0);
202596554Sobrien	retVal = ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr);
2026128812Sscottl	free(Message_Ptr, M_TEMP);
2027128812Sscottl	free(SystemTable, M_TEMP);
202896554Sobrien	return (retVal);
202965312Smsmith} /* ASR_setSysTab */
203065312Smsmith
2031128784Sscottlstatic int
2032128784SscottlASR_acquireHrt(Asr_softc_t *sc)
203365312Smsmith{
2034128812Sscottl	I2O_EXEC_HRT_GET_MESSAGE	Message;
2035128812Sscottl	I2O_EXEC_HRT_GET_MESSAGE	*Message_Ptr;
203696554Sobrien	struct {
203796554Sobrien		I2O_HRT	      Header;
203896554Sobrien		I2O_HRT_ENTRY Entry[MAX_CHANNEL];
2039128812Sscottl	}				Hrt;
2040128812Sscottl	u_int8_t			NumberOfEntries;
2041128812Sscottl	PI2O_HRT_ENTRY			Entry;
204265312Smsmith
2043128787Sscottl	bzero(&Hrt, sizeof (Hrt));
2044128812Sscottl	Message_Ptr = (I2O_EXEC_HRT_GET_MESSAGE *)ASR_fillMessage(&Message,
204596554Sobrien	  sizeof(I2O_EXEC_HRT_GET_MESSAGE) - sizeof(I2O_SG_ELEMENT)
204696554Sobrien	  + sizeof(I2O_SGE_SIMPLE_ELEMENT));
204796554Sobrien	I2O_MESSAGE_FRAME_setVersionOffset(&(Message_Ptr->StdMessageFrame),
204896554Sobrien	  (I2O_VERSION_11
204996554Sobrien	  + (((sizeof(I2O_EXEC_HRT_GET_MESSAGE) - sizeof(I2O_SG_ELEMENT))
205096554Sobrien		   / sizeof(U32)) << 4)));
205196554Sobrien	I2O_MESSAGE_FRAME_setFunction (&(Message_Ptr->StdMessageFrame),
205296554Sobrien	  I2O_EXEC_HRT_GET);
205365312Smsmith
205496554Sobrien	/*
205596554Sobrien	 *  Set up the buffers as scatter gather elements.
205696554Sobrien	 */
205796554Sobrien	SG(&(Message_Ptr->SGL), 0,
205896554Sobrien	  I2O_SGL_FLAGS_LAST_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER,
205996554Sobrien	  &Hrt, sizeof(Hrt));
206096554Sobrien	if (ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr) != CAM_REQ_CMP) {
206196554Sobrien		return (ENODEV);
206296554Sobrien	}
206396554Sobrien	if ((NumberOfEntries = I2O_HRT_getNumberEntries(&Hrt.Header))
206496554Sobrien	  > (MAX_CHANNEL + 1)) {
206596554Sobrien		NumberOfEntries = MAX_CHANNEL + 1;
206696554Sobrien	}
206796554Sobrien	for (Entry = Hrt.Header.HRTEntry;
206896554Sobrien	  NumberOfEntries != 0;
206996554Sobrien	  ++Entry, --NumberOfEntries) {
207096554Sobrien		PI2O_LCT_ENTRY Device;
207165312Smsmith
207296554Sobrien		for (Device = sc->ha_LCT->LCTEntry; Device < (PI2O_LCT_ENTRY)
207396554Sobrien		  (((U32 *)sc->ha_LCT)+I2O_LCT_getTableSize(sc->ha_LCT));
207496554Sobrien		  ++Device) {
207596554Sobrien			if (I2O_LCT_ENTRY_getLocalTID(Device)
207696554Sobrien			  == (I2O_HRT_ENTRY_getAdapterID(Entry) & 0xFFF)) {
207796554Sobrien				Device->le_bus = I2O_HRT_ENTRY_getAdapterID(
207896554Sobrien				  Entry) >> 16;
207996554Sobrien				if ((Device->le_bus > sc->ha_MaxBus)
208096554Sobrien				 && (Device->le_bus <= MAX_CHANNEL)) {
208196554Sobrien					sc->ha_MaxBus = Device->le_bus;
208296554Sobrien				}
208396554Sobrien			}
208496554Sobrien		}
208596554Sobrien	}
208696554Sobrien	return (0);
208765312Smsmith} /* ASR_acquireHrt */
208865312Smsmith
208965312Smsmith/*
209096554Sobrien *	Enable the adapter.
209165312Smsmith */
2092128784Sscottlstatic int
2093128784SscottlASR_enableSys(Asr_softc_t *sc)
209465312Smsmith{
2095128812Sscottl	I2O_EXEC_SYS_ENABLE_MESSAGE	Message;
2096128812Sscottl	PI2O_EXEC_SYS_ENABLE_MESSAGE	Message_Ptr;
209765312Smsmith
2098128812Sscottl	Message_Ptr = (PI2O_EXEC_SYS_ENABLE_MESSAGE)ASR_fillMessage(&Message,
209996554Sobrien	  sizeof(I2O_EXEC_SYS_ENABLE_MESSAGE));
210096554Sobrien	I2O_MESSAGE_FRAME_setFunction(&(Message_Ptr->StdMessageFrame),
210196554Sobrien	  I2O_EXEC_SYS_ENABLE);
210296554Sobrien	return (ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr) != 0);
210365312Smsmith} /* ASR_enableSys */
210465312Smsmith
210565312Smsmith/*
210696554Sobrien *	Perform the stages necessary to initialize the adapter
210765312Smsmith */
2108128784Sscottlstatic int
2109128784SscottlASR_init(Asr_softc_t *sc)
211065312Smsmith{
211196554Sobrien	return ((ASR_initOutBound(sc) == 0)
211296554Sobrien	 || (ASR_setSysTab(sc) != CAM_REQ_CMP)
211396554Sobrien	 || (ASR_enableSys(sc) != CAM_REQ_CMP));
211465312Smsmith} /* ASR_init */
211565312Smsmith
211665312Smsmith/*
211796554Sobrien *	Send a Synchronize Cache command to the target device.
211865312Smsmith */
2119128784Sscottlstatic void
2120128784SscottlASR_sync(Asr_softc_t *sc, int bus, int target, int lun)
212165312Smsmith{
2122128784Sscottl	tid_t TID;
212365312Smsmith
212496554Sobrien	/*
212596554Sobrien	 * We will not synchronize the device when there are outstanding
212696554Sobrien	 * commands issued by the OS (this is due to a locked up device,
212796554Sobrien	 * as the OS normally would flush all outstanding commands before
212896554Sobrien	 * issuing a shutdown or an adapter reset).
212996554Sobrien	 */
2130128511Sscottl	if ((sc != NULL)
2131128511Sscottl	 && (LIST_FIRST(&(sc->ha_ccb)) != NULL)
213296554Sobrien	 && ((TID = ASR_getTid (sc, bus, target, lun)) != (tid_t)-1)
213396554Sobrien	 && (TID != (tid_t)0)) {
2134128812Sscottl		PRIVATE_SCSI_SCB_EXECUTE_MESSAGE	Message;
2135128812Sscottl		PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE	Message_Ptr;
213665312Smsmith
2137128812Sscottl		Message_Ptr = (PRIVATE_SCSI_SCB_EXECUTE_MESSAGE *)&Message;
2138128787Sscottl		bzero(Message_Ptr, sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE)
2139128787Sscottl		    - sizeof(I2O_SG_ELEMENT) + sizeof(I2O_SGE_SIMPLE_ELEMENT));
214065312Smsmith
214196554Sobrien		I2O_MESSAGE_FRAME_setVersionOffset(
214296554Sobrien		  (PI2O_MESSAGE_FRAME)Message_Ptr,
214396554Sobrien		  I2O_VERSION_11
214496554Sobrien		    | (((sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE)
214596554Sobrien		    - sizeof(I2O_SG_ELEMENT))
214696554Sobrien			/ sizeof(U32)) << 4));
214796554Sobrien		I2O_MESSAGE_FRAME_setMessageSize(
214896554Sobrien		  (PI2O_MESSAGE_FRAME)Message_Ptr,
214996554Sobrien		  (sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE)
215096554Sobrien		  - sizeof(I2O_SG_ELEMENT))
215196554Sobrien			/ sizeof(U32));
215296554Sobrien		I2O_MESSAGE_FRAME_setInitiatorAddress (
215396554Sobrien		  (PI2O_MESSAGE_FRAME)Message_Ptr, 1);
215496554Sobrien		I2O_MESSAGE_FRAME_setFunction(
215596554Sobrien		  (PI2O_MESSAGE_FRAME)Message_Ptr, I2O_PRIVATE_MESSAGE);
215696554Sobrien		I2O_MESSAGE_FRAME_setTargetAddress(
215796554Sobrien		  (PI2O_MESSAGE_FRAME)Message_Ptr, TID);
215896554Sobrien		I2O_PRIVATE_MESSAGE_FRAME_setXFunctionCode (
215996554Sobrien		  (PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr,
216096554Sobrien		  I2O_SCSI_SCB_EXEC);
216196554Sobrien		PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setTID(Message_Ptr, TID);
216296554Sobrien		PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setSCBFlags (Message_Ptr,
216396554Sobrien		    I2O_SCB_FLAG_ENABLE_DISCONNECT
216496554Sobrien		  | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG
216596554Sobrien		  | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER);
216696554Sobrien		I2O_PRIVATE_MESSAGE_FRAME_setOrganizationID(
216796554Sobrien		  (PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr,
216896554Sobrien		  DPT_ORGANIZATION_ID);
216996554Sobrien		PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setCDBLength(Message_Ptr, 6);
217096554Sobrien		Message_Ptr->CDB[0] = SYNCHRONIZE_CACHE;
217196554Sobrien		Message_Ptr->CDB[1] = (lun << 5);
217265312Smsmith
217396554Sobrien		PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setSCBFlags (Message_Ptr,
217496554Sobrien		  (I2O_SCB_FLAG_XFER_FROM_DEVICE
217596554Sobrien		    | I2O_SCB_FLAG_ENABLE_DISCONNECT
217696554Sobrien		    | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG
217796554Sobrien		    | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER));
217865312Smsmith
217996554Sobrien		(void)ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr);
218065312Smsmith
218196554Sobrien	}
218265312Smsmith}
218365312Smsmith
2184128784Sscottlstatic void
2185128784SscottlASR_synchronize(Asr_softc_t *sc)
218665312Smsmith{
2187128784Sscottl	int bus, target, lun;
218865312Smsmith
218996554Sobrien	for (bus = 0; bus <= sc->ha_MaxBus; ++bus) {
219096554Sobrien		for (target = 0; target <= sc->ha_MaxId; ++target) {
219196554Sobrien			for (lun = 0; lun <= sc->ha_MaxLun; ++lun) {
219296554Sobrien				ASR_sync(sc,bus,target,lun);
219396554Sobrien			}
219496554Sobrien		}
219596554Sobrien	}
219665312Smsmith}
219765312Smsmith
219865312Smsmith/*
219996554Sobrien *	Reset the HBA, targets and BUS.
220096554Sobrien *		Currently this resets *all* the SCSI busses.
220165312Smsmith */
2202128784Sscottlstatic __inline void
2203128784Sscottlasr_hbareset(Asr_softc_t *sc)
220465312Smsmith{
2205128784Sscottl	ASR_synchronize(sc);
2206128784Sscottl	(void)ASR_reset(sc);
220765312Smsmith} /* asr_hbareset */
220865312Smsmith
220965312Smsmith/*
221096554Sobrien *	A reduced copy of the real pci_map_mem, incorporating the MAX_MAP
221165312Smsmith * limit and a reduction in error checking (in the pre 4.0 case).
221265312Smsmith */
2213128784Sscottlstatic int
2214154363Sscottlasr_pci_map_mem(device_t dev, Asr_softc_t *sc)
221565312Smsmith{
2216128784Sscottl	int		rid;
2217128784Sscottl	u_int32_t	p, l, s;
221865312Smsmith
221996554Sobrien	/*
222096554Sobrien	 * I2O specification says we must find first *memory* mapped BAR
222196554Sobrien	 */
2222119690Sjhb	for (rid = 0; rid < 4; rid++) {
2223154363Sscottl		p = pci_read_config(dev, PCIR_BAR(rid), sizeof(p));
222496554Sobrien		if ((p & 1) == 0) {
222596554Sobrien			break;
222696554Sobrien		}
222796554Sobrien	}
222896554Sobrien	/*
222996554Sobrien	 *	Give up?
223096554Sobrien	 */
2231119690Sjhb	if (rid >= 4) {
2232119690Sjhb		rid = 0;
223396554Sobrien	}
2234119690Sjhb	rid = PCIR_BAR(rid);
2235154363Sscottl	p = pci_read_config(dev, rid, sizeof(p));
2236154363Sscottl	pci_write_config(dev, rid, -1, sizeof(p));
2237154363Sscottl	l = 0 - (pci_read_config(dev, rid, sizeof(l)) & ~15);
2238154363Sscottl	pci_write_config(dev, rid, p, sizeof(p));
223996554Sobrien	if (l > MAX_MAP) {
224096554Sobrien		l = MAX_MAP;
224196554Sobrien	}
224296554Sobrien	/*
224396554Sobrien	 * The 2005S Zero Channel RAID solution is not a perfect PCI
224496554Sobrien	 * citizen. It asks for 4MB on BAR0, and 0MB on BAR1, once
224596554Sobrien	 * enabled it rewrites the size of BAR0 to 2MB, sets BAR1 to
224696554Sobrien	 * BAR0+2MB and sets it's size to 2MB. The IOP registers are
224796554Sobrien	 * accessible via BAR0, the messaging registers are accessible
224896554Sobrien	 * via BAR1. If the subdevice code is 50 to 59 decimal.
224996554Sobrien	 */
2250154363Sscottl	s = pci_read_config(dev, PCIR_DEVVENDOR, sizeof(s));
225196554Sobrien	if (s != 0xA5111044) {
2252154363Sscottl		s = pci_read_config(dev, PCIR_SUBVEND_0, sizeof(s));
225396554Sobrien		if ((((ADPTDOMINATOR_SUB_ID_START ^ s) & 0xF000FFFF) == 0)
225496554Sobrien		 && (ADPTDOMINATOR_SUB_ID_START <= s)
225596554Sobrien		 && (s <= ADPTDOMINATOR_SUB_ID_END)) {
225696554Sobrien			l = MAX_MAP; /* Conjoined BAR Raptor Daptor */
225796554Sobrien		}
225896554Sobrien	}
225996554Sobrien	p &= ~15;
2260154363Sscottl	sc->ha_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
226196554Sobrien	  p, p + l, l, RF_ACTIVE);
2262128511Sscottl	if (sc->ha_mem_res == NULL) {
226396554Sobrien		return (0);
226496554Sobrien	}
2265128944Sscottl	sc->ha_Base = rman_get_start(sc->ha_mem_res);
2266128944Sscottl	sc->ha_i2o_bhandle = rman_get_bushandle(sc->ha_mem_res);
2267128944Sscottl	sc->ha_i2o_btag = rman_get_bustag(sc->ha_mem_res);
2268128944Sscottl
226996554Sobrien	if (s == 0xA5111044) { /* Split BAR Raptor Daptor */
2270119690Sjhb		if ((rid += sizeof(u_int32_t)) >= PCIR_BAR(4)) {
227196554Sobrien			return (0);
227296554Sobrien		}
2273154363Sscottl		p = pci_read_config(dev, rid, sizeof(p));
2274154363Sscottl		pci_write_config(dev, rid, -1, sizeof(p));
2275154363Sscottl		l = 0 - (pci_read_config(dev, rid, sizeof(l)) & ~15);
2276154363Sscottl		pci_write_config(dev, rid, p, sizeof(p));
227796554Sobrien		if (l > MAX_MAP) {
227896554Sobrien			l = MAX_MAP;
227996554Sobrien		}
228096554Sobrien		p &= ~15;
2281154363Sscottl		sc->ha_mes_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
228296554Sobrien		  p, p + l, l, RF_ACTIVE);
2283128511Sscottl		if (sc->ha_mes_res == NULL) {
228496554Sobrien			return (0);
228596554Sobrien		}
2286128944Sscottl		sc->ha_frame_bhandle = rman_get_bushandle(sc->ha_mes_res);
2287128944Sscottl		sc->ha_frame_btag = rman_get_bustag(sc->ha_mes_res);
228896554Sobrien	} else {
2289128944Sscottl		sc->ha_frame_bhandle = sc->ha_i2o_bhandle;
2290128944Sscottl		sc->ha_frame_btag = sc->ha_i2o_btag;
229196554Sobrien	}
229296554Sobrien	return (1);
229365312Smsmith} /* asr_pci_map_mem */
229465312Smsmith
229565312Smsmith/*
229696554Sobrien *	A simplified copy of the real pci_map_int with additional
229765312Smsmith * registration requirements.
229865312Smsmith */
2299128784Sscottlstatic int
2300154363Sscottlasr_pci_map_int(device_t dev, Asr_softc_t *sc)
230165312Smsmith{
2302128784Sscottl	int rid = 0;
230365312Smsmith
2304154363Sscottl	sc->ha_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
2305127135Snjl	  RF_ACTIVE | RF_SHAREABLE);
2306128511Sscottl	if (sc->ha_irq_res == NULL) {
230796554Sobrien		return (0);
230896554Sobrien	}
2309154363Sscottl	if (bus_setup_intr(dev, sc->ha_irq_res, INTR_TYPE_CAM | INTR_ENTROPY,
2310166901Spiso	  NULL, (driver_intr_t *)asr_intr, (void *)sc, &(sc->ha_intr))) {
231196554Sobrien		return (0);
231296554Sobrien	}
2313154363Sscottl	sc->ha_irq = pci_read_config(dev, PCIR_INTLINE, sizeof(char));
231496554Sobrien	return (1);
231565312Smsmith} /* asr_pci_map_int */
231665312Smsmith
2317155286Sscottlstatic void
2318155286Sscottlasr_status_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2319155286Sscottl{
2320155286Sscottl	Asr_softc_t *sc;
2321155286Sscottl
2322155286Sscottl	if (error)
2323155286Sscottl		return;
2324155286Sscottl
2325155286Sscottl	sc = (Asr_softc_t *)arg;
2326155286Sscottl
2327155286Sscottl	/* XXX
2328155286Sscottl	 * The status word can be at a 64-bit address, but the existing
2329155286Sscottl	 * accessor macros simply cannot manipulate 64-bit addresses.
2330155286Sscottl	 */
2331155307Sscottl	sc->ha_status_phys = (u_int32_t)segs[0].ds_addr +
2332155307Sscottl	    offsetof(struct Asr_status_mem, status);
2333155307Sscottl	sc->ha_rstatus_phys = (u_int32_t)segs[0].ds_addr +
2334155307Sscottl	    offsetof(struct Asr_status_mem, rstatus);
2335155286Sscottl}
2336155286Sscottl
2337155286Sscottlstatic int
2338155286Sscottlasr_alloc_dma(Asr_softc_t *sc)
2339155286Sscottl{
2340155286Sscottl	device_t dev;
2341155286Sscottl
2342155286Sscottl	dev = sc->ha_dev;
2343155286Sscottl
2344232854Sscottl	if (bus_dma_tag_create(bus_get_dma_tag(dev),	/* PCI parent */
2345155286Sscottl			       1, 0,			/* algnmnt, boundary */
2346155286Sscottl			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
2347155286Sscottl			       BUS_SPACE_MAXADDR,	/* highaddr */
2348155286Sscottl			       NULL, NULL,		/* filter, filterarg */
2349155286Sscottl			       BUS_SPACE_MAXSIZE_32BIT, /* maxsize */
2350155286Sscottl			       BUS_SPACE_UNRESTRICTED,	/* nsegments */
2351155286Sscottl			       BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
2352155286Sscottl			       0,			/* flags */
2353155286Sscottl			       NULL, NULL,		/* lockfunc, lockarg */
2354155286Sscottl			       &sc->ha_parent_dmat)) {
2355155286Sscottl		device_printf(dev, "Cannot allocate parent DMA tag\n");
2356155286Sscottl		return (ENOMEM);
2357155286Sscottl	}
2358155286Sscottl
2359155286Sscottl	if (bus_dma_tag_create(sc->ha_parent_dmat,	/* parent */
2360155286Sscottl			       1, 0,			/* algnmnt, boundary */
2361155286Sscottl			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
2362155286Sscottl			       BUS_SPACE_MAXADDR,	/* highaddr */
2363155286Sscottl			       NULL, NULL,		/* filter, filterarg */
2364155307Sscottl			       sizeof(sc->ha_statusmem),/* maxsize */
2365155286Sscottl			       1,			/* nsegments */
2366155307Sscottl			       sizeof(sc->ha_statusmem),/* maxsegsize */
2367155286Sscottl			       0,			/* flags */
2368155286Sscottl			       NULL, NULL,		/* lockfunc, lockarg */
2369155307Sscottl			       &sc->ha_statusmem_dmat)) {
2370155286Sscottl		device_printf(dev, "Cannot allocate status DMA tag\n");
2371155286Sscottl		bus_dma_tag_destroy(sc->ha_parent_dmat);
2372155286Sscottl		return (ENOMEM);
2373155286Sscottl	}
2374155286Sscottl
2375155307Sscottl	if (bus_dmamem_alloc(sc->ha_statusmem_dmat, (void **)&sc->ha_statusmem,
2376155307Sscottl	    BUS_DMA_NOWAIT, &sc->ha_statusmem_dmamap)) {
2377155286Sscottl		device_printf(dev, "Cannot allocate status memory\n");
2378155307Sscottl		bus_dma_tag_destroy(sc->ha_statusmem_dmat);
2379155286Sscottl		bus_dma_tag_destroy(sc->ha_parent_dmat);
2380155286Sscottl		return (ENOMEM);
2381155286Sscottl	}
2382155307Sscottl	(void)bus_dmamap_load(sc->ha_statusmem_dmat, sc->ha_statusmem_dmamap,
2383155307Sscottl	    sc->ha_statusmem, sizeof(sc->ha_statusmem), asr_status_cb, sc, 0);
2384155286Sscottl
2385155286Sscottl	return (0);
2386155286Sscottl}
2387155286Sscottl
2388155286Sscottlstatic void
2389155286Sscottlasr_release_dma(Asr_softc_t *sc)
2390155286Sscottl{
2391155286Sscottl
2392155307Sscottl	if (sc->ha_rstatus_phys != 0)
2393155307Sscottl		bus_dmamap_unload(sc->ha_statusmem_dmat,
2394155307Sscottl		    sc->ha_statusmem_dmamap);
2395155307Sscottl	if (sc->ha_statusmem != NULL)
2396155307Sscottl		bus_dmamem_free(sc->ha_statusmem_dmat, sc->ha_statusmem,
2397155307Sscottl		    sc->ha_statusmem_dmamap);
2398155307Sscottl	if (sc->ha_statusmem_dmat != NULL)
2399155307Sscottl		bus_dma_tag_destroy(sc->ha_statusmem_dmat);
2400155286Sscottl	if (sc->ha_parent_dmat != NULL)
2401155286Sscottl		bus_dma_tag_destroy(sc->ha_parent_dmat);
2402155286Sscottl}
2403155286Sscottl
240465312Smsmith/*
240596554Sobrien *	Attach the devices, and virtual devices to the driver list.
240665312Smsmith */
2407128791Sscottlstatic int
2408154363Sscottlasr_attach(device_t dev)
240965312Smsmith{
2410128793Sscottl	PI2O_EXEC_STATUS_GET_REPLY status;
2411128793Sscottl	PI2O_LCT_ENTRY		 Device;
2412234503Sdim	Asr_softc_t		 *sc;
2413128784Sscottl	struct scsi_inquiry_data *iq;
2414154363Sscottl	int			 bus, size, unit;
2415155286Sscottl	int			 error;
241665312Smsmith
2417154363Sscottl	sc = device_get_softc(dev);
2418154363Sscottl	unit = device_get_unit(dev);
2419155286Sscottl	sc->ha_dev = dev;
2420154363Sscottl
2421234503Sdim	if (STAILQ_EMPTY(&Asr_softc_list)) {
242296554Sobrien		/*
242396554Sobrien		 *	Fixup the OS revision as saved in the dptsig for the
242496554Sobrien		 *	engine (dptioctl.h) to pick up.
242596554Sobrien		 */
2426128786Sscottl		bcopy(osrelease, &ASR_sig.dsDescription[16], 5);
242796554Sobrien	}
242896554Sobrien	/*
242996554Sobrien	 *	Initialize the software structure
243096554Sobrien	 */
243196554Sobrien	LIST_INIT(&(sc->ha_ccb));
243296554Sobrien	/* Link us into the HA list */
2433234503Sdim	STAILQ_INSERT_TAIL(&Asr_softc_list, sc, ha_next);
2434128793Sscottl
2435128793Sscottl	/*
2436128793Sscottl	 *	This is the real McCoy!
2437128793Sscottl	 */
2438154363Sscottl	if (!asr_pci_map_mem(dev, sc)) {
2439154363Sscottl		device_printf(dev, "could not map memory\n");
2440128793Sscottl		return(ENXIO);
2441128793Sscottl	}
2442128793Sscottl	/* Enable if not formerly enabled */
2443254263Sscottl	pci_enable_busmaster(dev);
2444154364Sscottl
2445154364Sscottl	sc->ha_pciBusNum = pci_get_bus(dev);
2446154364Sscottl	sc->ha_pciDeviceNum = (pci_get_slot(dev) << 3) | pci_get_function(dev);
2447154364Sscottl
2448155286Sscottl	if ((error = asr_alloc_dma(sc)) != 0)
2449155286Sscottl		return (error);
2450155286Sscottl
2451128793Sscottl	/* Check if the device is there? */
2452155274Sscottl	if (ASR_resetIOP(sc) == 0) {
2453155274Sscottl		device_printf(dev, "Cannot reset adapter\n");
2454155286Sscottl		asr_release_dma(sc);
2455155274Sscottl		return (EIO);
2456155274Sscottl	}
2457155307Sscottl	status = &sc->ha_statusmem->status;
2458155307Sscottl	if (ASR_getStatus(sc) == NULL) {
2459154363Sscottl		device_printf(dev, "could not initialize hardware\n");
2460155286Sscottl		asr_release_dma(sc);
2461155274Sscottl		return(ENODEV);
2462128793Sscottl	}
2463128793Sscottl	sc->ha_SystemTable.OrganizationID = status->OrganizationID;
2464128793Sscottl	sc->ha_SystemTable.IOP_ID = status->IOP_ID;
2465128793Sscottl	sc->ha_SystemTable.I2oVersion = status->I2oVersion;
2466128793Sscottl	sc->ha_SystemTable.IopState = status->IopState;
2467128793Sscottl	sc->ha_SystemTable.MessengerType = status->MessengerType;
2468128793Sscottl	sc->ha_SystemTable.InboundMessageFrameSize = status->InboundMFrameSize;
2469128793Sscottl	sc->ha_SystemTable.MessengerInfo.InboundMessagePortAddressLow =
2470128944Sscottl	    (U32)(sc->ha_Base + I2O_REG_TOFIFO);	/* XXX 64-bit */
247165312Smsmith
2472154363Sscottl	if (!asr_pci_map_int(dev, (void *)sc)) {
2473154363Sscottl		device_printf(dev, "could not map interrupt\n");
2474155286Sscottl		asr_release_dma(sc);
2475128793Sscottl		return(ENXIO);
2476128793Sscottl	}
247765312Smsmith
2478128793Sscottl	/* Adjust the maximim inbound count */
2479128793Sscottl	if (((sc->ha_QueueSize =
2480128793Sscottl	    I2O_EXEC_STATUS_GET_REPLY_getMaxInboundMFrames(status)) >
2481128793Sscottl	    MAX_INBOUND) || (sc->ha_QueueSize == 0)) {
2482128793Sscottl		sc->ha_QueueSize = MAX_INBOUND;
2483128793Sscottl	}
248465312Smsmith
2485128793Sscottl	/* Adjust the maximum outbound count */
2486128793Sscottl	if (((sc->ha_Msgs_Count =
2487128793Sscottl	    I2O_EXEC_STATUS_GET_REPLY_getMaxOutboundMFrames(status)) >
2488128793Sscottl	    MAX_OUTBOUND) || (sc->ha_Msgs_Count == 0)) {
2489128793Sscottl		sc->ha_Msgs_Count = MAX_OUTBOUND;
2490128793Sscottl	}
2491128793Sscottl	if (sc->ha_Msgs_Count > sc->ha_QueueSize) {
2492128793Sscottl		sc->ha_Msgs_Count = sc->ha_QueueSize;
2493128793Sscottl	}
249465312Smsmith
2495128793Sscottl	/* Adjust the maximum SG size to adapter */
2496128793Sscottl	if ((size = (I2O_EXEC_STATUS_GET_REPLY_getInboundMFrameSize(status) <<
2497128793Sscottl	    2)) > MAX_INBOUND_SIZE) {
2498128793Sscottl		size = MAX_INBOUND_SIZE;
249996554Sobrien	}
2500128793Sscottl	sc->ha_SgSize = (size - sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE)
2501128793Sscottl	  + sizeof(I2O_SG_ELEMENT)) / sizeof(I2O_SGE_SIMPLE_ELEMENT);
250265312Smsmith
250396554Sobrien	/*
250496554Sobrien	 *	Only do a bus/HBA reset on the first time through. On this
250596554Sobrien	 * first time through, we do not send a flush to the devices.
250696554Sobrien	 */
250796554Sobrien	if (ASR_init(sc) == 0) {
250896554Sobrien		struct BufferInfo {
250996554Sobrien			I2O_PARAM_RESULTS_LIST_HEADER	    Header;
251096554Sobrien			I2O_PARAM_READ_OPERATION_RESULT	    Read;
251196554Sobrien			I2O_DPT_EXEC_IOP_BUFFERS_SCALAR	    Info;
2512128812Sscottl		} Buffer;
251396554Sobrien		PI2O_DPT_EXEC_IOP_BUFFERS_SCALAR Info;
2514128535Sscottl#define FW_DEBUG_BLED_OFFSET 8
251565312Smsmith
251696554Sobrien		if ((Info = (PI2O_DPT_EXEC_IOP_BUFFERS_SCALAR)
2517128944Sscottl		    ASR_getParams(sc, 0, I2O_DPT_EXEC_IOP_BUFFERS_GROUP_NO,
2518128812Sscottl		    &Buffer, sizeof(struct BufferInfo))) != NULL) {
2519128944Sscottl			sc->ha_blinkLED = FW_DEBUG_BLED_OFFSET +
2520128944Sscottl			    I2O_DPT_EXEC_IOP_BUFFERS_SCALAR_getSerialOutputOffset(Info);
252196554Sobrien		}
252296554Sobrien		if (ASR_acquireLct(sc) == 0) {
252396554Sobrien			(void)ASR_acquireHrt(sc);
252496554Sobrien		}
252596554Sobrien	} else {
2526154363Sscottl		device_printf(dev, "failed to initialize\n");
2527155286Sscottl		asr_release_dma(sc);
2528128791Sscottl		return(ENXIO);
252996554Sobrien	}
253096554Sobrien	/*
253196554Sobrien	 *	Add in additional probe responses for more channels. We
253296554Sobrien	 * are reusing the variable `target' for a channel loop counter.
253396554Sobrien	 * Done here because of we need both the acquireLct and
253496554Sobrien	 * acquireHrt data.
253596554Sobrien	 */
2536128793Sscottl	for (Device = sc->ha_LCT->LCTEntry; Device < (PI2O_LCT_ENTRY)
2537128793Sscottl	    (((U32 *)sc->ha_LCT)+I2O_LCT_getTableSize(sc->ha_LCT)); ++Device) {
2538128793Sscottl		if (Device->le_type == I2O_UNKNOWN) {
2539128793Sscottl			continue;
2540128793Sscottl		}
2541128793Sscottl		if (I2O_LCT_ENTRY_getUserTID(Device) == 0xFFF) {
2542128793Sscottl			if (Device->le_target > sc->ha_MaxId) {
2543128793Sscottl				sc->ha_MaxId = Device->le_target;
254496554Sobrien			}
2545128793Sscottl			if (Device->le_lun > sc->ha_MaxLun) {
2546128793Sscottl				sc->ha_MaxLun = Device->le_lun;
254796554Sobrien			}
254896554Sobrien		}
2549128793Sscottl		if (((Device->le_type & I2O_PORT) != 0)
2550128793Sscottl		 && (Device->le_bus <= MAX_CHANNEL)) {
2551128793Sscottl			/* Do not increase MaxId for efficiency */
2552128793Sscottl			sc->ha_adapter_target[Device->le_bus] =
2553128793Sscottl			    Device->le_target;
2554128793Sscottl		}
255596554Sobrien	}
255665312Smsmith
255796554Sobrien	/*
255896554Sobrien	 *	Print the HBA model number as inquired from the card.
255996554Sobrien	 */
256065312Smsmith
2561154363Sscottl	device_printf(dev, " ");
256265312Smsmith
2563128793Sscottl	if ((iq = (struct scsi_inquiry_data *)malloc(
2564128793Sscottl	    sizeof(struct scsi_inquiry_data), M_TEMP, M_WAITOK | M_ZERO)) !=
2565128793Sscottl	    NULL) {
2566128812Sscottl		PRIVATE_SCSI_SCB_EXECUTE_MESSAGE	Message;
2567128812Sscottl		PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE	Message_Ptr;
2568128812Sscottl		int					posted = 0;
256965312Smsmith
2570128812Sscottl		Message_Ptr = (PRIVATE_SCSI_SCB_EXECUTE_MESSAGE *)&Message;
2571128787Sscottl		bzero(Message_Ptr, sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) -
2572128787Sscottl		    sizeof(I2O_SG_ELEMENT) + sizeof(I2O_SGE_SIMPLE_ELEMENT));
257365312Smsmith
257496554Sobrien		I2O_MESSAGE_FRAME_setVersionOffset(
2575128787Sscottl		    (PI2O_MESSAGE_FRAME)Message_Ptr, I2O_VERSION_11 |
2576128787Sscottl		    (((sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE)
2577128787Sscottl		    - sizeof(I2O_SG_ELEMENT)) / sizeof(U32)) << 4));
257896554Sobrien		I2O_MESSAGE_FRAME_setMessageSize(
2579128787Sscottl		    (PI2O_MESSAGE_FRAME)Message_Ptr,
2580128787Sscottl		    (sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) -
2581128787Sscottl		    sizeof(I2O_SG_ELEMENT) + sizeof(I2O_SGE_SIMPLE_ELEMENT)) /
2582128787Sscottl		    sizeof(U32));
2583128787Sscottl		I2O_MESSAGE_FRAME_setInitiatorAddress(
2584128787Sscottl		    (PI2O_MESSAGE_FRAME)Message_Ptr, 1);
258596554Sobrien		I2O_MESSAGE_FRAME_setFunction(
2586128787Sscottl		    (PI2O_MESSAGE_FRAME)Message_Ptr, I2O_PRIVATE_MESSAGE);
2587128787Sscottl		I2O_PRIVATE_MESSAGE_FRAME_setXFunctionCode(
2588128787Sscottl		    (PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr, I2O_SCSI_SCB_EXEC);
258996554Sobrien		PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setSCBFlags (Message_Ptr,
259096554Sobrien		    I2O_SCB_FLAG_ENABLE_DISCONNECT
259196554Sobrien		  | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG
259296554Sobrien		  | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER);
259396554Sobrien		PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setInterpret(Message_Ptr, 1);
259496554Sobrien		I2O_PRIVATE_MESSAGE_FRAME_setOrganizationID(
2595128787Sscottl		    (PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr,
2596128787Sscottl		    DPT_ORGANIZATION_ID);
259796554Sobrien		PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setCDBLength(Message_Ptr, 6);
259896554Sobrien		Message_Ptr->CDB[0] = INQUIRY;
2599128793Sscottl		Message_Ptr->CDB[4] =
2600128793Sscottl		    (unsigned char)sizeof(struct scsi_inquiry_data);
260196554Sobrien		if (Message_Ptr->CDB[4] == 0) {
260296554Sobrien			Message_Ptr->CDB[4] = 255;
260396554Sobrien		}
260465312Smsmith
260596554Sobrien		PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setSCBFlags (Message_Ptr,
260696554Sobrien		  (I2O_SCB_FLAG_XFER_FROM_DEVICE
260796554Sobrien		    | I2O_SCB_FLAG_ENABLE_DISCONNECT
260896554Sobrien		    | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG
260996554Sobrien		    | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER));
261065312Smsmith
261196554Sobrien		PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setByteCount(
261296554Sobrien		  (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr,
261396554Sobrien		  sizeof(struct scsi_inquiry_data));
261496554Sobrien		SG(&(Message_Ptr->SGL), 0,
261596554Sobrien		  I2O_SGL_FLAGS_LAST_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER,
261696554Sobrien		  iq, sizeof(struct scsi_inquiry_data));
261796554Sobrien		(void)ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr);
261865312Smsmith
261996554Sobrien		if (iq->vendor[0] && (iq->vendor[0] != ' ')) {
262096554Sobrien			printf (" ");
262196554Sobrien			ASR_prstring (iq->vendor, 8);
262296554Sobrien			++posted;
262396554Sobrien		}
262496554Sobrien		if (iq->product[0] && (iq->product[0] != ' ')) {
262596554Sobrien			printf (" ");
262696554Sobrien			ASR_prstring (iq->product, 16);
262796554Sobrien			++posted;
262896554Sobrien		}
262996554Sobrien		if (iq->revision[0] && (iq->revision[0] != ' ')) {
263096554Sobrien			printf (" FW Rev. ");
263196554Sobrien			ASR_prstring (iq->revision, 4);
263296554Sobrien			++posted;
263396554Sobrien		}
2634128812Sscottl		free(iq, M_TEMP);
263596554Sobrien		if (posted) {
263696554Sobrien			printf (",");
263796554Sobrien		}
263896554Sobrien	}
263996554Sobrien	printf (" %d channel, %d CCBs, Protocol I2O\n", sc->ha_MaxBus + 1,
264096554Sobrien	  (sc->ha_QueueSize > MAX_INBOUND) ? MAX_INBOUND : sc->ha_QueueSize);
264165312Smsmith
2642128793Sscottl	for (bus = 0; bus <= sc->ha_MaxBus; ++bus) {
2643128793Sscottl		struct cam_devq	  * devq;
2644128793Sscottl		int		    QueueSize = sc->ha_QueueSize;
264565312Smsmith
2646128793Sscottl		if (QueueSize > MAX_INBOUND) {
2647128793Sscottl			QueueSize = MAX_INBOUND;
264896554Sobrien		}
264965312Smsmith
2650128793Sscottl		/*
2651128793Sscottl		 *	Create the device queue for our SIM(s).
2652128793Sscottl		 */
2653128793Sscottl		if ((devq = cam_simq_alloc(QueueSize)) == NULL) {
2654128793Sscottl			continue;
2655128793Sscottl		}
265665312Smsmith
2657128793Sscottl		/*
2658128793Sscottl		 *	Construct our first channel SIM entry
2659128793Sscottl		 */
2660128793Sscottl		sc->ha_sim[bus] = cam_sim_alloc(asr_action, asr_poll, "asr", sc,
2661168752Sscottl						unit, &Giant,
2662168752Sscottl						1, QueueSize, devq);
2663128793Sscottl		if (sc->ha_sim[bus] == NULL) {
2664128793Sscottl			continue;
2665128793Sscottl		}
266665312Smsmith
2667170872Sscottl		if (xpt_bus_register(sc->ha_sim[bus], dev, bus) != CAM_SUCCESS){
2668128793Sscottl			cam_sim_free(sc->ha_sim[bus],
2669128793Sscottl			  /*free_devq*/TRUE);
2670128793Sscottl			sc->ha_sim[bus] = NULL;
2671128793Sscottl			continue;
2672128793Sscottl		}
267365312Smsmith
2674128793Sscottl		if (xpt_create_path(&(sc->ha_path[bus]), /*periph*/NULL,
2675128793Sscottl		    cam_sim_path(sc->ha_sim[bus]), CAM_TARGET_WILDCARD,
2676128793Sscottl		    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
2677128793Sscottl			xpt_bus_deregister( cam_sim_path(sc->ha_sim[bus]));
2678128793Sscottl			cam_sim_free(sc->ha_sim[bus], /*free_devq*/TRUE);
2679128793Sscottl			sc->ha_sim[bus] = NULL;
2680128793Sscottl			continue;
268196554Sobrien		}
268296554Sobrien	}
2683154365Sscottl
268496554Sobrien	/*
268596554Sobrien	 *	Generate the device node information
268696554Sobrien	 */
2687128792Sscottl	sc->ha_devt = make_dev(&asr_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640,
2688128807Sscottl			       "asr%d", unit);
2689145658Sscottl	if (sc->ha_devt != NULL)
2690145658Sscottl		(void)make_dev_alias(sc->ha_devt, "rdpti%d", unit);
2691128792Sscottl	sc->ha_devt->si_drv1 = sc;
2692128791Sscottl	return(0);
269365312Smsmith} /* asr_attach */
269465312Smsmith
2695128784Sscottlstatic void
2696128784Sscottlasr_poll(struct cam_sim *sim)
269765312Smsmith{
269896554Sobrien	asr_intr(cam_sim_softc(sim));
269965312Smsmith} /* asr_poll */
270065312Smsmith
2701128784Sscottlstatic void
2702128784Sscottlasr_action(struct cam_sim *sim, union ccb  *ccb)
270365312Smsmith{
2704128784Sscottl	struct Asr_softc *sc;
270565312Smsmith
2706128786Sscottl	debug_asr_printf("asr_action(%lx,%lx{%x})\n", (u_long)sim, (u_long)ccb,
2707128786Sscottl			 ccb->ccb_h.func_code);
270865312Smsmith
270996554Sobrien	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("asr_action\n"));
271065312Smsmith
271196554Sobrien	ccb->ccb_h.spriv_ptr0 = sc = (struct Asr_softc *)cam_sim_softc(sim);
271265312Smsmith
2713234503Sdim	switch ((int)ccb->ccb_h.func_code) {
271465312Smsmith
271596554Sobrien	/* Common cases first */
271696554Sobrien	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
271796554Sobrien	{
271896554Sobrien		struct Message {
271996554Sobrien			char M[MAX_INBOUND_SIZE];
2720128812Sscottl		} Message;
272196554Sobrien		PI2O_MESSAGE_FRAME   Message_Ptr;
272265312Smsmith
272396554Sobrien		/* Reject incoming commands while we are resetting the card */
272496554Sobrien		if (sc->ha_in_reset != HA_OPERATIONAL) {
272596554Sobrien			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
272696554Sobrien			if (sc->ha_in_reset >= HA_OFF_LINE) {
272796554Sobrien				/* HBA is now off-line */
272896554Sobrien				ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR;
272996554Sobrien			} else {
273096554Sobrien				/* HBA currently resetting, try again later. */
273196554Sobrien				ccb->ccb_h.status |= CAM_REQUEUE_REQ;
273296554Sobrien			}
273396554Sobrien			debug_asr_cmd_printf (" e\n");
273496554Sobrien			xpt_done(ccb);
273596554Sobrien			debug_asr_cmd_printf (" q\n");
273696554Sobrien			break;
273796554Sobrien		}
273896554Sobrien		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
273996554Sobrien			printf(
274096554Sobrien			  "asr%d WARNING: scsi_cmd(%x) already done on b%dt%du%d\n",
274196554Sobrien			  cam_sim_unit(xpt_path_sim(ccb->ccb_h.path)),
274296554Sobrien			  ccb->csio.cdb_io.cdb_bytes[0],
274396554Sobrien			  cam_sim_bus(sim),
274496554Sobrien			  ccb->ccb_h.target_id,
274596554Sobrien			  ccb->ccb_h.target_lun);
274696554Sobrien		}
2747128786Sscottl		debug_asr_cmd_printf("(%d,%d,%d,%d)", cam_sim_unit(sim),
2748128786Sscottl				     cam_sim_bus(sim), ccb->ccb_h.target_id,
2749128786Sscottl				     ccb->ccb_h.target_lun);
2750128786Sscottl		debug_asr_dump_ccb(ccb);
275165312Smsmith
2752128812Sscottl		if ((Message_Ptr = ASR_init_message((union asr_ccb *)ccb,
2753128812Sscottl		  (PI2O_MESSAGE_FRAME)&Message)) != NULL) {
275496554Sobrien			debug_asr_cmd2_printf ("TID=%x:\n",
275596554Sobrien			  PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_getTID(
275696554Sobrien			    (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr));
275796554Sobrien			debug_asr_cmd2_dump_message(Message_Ptr);
275896554Sobrien			debug_asr_cmd1_printf (" q");
275965312Smsmith
276096554Sobrien			if (ASR_queue (sc, Message_Ptr) == EMPTY_QUEUE) {
276196554Sobrien				ccb->ccb_h.status &= ~CAM_STATUS_MASK;
276296554Sobrien				ccb->ccb_h.status |= CAM_REQUEUE_REQ;
276396554Sobrien				debug_asr_cmd_printf (" E\n");
276496554Sobrien				xpt_done(ccb);
276596554Sobrien			}
2766128786Sscottl			debug_asr_cmd_printf(" Q\n");
276796554Sobrien			break;
276896554Sobrien		}
276996554Sobrien		/*
277096554Sobrien		 *	We will get here if there is no valid TID for the device
277196554Sobrien		 * referenced in the scsi command packet.
277296554Sobrien		 */
277396554Sobrien		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
277496554Sobrien		ccb->ccb_h.status |= CAM_SEL_TIMEOUT;
277596554Sobrien		debug_asr_cmd_printf (" B\n");
277696554Sobrien		xpt_done(ccb);
277796554Sobrien		break;
277896554Sobrien	}
277965312Smsmith
278096554Sobrien	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
278196554Sobrien		/* Rese HBA device ... */
278296554Sobrien		asr_hbareset (sc);
278396554Sobrien		ccb->ccb_h.status = CAM_REQ_CMP;
278496554Sobrien		xpt_done(ccb);
278596554Sobrien		break;
278665312Smsmith
2787128535Sscottl#if (defined(REPORT_LUNS))
278896554Sobrien	case REPORT_LUNS:
2789128535Sscottl#endif
279096554Sobrien	case XPT_ABORT:			/* Abort the specified CCB */
279196554Sobrien		/* XXX Implement */
279296554Sobrien		ccb->ccb_h.status = CAM_REQ_INVALID;
279396554Sobrien		xpt_done(ccb);
279496554Sobrien		break;
279565312Smsmith
279696554Sobrien	case XPT_SET_TRAN_SETTINGS:
279796554Sobrien		/* XXX Implement */
279896554Sobrien		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
279996554Sobrien		xpt_done(ccb);
280096554Sobrien		break;
280165312Smsmith
280296554Sobrien	case XPT_GET_TRAN_SETTINGS:
280396554Sobrien	/* Get default/user set transfer settings for the target */
280496554Sobrien	{
2805163816Smjacob		struct	ccb_trans_settings *cts = &(ccb->cts);
2806163816Smjacob		struct ccb_trans_settings_scsi *scsi =
2807163816Smjacob		    &cts->proto_specific.scsi;
2808163816Smjacob		struct ccb_trans_settings_spi *spi =
2809163816Smjacob		    &cts->xport_specific.spi;
281065312Smsmith
2811163816Smjacob		if (cts->type == CTS_TYPE_USER_SETTINGS) {
2812163816Smjacob			cts->protocol = PROTO_SCSI;
2813163816Smjacob			cts->protocol_version = SCSI_REV_2;
2814163816Smjacob			cts->transport = XPORT_SPI;
2815163816Smjacob			cts->transport_version = 2;
2816163816Smjacob
2817163816Smjacob			scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
2818163816Smjacob			spi->flags = CTS_SPI_FLAGS_DISC_ENB;
2819163816Smjacob			spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2820163816Smjacob			spi->sync_period = 6; /* 40MHz */
2821163816Smjacob			spi->sync_offset = 15;
2822163816Smjacob			spi->valid = CTS_SPI_VALID_SYNC_RATE
2823163816Smjacob				   | CTS_SPI_VALID_SYNC_OFFSET
2824163816Smjacob				   | CTS_SPI_VALID_BUS_WIDTH
2825163816Smjacob				   | CTS_SPI_VALID_DISC;
2826163816Smjacob			scsi->valid = CTS_SCSI_VALID_TQ;
2827163816Smjacob
2828163816Smjacob			ccb->ccb_h.status = CAM_REQ_CMP;
2829163816Smjacob		} else {
2830163816Smjacob			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
2831163816Smjacob		}
283296554Sobrien		xpt_done(ccb);
283396554Sobrien		break;
283496554Sobrien	}
283565312Smsmith
283696554Sobrien	case XPT_CALC_GEOMETRY:
283796554Sobrien	{
283896554Sobrien		struct	  ccb_calc_geometry *ccg;
283996554Sobrien		u_int32_t size_mb;
284096554Sobrien		u_int32_t secs_per_cylinder;
284165312Smsmith
284296554Sobrien		ccg = &(ccb->ccg);
284396554Sobrien		size_mb = ccg->volume_size
284496554Sobrien			/ ((1024L * 1024L) / ccg->block_size);
284565312Smsmith
284696554Sobrien		if (size_mb > 4096) {
284796554Sobrien			ccg->heads = 255;
284896554Sobrien			ccg->secs_per_track = 63;
284996554Sobrien		} else if (size_mb > 2048) {
285096554Sobrien			ccg->heads = 128;
285196554Sobrien			ccg->secs_per_track = 63;
285296554Sobrien		} else if (size_mb > 1024) {
285396554Sobrien			ccg->heads = 65;
285496554Sobrien			ccg->secs_per_track = 63;
285596554Sobrien		} else {
285696554Sobrien			ccg->heads = 64;
285796554Sobrien			ccg->secs_per_track = 32;
285896554Sobrien		}
285996554Sobrien		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
286096554Sobrien		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
286196554Sobrien		ccb->ccb_h.status = CAM_REQ_CMP;
286296554Sobrien		xpt_done(ccb);
286396554Sobrien		break;
286496554Sobrien	}
286565312Smsmith
286696554Sobrien	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
286796554Sobrien		ASR_resetBus (sc, cam_sim_bus(sim));
286896554Sobrien		ccb->ccb_h.status = CAM_REQ_CMP;
286996554Sobrien		xpt_done(ccb);
287096554Sobrien		break;
287165312Smsmith
287296554Sobrien	case XPT_TERM_IO:		/* Terminate the I/O process */
287396554Sobrien		/* XXX Implement */
287496554Sobrien		ccb->ccb_h.status = CAM_REQ_INVALID;
287596554Sobrien		xpt_done(ccb);
287696554Sobrien		break;
287765312Smsmith
287896554Sobrien	case XPT_PATH_INQ:		/* Path routing inquiry */
287996554Sobrien	{
288096554Sobrien		struct ccb_pathinq *cpi = &(ccb->cpi);
288165312Smsmith
288296554Sobrien		cpi->version_num = 1; /* XXX??? */
288396554Sobrien		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
288496554Sobrien		cpi->target_sprt = 0;
288596554Sobrien		/* Not necessary to reset bus, done by HDM initialization */
288696554Sobrien		cpi->hba_misc = PIM_NOBUSRESET;
288796554Sobrien		cpi->hba_eng_cnt = 0;
288896554Sobrien		cpi->max_target = sc->ha_MaxId;
288996554Sobrien		cpi->max_lun = sc->ha_MaxLun;
289096554Sobrien		cpi->initiator_id = sc->ha_adapter_target[cam_sim_bus(sim)];
289196554Sobrien		cpi->bus_id = cam_sim_bus(sim);
289296554Sobrien		cpi->base_transfer_speed = 3300;
289396554Sobrien		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
289496554Sobrien		strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
289596554Sobrien		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
289696554Sobrien		cpi->unit_number = cam_sim_unit(sim);
289796554Sobrien		cpi->ccb_h.status = CAM_REQ_CMP;
2898163816Smjacob                cpi->transport = XPORT_SPI;
2899163816Smjacob                cpi->transport_version = 2;
2900163816Smjacob                cpi->protocol = PROTO_SCSI;
2901163816Smjacob                cpi->protocol_version = SCSI_REV_2;
290296554Sobrien		xpt_done(ccb);
290396554Sobrien		break;
290496554Sobrien	}
290596554Sobrien	default:
290696554Sobrien		ccb->ccb_h.status = CAM_REQ_INVALID;
290796554Sobrien		xpt_done(ccb);
290896554Sobrien		break;
290996554Sobrien	}
291065312Smsmith} /* asr_action */
291165312Smsmith
291265312Smsmith/*
291365312Smsmith * Handle processing of current CCB as pointed to by the Status.
291465312Smsmith */
2915128784Sscottlstatic int
2916128784Sscottlasr_intr(Asr_softc_t *sc)
291765312Smsmith{
2918128784Sscottl	int processed;
291965312Smsmith
2920128944Sscottl	for(processed = 0; asr_get_status(sc) & Mask_InterruptsDisabled;
2921128784Sscottl	    processed = 1) {
2922128784Sscottl		union asr_ccb			   *ccb;
2923133041Smarius		u_int				    dsc;
292496554Sobrien		U32				    ReplyOffset;
292596554Sobrien		PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME Reply;
292665312Smsmith
2927128944Sscottl		if (((ReplyOffset = asr_get_FromFIFO(sc)) == EMPTY_QUEUE)
2928128944Sscottl		 && ((ReplyOffset = asr_get_FromFIFO(sc)) == EMPTY_QUEUE)) {
292996554Sobrien			break;
293096554Sobrien		}
293196554Sobrien		Reply = (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)(ReplyOffset
293296554Sobrien		  - sc->ha_Msgs_Phys + (char *)(sc->ha_Msgs));
293396554Sobrien		/*
293496554Sobrien		 * We do not need any (optional byteswapping) method access to
293596554Sobrien		 * the Initiator context field.
293696554Sobrien		 */
293796554Sobrien		ccb = (union asr_ccb *)(long)
293896554Sobrien		  I2O_MESSAGE_FRAME_getInitiatorContext64(
293996554Sobrien		    &(Reply->StdReplyFrame.StdMessageFrame));
294096554Sobrien		if (I2O_MESSAGE_FRAME_getMsgFlags(
294196554Sobrien		  &(Reply->StdReplyFrame.StdMessageFrame))
294296554Sobrien		  & I2O_MESSAGE_FLAGS_FAIL) {
2943128812Sscottl			I2O_UTIL_NOP_MESSAGE	Message;
2944128812Sscottl			PI2O_UTIL_NOP_MESSAGE	Message_Ptr;
2945128812Sscottl			U32			MessageOffset;
294665312Smsmith
294796554Sobrien			MessageOffset = (u_long)
294896554Sobrien			  I2O_FAILURE_REPLY_MESSAGE_FRAME_getPreservedMFA(
294996554Sobrien			    (PI2O_FAILURE_REPLY_MESSAGE_FRAME)Reply);
295096554Sobrien			/*
295196554Sobrien			 *  Get the Original Message Frame's address, and get
295296554Sobrien			 * it's Transaction Context into our space. (Currently
295396554Sobrien			 * unused at original authorship, but better to be
295496554Sobrien			 * safe than sorry). Straight copy means that we
295596554Sobrien			 * need not concern ourselves with the (optional
295696554Sobrien			 * byteswapping) method access.
295796554Sobrien			 */
2958128944Sscottl			Reply->StdReplyFrame.TransactionContext =
2959128944Sscottl			    bus_space_read_4(sc->ha_frame_btag,
2960128944Sscottl			    sc->ha_frame_bhandle, MessageOffset +
2961128944Sscottl			    offsetof(I2O_SINGLE_REPLY_MESSAGE_FRAME,
2962128944Sscottl			    TransactionContext));
296396554Sobrien			/*
296496554Sobrien			 *	For 64 bit machines, we need to reconstruct the
296596554Sobrien			 * 64 bit context.
296696554Sobrien			 */
296796554Sobrien			ccb = (union asr_ccb *)(long)
296896554Sobrien			  I2O_MESSAGE_FRAME_getInitiatorContext64(
296996554Sobrien			    &(Reply->StdReplyFrame.StdMessageFrame));
297096554Sobrien			/*
297196554Sobrien			 * Unique error code for command failure.
297296554Sobrien			 */
297396554Sobrien			I2O_SINGLE_REPLY_MESSAGE_FRAME_setDetailedStatusCode(
297496554Sobrien			  &(Reply->StdReplyFrame), (u_int16_t)-2);
297596554Sobrien			/*
297696554Sobrien			 *  Modify the message frame to contain a NOP and
297796554Sobrien			 * re-issue it to the controller.
297896554Sobrien			 */
297996554Sobrien			Message_Ptr = (PI2O_UTIL_NOP_MESSAGE)ASR_fillMessage(
2980128812Sscottl			    &Message, sizeof(I2O_UTIL_NOP_MESSAGE));
2981128535Sscottl#if (I2O_UTIL_NOP != 0)
298296554Sobrien				I2O_MESSAGE_FRAME_setFunction (
298396554Sobrien				  &(Message_Ptr->StdMessageFrame),
298496554Sobrien				  I2O_UTIL_NOP);
2985128535Sscottl#endif
298696554Sobrien			/*
298796554Sobrien			 *  Copy the packet out to the Original Message
298896554Sobrien			 */
2989128944Sscottl			asr_set_frame(sc, Message_Ptr, MessageOffset,
2990128944Sscottl				      sizeof(I2O_UTIL_NOP_MESSAGE));
299196554Sobrien			/*
299296554Sobrien			 *  Issue the NOP
299396554Sobrien			 */
2994128944Sscottl			asr_set_ToFIFO(sc, MessageOffset);
299596554Sobrien		}
299665312Smsmith
299796554Sobrien		/*
299896554Sobrien		 *	Asynchronous command with no return requirements,
299996554Sobrien		 * and a generic handler for immunity against odd error
300096554Sobrien		 * returns from the adapter.
300196554Sobrien		 */
3002128511Sscottl		if (ccb == NULL) {
300396554Sobrien			/*
300496554Sobrien			 * Return Reply so that it can be used for the
300596554Sobrien			 * next command
300696554Sobrien			 */
3007128944Sscottl			asr_set_FromFIFO(sc, ReplyOffset);
300896554Sobrien			continue;
300996554Sobrien		}
301065312Smsmith
301196554Sobrien		/* Welease Wadjah! (and stop timeouts) */
301296554Sobrien		ASR_ccbRemove (sc, ccb);
301365312Smsmith
3014133041Smarius		dsc = I2O_SINGLE_REPLY_MESSAGE_FRAME_getDetailedStatusCode(
3015133041Smarius		    &(Reply->StdReplyFrame));
3016133041Smarius		ccb->csio.scsi_status = dsc & I2O_SCSI_DEVICE_DSC_MASK;
3017133041Smarius		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
3018133041Smarius		switch (dsc) {
301965312Smsmith
302096554Sobrien		case I2O_SCSI_DSC_SUCCESS:
302196554Sobrien			ccb->ccb_h.status |= CAM_REQ_CMP;
302296554Sobrien			break;
302365312Smsmith
302496554Sobrien		case I2O_SCSI_DSC_CHECK_CONDITION:
3025133041Smarius			ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR |
3026133041Smarius			    CAM_AUTOSNS_VALID;
302796554Sobrien			break;
302865312Smsmith
302996554Sobrien		case I2O_SCSI_DSC_BUSY:
303096554Sobrien			/* FALLTHRU */
303196554Sobrien		case I2O_SCSI_HBA_DSC_ADAPTER_BUSY:
303296554Sobrien			/* FALLTHRU */
303396554Sobrien		case I2O_SCSI_HBA_DSC_SCSI_BUS_RESET:
303496554Sobrien			/* FALLTHRU */
303596554Sobrien		case I2O_SCSI_HBA_DSC_BUS_BUSY:
303696554Sobrien			ccb->ccb_h.status |= CAM_SCSI_BUSY;
303796554Sobrien			break;
303865312Smsmith
303996554Sobrien		case I2O_SCSI_HBA_DSC_SELECTION_TIMEOUT:
304096554Sobrien			ccb->ccb_h.status |= CAM_SEL_TIMEOUT;
304196554Sobrien			break;
304265312Smsmith
304396554Sobrien		case I2O_SCSI_HBA_DSC_COMMAND_TIMEOUT:
304496554Sobrien			/* FALLTHRU */
304596554Sobrien		case I2O_SCSI_HBA_DSC_DEVICE_NOT_PRESENT:
304696554Sobrien			/* FALLTHRU */
304796554Sobrien		case I2O_SCSI_HBA_DSC_LUN_INVALID:
304896554Sobrien			/* FALLTHRU */
304996554Sobrien		case I2O_SCSI_HBA_DSC_SCSI_TID_INVALID:
305096554Sobrien			ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
305196554Sobrien			break;
305265312Smsmith
305396554Sobrien		case I2O_SCSI_HBA_DSC_DATA_OVERRUN:
305496554Sobrien			/* FALLTHRU */
305596554Sobrien		case I2O_SCSI_HBA_DSC_REQUEST_LENGTH_ERROR:
305696554Sobrien			ccb->ccb_h.status |= CAM_DATA_RUN_ERR;
305796554Sobrien			break;
305865312Smsmith
305996554Sobrien		default:
306096554Sobrien			ccb->ccb_h.status |= CAM_REQUEUE_REQ;
306196554Sobrien			break;
306296554Sobrien		}
306396554Sobrien		if ((ccb->csio.resid = ccb->csio.dxfer_len) != 0) {
306496554Sobrien			ccb->csio.resid -=
306596554Sobrien			  I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME_getTransferCount(
306696554Sobrien			    Reply);
306796554Sobrien		}
306865312Smsmith
306996554Sobrien		/* Sense data in reply packet */
307096554Sobrien		if (ccb->ccb_h.status & CAM_AUTOSNS_VALID) {
307196554Sobrien			u_int16_t size = I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME_getAutoSenseTransferCount(Reply);
307265312Smsmith
307396554Sobrien			if (size) {
307496554Sobrien				if (size > sizeof(ccb->csio.sense_data)) {
307596554Sobrien					size = sizeof(ccb->csio.sense_data);
307696554Sobrien				}
307796554Sobrien				if (size > I2O_SCSI_SENSE_DATA_SZ) {
307896554Sobrien					size = I2O_SCSI_SENSE_DATA_SZ;
307996554Sobrien				}
308096554Sobrien				if ((ccb->csio.sense_len)
308196554Sobrien				 && (size > ccb->csio.sense_len)) {
308296554Sobrien					size = ccb->csio.sense_len;
308396554Sobrien				}
3084226350Smarius				if (size < ccb->csio.sense_len) {
3085226350Smarius					ccb->csio.sense_resid =
3086226350Smarius					    ccb->csio.sense_len - size;
3087226350Smarius				} else {
3088226350Smarius					ccb->csio.sense_resid = 0;
3089226350Smarius				}
3090226350Smarius				bzero(&(ccb->csio.sense_data),
3091226350Smarius				    sizeof(ccb->csio.sense_data));
3092128786Sscottl				bcopy(Reply->SenseData,
3093128786Sscottl				      &(ccb->csio.sense_data), size);
309496554Sobrien			}
309596554Sobrien		}
309665312Smsmith
309796554Sobrien		/*
309896554Sobrien		 * Return Reply so that it can be used for the next command
309996554Sobrien		 * since we have no more need for it now
310096554Sobrien		 */
3101128944Sscottl		asr_set_FromFIFO(sc, ReplyOffset);
310265312Smsmith
310396554Sobrien		if (ccb->ccb_h.path) {
310496554Sobrien			xpt_done ((union ccb *)ccb);
310596554Sobrien		} else {
3106111748Sdes			wakeup (ccb);
310796554Sobrien		}
310896554Sobrien	}
310996554Sobrien	return (processed);
311065312Smsmith} /* asr_intr */
311165312Smsmith
311296554Sobrien#undef QueueSize	/* Grrrr */
311396554Sobrien#undef SG_Size		/* Grrrr */
311465312Smsmith
311565312Smsmith/*
311696554Sobrien *	Meant to be included at the bottom of asr.c !!!
311765312Smsmith */
311865312Smsmith
311965312Smsmith/*
312096554Sobrien *	Included here as hard coded. Done because other necessary include
312196554Sobrien *	files utilize C++ comment structures which make them a nuisance to
312296554Sobrien *	included here just to pick up these three typedefs.
312365312Smsmith */
312465312Smsmithtypedef U32   DPT_TAG_T;
312565312Smsmithtypedef U32   DPT_MSG_T;
312665312Smsmithtypedef U32   DPT_RTN_T;
312765312Smsmith
312896554Sobrien#undef SCSI_RESET	/* Conflicts with "scsi/scsiconf.h" defintion */
312996554Sobrien#include	"dev/asr/osd_unix.h"
313065312Smsmith
3131183397Sed#define	asr_unit(dev)	  dev2unit(dev)
313265312Smsmith
3133128784Sscottlstatic u_int8_t ASR_ctlr_held;
313465312Smsmith
3135128784Sscottlstatic int
3136130585Sphkasr_open(struct cdev *dev, int32_t flags, int32_t ifmt, struct thread *td)
313765312Smsmith{
313896554Sobrien	int		 s;
3139128784Sscottl	int		 error;
314065312Smsmith
3141128792Sscottl	if (dev->si_drv1 == NULL) {
314296554Sobrien		return (ENODEV);
314396554Sobrien	}
314496554Sobrien	s = splcam ();
314596554Sobrien	if (ASR_ctlr_held) {
314696554Sobrien		error = EBUSY;
3147164033Srwatson	} else if ((error = priv_check(td, PRIV_DRIVER)) == 0) {
314896554Sobrien		++ASR_ctlr_held;
314996554Sobrien	}
315096554Sobrien	splx(s);
315196554Sobrien	return (error);
315265312Smsmith} /* asr_open */
315365312Smsmith
3154128784Sscottlstatic int
3155130585Sphkasr_close(struct cdev *dev, int flags, int ifmt, struct thread *td)
315665312Smsmith{
315765312Smsmith
315896554Sobrien	ASR_ctlr_held = 0;
315996554Sobrien	return (0);
316065312Smsmith} /* asr_close */
316165312Smsmith
316265312Smsmith
316365312Smsmith/*-------------------------------------------------------------------------*/
316496554Sobrien/*		      Function ASR_queue_i				   */
316565312Smsmith/*-------------------------------------------------------------------------*/
316696554Sobrien/* The Parameters Passed To This Function Are :				   */
316796554Sobrien/*     Asr_softc_t *	  : HBA miniport driver's adapter data storage.	   */
316896554Sobrien/*     PI2O_MESSAGE_FRAME : Msg Structure Pointer For This Command	   */
316996554Sobrien/*	I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME following the Msg Structure	   */
317096554Sobrien/*									   */
317196554Sobrien/* This Function Will Take The User Request Packet And Convert It To An	   */
317296554Sobrien/* I2O MSG And Send It Off To The Adapter.				   */
317396554Sobrien/*									   */
317496554Sobrien/* Return : 0 For OK, Error Code Otherwise				   */
317565312Smsmith/*-------------------------------------------------------------------------*/
3176128784Sscottlstatic int
3177128784SscottlASR_queue_i(Asr_softc_t	*sc, PI2O_MESSAGE_FRAME	Packet)
317865312Smsmith{
317996554Sobrien	union asr_ccb				   * ccb;
318096554Sobrien	PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME	     Reply;
318196554Sobrien	PI2O_MESSAGE_FRAME			     Message_Ptr;
318296554Sobrien	PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME	     Reply_Ptr;
318396554Sobrien	int					     MessageSizeInBytes;
318496554Sobrien	int					     ReplySizeInBytes;
318596554Sobrien	int					     error;
318696554Sobrien	int					     s;
318796554Sobrien	/* Scatter Gather buffer list */
318896554Sobrien	struct ioctlSgList_S {
318996554Sobrien		SLIST_ENTRY(ioctlSgList_S) link;
319096554Sobrien		caddr_t			   UserSpace;
319196554Sobrien		I2O_FLAGS_COUNT		   FlagsCount;
319296554Sobrien		char			   KernelSpace[sizeof(long)];
319396554Sobrien	}					   * elm;
319496554Sobrien	/* Generates a `first' entry */
319596554Sobrien	SLIST_HEAD(ioctlSgListHead_S, ioctlSgList_S) sgList;
319665312Smsmith
319796554Sobrien	if (ASR_getBlinkLedCode(sc)) {
319896554Sobrien		debug_usr_cmd_printf ("Adapter currently in BlinkLed %x\n",
319996554Sobrien		  ASR_getBlinkLedCode(sc));
320096554Sobrien		return (EIO);
320196554Sobrien	}
320296554Sobrien	/* Copy in the message into a local allocation */
320396554Sobrien	if ((Message_Ptr = (PI2O_MESSAGE_FRAME)malloc (
3204128511Sscottl	  sizeof(I2O_MESSAGE_FRAME), M_TEMP, M_WAITOK)) == NULL) {
320596554Sobrien		debug_usr_cmd_printf (
320696554Sobrien		  "Failed to acquire I2O_MESSAGE_FRAME memory\n");
320796554Sobrien		return (ENOMEM);
320896554Sobrien	}
320996554Sobrien	if ((error = copyin ((caddr_t)Packet, (caddr_t)Message_Ptr,
321096554Sobrien	  sizeof(I2O_MESSAGE_FRAME))) != 0) {
3211128812Sscottl		free(Message_Ptr, M_TEMP);
321296554Sobrien		debug_usr_cmd_printf ("Can't copy in packet errno=%d\n", error);
321396554Sobrien		return (error);
321496554Sobrien	}
321596554Sobrien	/* Acquire information to determine type of packet */
321696554Sobrien	MessageSizeInBytes = (I2O_MESSAGE_FRAME_getMessageSize(Message_Ptr)<<2);
321796554Sobrien	/* The offset of the reply information within the user packet */
321896554Sobrien	Reply = (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)((char *)Packet
321996554Sobrien	  + MessageSizeInBytes);
322065312Smsmith
322196554Sobrien	/* Check if the message is a synchronous initialization command */
322296554Sobrien	s = I2O_MESSAGE_FRAME_getFunction(Message_Ptr);
3223128812Sscottl	free(Message_Ptr, M_TEMP);
322496554Sobrien	switch (s) {
322565312Smsmith
322696554Sobrien	case I2O_EXEC_IOP_RESET:
322796554Sobrien	{	U32 status;
322865312Smsmith
3229128944Sscottl		status = ASR_resetIOP(sc);
323096554Sobrien		ReplySizeInBytes = sizeof(status);
323196554Sobrien		debug_usr_cmd_printf ("resetIOP done\n");
323296554Sobrien		return (copyout ((caddr_t)&status, (caddr_t)Reply,
323396554Sobrien		  ReplySizeInBytes));
323496554Sobrien	}
323565312Smsmith
323696554Sobrien	case I2O_EXEC_STATUS_GET:
3237155307Sscottl	{	PI2O_EXEC_STATUS_GET_REPLY status;
323865312Smsmith
3239155307Sscottl		status = &sc->ha_statusmem->status;
3240155307Sscottl		if (ASR_getStatus(sc) == NULL) {
324196554Sobrien			debug_usr_cmd_printf ("getStatus failed\n");
324296554Sobrien			return (ENXIO);
324396554Sobrien		}
324496554Sobrien		ReplySizeInBytes = sizeof(status);
324596554Sobrien		debug_usr_cmd_printf ("getStatus done\n");
3246155307Sscottl		return (copyout ((caddr_t)status, (caddr_t)Reply,
324796554Sobrien		  ReplySizeInBytes));
324896554Sobrien	}
324965312Smsmith
325096554Sobrien	case I2O_EXEC_OUTBOUND_INIT:
325196554Sobrien	{	U32 status;
325265312Smsmith
325396554Sobrien		status = ASR_initOutBound(sc);
325496554Sobrien		ReplySizeInBytes = sizeof(status);
325596554Sobrien		debug_usr_cmd_printf ("intOutBound done\n");
325696554Sobrien		return (copyout ((caddr_t)&status, (caddr_t)Reply,
325796554Sobrien		  ReplySizeInBytes));
325896554Sobrien	}
325996554Sobrien	}
326065312Smsmith
326196554Sobrien	/* Determine if the message size is valid */
326296554Sobrien	if ((MessageSizeInBytes < sizeof(I2O_MESSAGE_FRAME))
326396554Sobrien	 || (MAX_INBOUND_SIZE < MessageSizeInBytes)) {
326496554Sobrien		debug_usr_cmd_printf ("Packet size %d incorrect\n",
326596554Sobrien		  MessageSizeInBytes);
326696554Sobrien		return (EINVAL);
326796554Sobrien	}
326865312Smsmith
326996554Sobrien	if ((Message_Ptr = (PI2O_MESSAGE_FRAME)malloc (MessageSizeInBytes,
3270128511Sscottl	  M_TEMP, M_WAITOK)) == NULL) {
327196554Sobrien		debug_usr_cmd_printf ("Failed to acquire frame[%d] memory\n",
327296554Sobrien		  MessageSizeInBytes);
327396554Sobrien		return (ENOMEM);
327496554Sobrien	}
327596554Sobrien	if ((error = copyin ((caddr_t)Packet, (caddr_t)Message_Ptr,
327696554Sobrien	  MessageSizeInBytes)) != 0) {
3277128812Sscottl		free(Message_Ptr, M_TEMP);
327896554Sobrien		debug_usr_cmd_printf ("Can't copy in packet[%d] errno=%d\n",
327996554Sobrien		  MessageSizeInBytes, error);
328096554Sobrien		return (error);
328196554Sobrien	}
328265312Smsmith
328396554Sobrien	/* Check the size of the reply frame, and start constructing */
328465312Smsmith
328596554Sobrien	if ((Reply_Ptr = (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)malloc (
3286128511Sscottl	  sizeof(I2O_MESSAGE_FRAME), M_TEMP, M_WAITOK)) == NULL) {
3287128812Sscottl		free(Message_Ptr, M_TEMP);
328896554Sobrien		debug_usr_cmd_printf (
328996554Sobrien		  "Failed to acquire I2O_MESSAGE_FRAME memory\n");
329096554Sobrien		return (ENOMEM);
329196554Sobrien	}
329296554Sobrien	if ((error = copyin ((caddr_t)Reply, (caddr_t)Reply_Ptr,
329396554Sobrien	  sizeof(I2O_MESSAGE_FRAME))) != 0) {
3294128812Sscottl		free(Reply_Ptr, M_TEMP);
3295128812Sscottl		free(Message_Ptr, M_TEMP);
329696554Sobrien		debug_usr_cmd_printf (
329796554Sobrien		  "Failed to copy in reply frame, errno=%d\n",
329896554Sobrien		  error);
329996554Sobrien		return (error);
330096554Sobrien	}
330196554Sobrien	ReplySizeInBytes = (I2O_MESSAGE_FRAME_getMessageSize(
330296554Sobrien	  &(Reply_Ptr->StdReplyFrame.StdMessageFrame)) << 2);
3303128812Sscottl	free(Reply_Ptr, M_TEMP);
330496554Sobrien	if (ReplySizeInBytes < sizeof(I2O_SINGLE_REPLY_MESSAGE_FRAME)) {
3305128812Sscottl		free(Message_Ptr, M_TEMP);
330696554Sobrien		debug_usr_cmd_printf (
330796554Sobrien		  "Failed to copy in reply frame[%d], errno=%d\n",
330896554Sobrien		  ReplySizeInBytes, error);
330996554Sobrien		return (EINVAL);
331096554Sobrien	}
331165312Smsmith
331296554Sobrien	if ((Reply_Ptr = (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)malloc (
331396554Sobrien	  ((ReplySizeInBytes > sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME))
3314128511Sscottl	    ? ReplySizeInBytes : sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)),
3315128511Sscottl	  M_TEMP, M_WAITOK)) == NULL) {
3316128812Sscottl		free(Message_Ptr, M_TEMP);
331796554Sobrien		debug_usr_cmd_printf ("Failed to acquire frame[%d] memory\n",
331896554Sobrien		  ReplySizeInBytes);
331996554Sobrien		return (ENOMEM);
332096554Sobrien	}
3321128812Sscottl	(void)ASR_fillMessage((void *)Reply_Ptr, ReplySizeInBytes);
332296554Sobrien	Reply_Ptr->StdReplyFrame.StdMessageFrame.InitiatorContext
332396554Sobrien	  = Message_Ptr->InitiatorContext;
332496554Sobrien	Reply_Ptr->StdReplyFrame.TransactionContext
332596554Sobrien	  = ((PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr)->TransactionContext;
332696554Sobrien	I2O_MESSAGE_FRAME_setMsgFlags(
332796554Sobrien	  &(Reply_Ptr->StdReplyFrame.StdMessageFrame),
332896554Sobrien	  I2O_MESSAGE_FRAME_getMsgFlags(
332996554Sobrien	    &(Reply_Ptr->StdReplyFrame.StdMessageFrame))
333096554Sobrien	      | I2O_MESSAGE_FLAGS_REPLY);
333165312Smsmith
333296554Sobrien	/* Check if the message is a special case command */
333396554Sobrien	switch (I2O_MESSAGE_FRAME_getFunction(Message_Ptr)) {
333496554Sobrien	case I2O_EXEC_SYS_TAB_SET: /* Special Case of empty Scatter Gather */
333596554Sobrien		if (MessageSizeInBytes == ((I2O_MESSAGE_FRAME_getVersionOffset(
333696554Sobrien		  Message_Ptr) & 0xF0) >> 2)) {
3337128812Sscottl			free(Message_Ptr, M_TEMP);
333896554Sobrien			I2O_SINGLE_REPLY_MESSAGE_FRAME_setDetailedStatusCode(
333996554Sobrien			  &(Reply_Ptr->StdReplyFrame),
334096554Sobrien			  (ASR_setSysTab(sc) != CAM_REQ_CMP));
334196554Sobrien			I2O_MESSAGE_FRAME_setMessageSize(
334296554Sobrien			  &(Reply_Ptr->StdReplyFrame.StdMessageFrame),
334396554Sobrien			  sizeof(I2O_SINGLE_REPLY_MESSAGE_FRAME));
334496554Sobrien			error = copyout ((caddr_t)Reply_Ptr, (caddr_t)Reply,
334596554Sobrien			  ReplySizeInBytes);
3346128812Sscottl			free(Reply_Ptr, M_TEMP);
334796554Sobrien			return (error);
334896554Sobrien		}
334996554Sobrien	}
335065312Smsmith
335196554Sobrien	/* Deal in the general case */
335296554Sobrien	/* First allocate and optionally copy in each scatter gather element */
335396554Sobrien	SLIST_INIT(&sgList);
335496554Sobrien	if ((I2O_MESSAGE_FRAME_getVersionOffset(Message_Ptr) & 0xF0) != 0) {
335596554Sobrien		PI2O_SGE_SIMPLE_ELEMENT sg;
335665312Smsmith
335796554Sobrien		/*
335896554Sobrien		 *	since this code is reused in several systems, code
335996554Sobrien		 * efficiency is greater by using a shift operation rather
336096554Sobrien		 * than a divide by sizeof(u_int32_t).
336196554Sobrien		 */
336296554Sobrien		sg = (PI2O_SGE_SIMPLE_ELEMENT)((char *)Message_Ptr
336396554Sobrien		  + ((I2O_MESSAGE_FRAME_getVersionOffset(Message_Ptr) & 0xF0)
336496554Sobrien		    >> 2));
336596554Sobrien		while (sg < (PI2O_SGE_SIMPLE_ELEMENT)(((caddr_t)Message_Ptr)
336696554Sobrien		  + MessageSizeInBytes)) {
336796554Sobrien			caddr_t v;
336896554Sobrien			int	len;
336965312Smsmith
337096554Sobrien			if ((I2O_FLAGS_COUNT_getFlags(&(sg->FlagsCount))
337196554Sobrien			 & I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT) == 0) {
337296554Sobrien				error = EINVAL;
337396554Sobrien				break;
337496554Sobrien			}
337596554Sobrien			len = I2O_FLAGS_COUNT_getCount(&(sg->FlagsCount));
337696554Sobrien			debug_usr_cmd_printf ("SG[%d] = %x[%d]\n",
337796554Sobrien			  sg - (PI2O_SGE_SIMPLE_ELEMENT)((char *)Message_Ptr
337896554Sobrien			  + ((I2O_MESSAGE_FRAME_getVersionOffset(
337996554Sobrien				Message_Ptr) & 0xF0) >> 2)),
338096554Sobrien			  I2O_SGE_SIMPLE_ELEMENT_getPhysicalAddress(sg), len);
338165312Smsmith
338296554Sobrien			if ((elm = (struct ioctlSgList_S *)malloc (
338396554Sobrien			  sizeof(*elm) - sizeof(elm->KernelSpace) + len,
3384128511Sscottl			  M_TEMP, M_WAITOK)) == NULL) {
338596554Sobrien				debug_usr_cmd_printf (
338696554Sobrien				  "Failed to allocate SG[%d]\n", len);
338796554Sobrien				error = ENOMEM;
338896554Sobrien				break;
338996554Sobrien			}
339096554Sobrien			SLIST_INSERT_HEAD(&sgList, elm, link);
339196554Sobrien			elm->FlagsCount = sg->FlagsCount;
339296554Sobrien			elm->UserSpace = (caddr_t)
339396554Sobrien			  (I2O_SGE_SIMPLE_ELEMENT_getPhysicalAddress(sg));
339496554Sobrien			v = elm->KernelSpace;
339596554Sobrien			/* Copy in outgoing data (DIR bit could be invalid) */
339696554Sobrien			if ((error = copyin (elm->UserSpace, (caddr_t)v, len))
339796554Sobrien			  != 0) {
339896554Sobrien				break;
339996554Sobrien			}
340096554Sobrien			/*
340196554Sobrien			 *	If the buffer is not contiguous, lets
340296554Sobrien			 * break up the scatter/gather entries.
340396554Sobrien			 */
340496554Sobrien			while ((len > 0)
340596554Sobrien			 && (sg < (PI2O_SGE_SIMPLE_ELEMENT)
340696554Sobrien			  (((caddr_t)Message_Ptr) + MAX_INBOUND_SIZE))) {
340796554Sobrien				int next, base, span;
340865312Smsmith
340996554Sobrien				span = 0;
341096554Sobrien				next = base = KVTOPHYS(v);
341196554Sobrien				I2O_SGE_SIMPLE_ELEMENT_setPhysicalAddress(sg,
341296554Sobrien				  base);
341365312Smsmith
341496554Sobrien				/* How far can we go physically contiguously */
341596554Sobrien				while ((len > 0) && (base == next)) {
341696554Sobrien					int size;
341765312Smsmith
341896554Sobrien					next = trunc_page(base) + PAGE_SIZE;
341996554Sobrien					size = next - base;
342096554Sobrien					if (size > len) {
342196554Sobrien						size = len;
342296554Sobrien					}
342396554Sobrien					span += size;
342496554Sobrien					v += size;
342596554Sobrien					len -= size;
342696554Sobrien					base = KVTOPHYS(v);
342796554Sobrien				}
342865312Smsmith
342996554Sobrien				/* Construct the Flags */
343096554Sobrien				I2O_FLAGS_COUNT_setCount(&(sg->FlagsCount),
343196554Sobrien				  span);
343296554Sobrien				{
343396554Sobrien					int flags = I2O_FLAGS_COUNT_getFlags(
343496554Sobrien					  &(elm->FlagsCount));
343596554Sobrien					/* Any remaining length? */
343696554Sobrien					if (len > 0) {
343796554Sobrien					    flags &=
343896554Sobrien						~(I2O_SGL_FLAGS_END_OF_BUFFER
343996554Sobrien						 | I2O_SGL_FLAGS_LAST_ELEMENT);
344096554Sobrien					}
344196554Sobrien					I2O_FLAGS_COUNT_setFlags(
344296554Sobrien					  &(sg->FlagsCount), flags);
344396554Sobrien				}
344465312Smsmith
344596554Sobrien				debug_usr_cmd_printf ("sg[%d] = %x[%d]\n",
344696554Sobrien				  sg - (PI2O_SGE_SIMPLE_ELEMENT)
344796554Sobrien				    ((char *)Message_Ptr
344896554Sobrien				  + ((I2O_MESSAGE_FRAME_getVersionOffset(
344996554Sobrien					Message_Ptr) & 0xF0) >> 2)),
345096554Sobrien				  I2O_SGE_SIMPLE_ELEMENT_getPhysicalAddress(sg),
345196554Sobrien				  span);
345296554Sobrien				if (len <= 0) {
345396554Sobrien					break;
345496554Sobrien				}
345565312Smsmith
345696554Sobrien				/*
345796554Sobrien				 * Incrementing requires resizing of the
345896554Sobrien				 * packet, and moving up the existing SG
345996554Sobrien				 * elements.
346096554Sobrien				 */
346196554Sobrien				++sg;
346296554Sobrien				MessageSizeInBytes += sizeof(*sg);
346396554Sobrien				I2O_MESSAGE_FRAME_setMessageSize(Message_Ptr,
346496554Sobrien				  I2O_MESSAGE_FRAME_getMessageSize(Message_Ptr)
346596554Sobrien				  + (sizeof(*sg) / sizeof(U32)));
346696554Sobrien				{
346796554Sobrien					PI2O_MESSAGE_FRAME NewMessage_Ptr;
346865312Smsmith
346996554Sobrien					if ((NewMessage_Ptr
347096554Sobrien					  = (PI2O_MESSAGE_FRAME)
347196554Sobrien					    malloc (MessageSizeInBytes,
3472128511Sscottl					     M_TEMP, M_WAITOK)) == NULL) {
347396554Sobrien						debug_usr_cmd_printf (
347496554Sobrien						  "Failed to acquire frame[%d] memory\n",
347596554Sobrien						  MessageSizeInBytes);
347696554Sobrien						error = ENOMEM;
347796554Sobrien						break;
347896554Sobrien					}
347996554Sobrien					span = ((caddr_t)sg)
348096554Sobrien					     - (caddr_t)Message_Ptr;
3481128786Sscottl					bcopy(Message_Ptr,NewMessage_Ptr, span);
3482128786Sscottl					bcopy((caddr_t)(sg-1),
348396554Sobrien					  ((caddr_t)NewMessage_Ptr) + span,
348496554Sobrien					  MessageSizeInBytes - span);
3485128812Sscottl					free(Message_Ptr, M_TEMP);
348696554Sobrien					sg = (PI2O_SGE_SIMPLE_ELEMENT)
348796554Sobrien					  (((caddr_t)NewMessage_Ptr) + span);
348896554Sobrien					Message_Ptr = NewMessage_Ptr;
348996554Sobrien				}
349096554Sobrien			}
349196554Sobrien			if ((error)
349296554Sobrien			 || ((I2O_FLAGS_COUNT_getFlags(&(sg->FlagsCount))
349396554Sobrien			  & I2O_SGL_FLAGS_LAST_ELEMENT) != 0)) {
349496554Sobrien				break;
349596554Sobrien			}
349696554Sobrien			++sg;
349796554Sobrien		}
349896554Sobrien		if (error) {
3499128511Sscottl			while ((elm = SLIST_FIRST(&sgList)) != NULL) {
350096554Sobrien				SLIST_REMOVE_HEAD(&sgList, link);
3501128812Sscottl				free(elm, M_TEMP);
350296554Sobrien			}
3503128812Sscottl			free(Reply_Ptr, M_TEMP);
3504128812Sscottl			free(Message_Ptr, M_TEMP);
350596554Sobrien			return (error);
350696554Sobrien		}
350796554Sobrien	}
350865312Smsmith
350996554Sobrien	debug_usr_cmd_printf ("Inbound: ");
351096554Sobrien	debug_usr_cmd_dump_message(Message_Ptr);
351165312Smsmith
351296554Sobrien	/* Send the command */
3513128511Sscottl	if ((ccb = asr_alloc_ccb (sc)) == NULL) {
351496554Sobrien		/* Free up in-kernel buffers */
3515128511Sscottl		while ((elm = SLIST_FIRST(&sgList)) != NULL) {
351696554Sobrien			SLIST_REMOVE_HEAD(&sgList, link);
3517128812Sscottl			free(elm, M_TEMP);
351896554Sobrien		}
3519128812Sscottl		free(Reply_Ptr, M_TEMP);
3520128812Sscottl		free(Message_Ptr, M_TEMP);
352196554Sobrien		return (ENOMEM);
352296554Sobrien	}
352365312Smsmith
352496554Sobrien	/*
352596554Sobrien	 * We do not need any (optional byteswapping) method access to
352696554Sobrien	 * the Initiator context field.
352796554Sobrien	 */
352896554Sobrien	I2O_MESSAGE_FRAME_setInitiatorContext64(
352996554Sobrien	  (PI2O_MESSAGE_FRAME)Message_Ptr, (long)ccb);
353065312Smsmith
353196554Sobrien	(void)ASR_queue (sc, (PI2O_MESSAGE_FRAME)Message_Ptr);
353265312Smsmith
3533128812Sscottl	free(Message_Ptr, M_TEMP);
353465312Smsmith
353596554Sobrien	/*
353696554Sobrien	 * Wait for the board to report a finished instruction.
353796554Sobrien	 */
353896554Sobrien	s = splcam();
353996554Sobrien	while ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
354096554Sobrien		if (ASR_getBlinkLedCode(sc)) {
354196554Sobrien			/* Reset Adapter */
354296554Sobrien			printf ("asr%d: Blink LED 0x%x resetting adapter\n",
354396554Sobrien			  cam_sim_unit(xpt_path_sim(ccb->ccb_h.path)),
354496554Sobrien			  ASR_getBlinkLedCode(sc));
354596554Sobrien			if (ASR_reset (sc) == ENXIO) {
354696554Sobrien				/* Command Cleanup */
354796554Sobrien				ASR_ccbRemove(sc, ccb);
354896554Sobrien			}
354996554Sobrien			splx(s);
355096554Sobrien			/* Free up in-kernel buffers */
3551128511Sscottl			while ((elm = SLIST_FIRST(&sgList)) != NULL) {
355296554Sobrien				SLIST_REMOVE_HEAD(&sgList, link);
3553128812Sscottl				free(elm, M_TEMP);
355496554Sobrien			}
3555128812Sscottl			free(Reply_Ptr, M_TEMP);
355696554Sobrien			asr_free_ccb(ccb);
355796554Sobrien			return (EIO);
355896554Sobrien		}
355996554Sobrien		/* Check every second for BlinkLed */
356096554Sobrien		/* There is no PRICAM, but outwardly PRIBIO is functional */
3561111748Sdes		tsleep(ccb, PRIBIO, "asr", hz);
356296554Sobrien	}
356396554Sobrien	splx(s);
356465312Smsmith
356596554Sobrien	debug_usr_cmd_printf ("Outbound: ");
356696554Sobrien	debug_usr_cmd_dump_message(Reply_Ptr);
356765312Smsmith
356896554Sobrien	I2O_SINGLE_REPLY_MESSAGE_FRAME_setDetailedStatusCode(
356996554Sobrien	  &(Reply_Ptr->StdReplyFrame),
357096554Sobrien	  (ccb->ccb_h.status != CAM_REQ_CMP));
357165312Smsmith
357296554Sobrien	if (ReplySizeInBytes >= (sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)
357396554Sobrien	  - I2O_SCSI_SENSE_DATA_SZ - sizeof(U32))) {
357496554Sobrien		I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME_setTransferCount(Reply_Ptr,
357596554Sobrien		  ccb->csio.dxfer_len - ccb->csio.resid);
357696554Sobrien	}
357796554Sobrien	if ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) && (ReplySizeInBytes
357896554Sobrien	 > (sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)
357996554Sobrien	 - I2O_SCSI_SENSE_DATA_SZ))) {
358096554Sobrien		int size = ReplySizeInBytes
358196554Sobrien		  - sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)
358296554Sobrien		  - I2O_SCSI_SENSE_DATA_SZ;
358365312Smsmith
358496554Sobrien		if (size > sizeof(ccb->csio.sense_data)) {
358596554Sobrien			size = sizeof(ccb->csio.sense_data);
358696554Sobrien		}
3587226350Smarius		if (size < ccb->csio.sense_len) {
3588226350Smarius			ccb->csio.sense_resid = ccb->csio.sense_len - size;
3589226350Smarius		} else {
3590226350Smarius			ccb->csio.sense_resid = 0;
3591226350Smarius		}
3592226350Smarius		bzero(&(ccb->csio.sense_data), sizeof(ccb->csio.sense_data));
3593128786Sscottl		bcopy(&(ccb->csio.sense_data), Reply_Ptr->SenseData, size);
359496554Sobrien		I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME_setAutoSenseTransferCount(
3595128786Sscottl		    Reply_Ptr, size);
359696554Sobrien	}
359765312Smsmith
359896554Sobrien	/* Free up in-kernel buffers */
3599128511Sscottl	while ((elm = SLIST_FIRST(&sgList)) != NULL) {
360096554Sobrien		/* Copy out as necessary */
360196554Sobrien		if ((error == 0)
360296554Sobrien		/* DIR bit considered `valid', error due to ignorance works */
360396554Sobrien		 && ((I2O_FLAGS_COUNT_getFlags(&(elm->FlagsCount))
360496554Sobrien		  & I2O_SGL_FLAGS_DIR) == 0)) {
3605128786Sscottl			error = copyout((caddr_t)(elm->KernelSpace),
360696554Sobrien			  elm->UserSpace,
360796554Sobrien			  I2O_FLAGS_COUNT_getCount(&(elm->FlagsCount)));
360896554Sobrien		}
360996554Sobrien		SLIST_REMOVE_HEAD(&sgList, link);
3610128786Sscottl		free(elm, M_TEMP);
361196554Sobrien	}
361296554Sobrien	if (error == 0) {
361396554Sobrien	/* Copy reply frame to user space */
3614128786Sscottl		error = copyout((caddr_t)Reply_Ptr, (caddr_t)Reply,
3615128786Sscottl				ReplySizeInBytes);
361696554Sobrien	}
3617128786Sscottl	free(Reply_Ptr, M_TEMP);
361896554Sobrien	asr_free_ccb(ccb);
361965312Smsmith
362096554Sobrien	return (error);
362165312Smsmith} /* ASR_queue_i */
362265312Smsmith
362365312Smsmith/*----------------------------------------------------------------------*/
362496554Sobrien/*			    Function asr_ioctl			       */
362565312Smsmith/*----------------------------------------------------------------------*/
362696554Sobrien/* The parameters passed to this function are :				*/
362796554Sobrien/*     dev  : Device number.						*/
362896554Sobrien/*     cmd  : Ioctl Command						*/
362996554Sobrien/*     data : User Argument Passed In.					*/
363096554Sobrien/*     flag : Mode Parameter						*/
363196554Sobrien/*     proc : Process Parameter						*/
363296554Sobrien/*									*/
363396554Sobrien/* This function is the user interface into this adapter driver		*/
363496554Sobrien/*									*/
363596554Sobrien/* Return : zero if OK, error code if not				*/
363665312Smsmith/*----------------------------------------------------------------------*/
363765312Smsmith
3638128784Sscottlstatic int
3639130585Sphkasr_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
364065312Smsmith{
3641128792Sscottl	Asr_softc_t	*sc = dev->si_drv1;
3642128945Sscottl	int		i, error = 0;
3643143729Scognet#ifdef ASR_IOCTL_COMPAT
3644143729Scognet	int		j;
3645143729Scognet#endif /* ASR_IOCTL_COMPAT */
364665312Smsmith
3647128511Sscottl	if (sc != NULL)
364896554Sobrien	switch(cmd) {
364965312Smsmith
365096554Sobrien	case DPT_SIGNATURE:
3651143729Scognet#ifdef ASR_IOCTL_COMPAT
3652143729Scognet#if (dsDescription_size != 50)
3653143729Scognet	case DPT_SIGNATURE + ((50 - dsDescription_size) << 16):
3654143729Scognet#endif
3655143729Scognet		if (cmd & 0xFFFF0000) {
3656143729Scognet			bcopy(&ASR_sig, data, sizeof(dpt_sig_S));
3657143729Scognet			return (0);
3658143729Scognet		}
3659143729Scognet	/* Traditional version of the ioctl interface */
3660143729Scognet	case DPT_SIGNATURE & 0x0000FFFF:
3661143729Scognet#endif
3662128945Sscottl		return (copyout((caddr_t)(&ASR_sig), *((caddr_t *)data),
3663128945Sscottl				sizeof(dpt_sig_S)));
366465312Smsmith
366596554Sobrien	/* Traditional version of the ioctl interface */
366696554Sobrien	case DPT_CTRLINFO & 0x0000FFFF:
366796554Sobrien	case DPT_CTRLINFO: {
366896554Sobrien		struct {
366996554Sobrien			u_int16_t length;
367096554Sobrien			u_int16_t drvrHBAnum;
367196554Sobrien			u_int32_t baseAddr;
367296554Sobrien			u_int16_t blinkState;
367396554Sobrien			u_int8_t  pciBusNum;
367496554Sobrien			u_int8_t  pciDeviceNum;
367596554Sobrien			u_int16_t hbaFlags;
367696554Sobrien			u_int16_t Interrupt;
367796554Sobrien			u_int32_t reserved1;
367896554Sobrien			u_int32_t reserved2;
367996554Sobrien			u_int32_t reserved3;
368096554Sobrien		} CtlrInfo;
368165312Smsmith
3682128787Sscottl		bzero(&CtlrInfo, sizeof(CtlrInfo));
368396554Sobrien		CtlrInfo.length = sizeof(CtlrInfo) - sizeof(u_int16_t);
368496554Sobrien		CtlrInfo.drvrHBAnum = asr_unit(dev);
3685128944Sscottl		CtlrInfo.baseAddr = sc->ha_Base;
368696554Sobrien		i = ASR_getBlinkLedCode (sc);
3687128945Sscottl		if (i == -1)
368896554Sobrien			i = 0;
3689128945Sscottl
369096554Sobrien		CtlrInfo.blinkState = i;
369196554Sobrien		CtlrInfo.pciBusNum = sc->ha_pciBusNum;
369296554Sobrien		CtlrInfo.pciDeviceNum = sc->ha_pciDeviceNum;
369396615Sobrien#define	FLG_OSD_PCI_VALID 0x0001
369496615Sobrien#define	FLG_OSD_DMA	  0x0002
369596615Sobrien#define	FLG_OSD_I2O	  0x0004
3696128786Sscottl		CtlrInfo.hbaFlags = FLG_OSD_PCI_VALID|FLG_OSD_DMA|FLG_OSD_I2O;
369796554Sobrien		CtlrInfo.Interrupt = sc->ha_irq;
3698143729Scognet#ifdef ASR_IOCTL_COMPAT
3699143729Scognet		if (cmd & 0xffff0000)
3700143729Scognet			bcopy(&CtlrInfo, data, sizeof(CtlrInfo));
3701143729Scognet		else
3702143729Scognet#endif /* ASR_IOCTL_COMPAT */
3703128945Sscottl		error = copyout(&CtlrInfo, *(caddr_t *)data, sizeof(CtlrInfo));
370496554Sobrien	}	return (error);
370565312Smsmith
370696554Sobrien	/* Traditional version of the ioctl interface */
370796554Sobrien	case DPT_SYSINFO & 0x0000FFFF:
370896554Sobrien	case DPT_SYSINFO: {
370996554Sobrien		sysInfo_S	Info;
3710143729Scognet#ifdef ASR_IOCTL_COMPAT
3711143729Scognet		char	      * cp;
3712143729Scognet		/* Kernel Specific ptok `hack' */
3713143729Scognet#define		ptok(a) ((char *)(uintptr_t)(a) + KERNBASE)
371465312Smsmith
3715128786Sscottl		bzero(&Info, sizeof(Info));
371665312Smsmith
3717143729Scognet		/* Appears I am the only person in the Kernel doing this */
3718143729Scognet		outb (0x70, 0x12);
3719143729Scognet		i = inb(0x71);
3720143729Scognet		j = i >> 4;
3721143729Scognet		if (i == 0x0f) {
3722143729Scognet			outb (0x70, 0x19);
3723143729Scognet			j = inb (0x71);
3724143729Scognet		}
3725143729Scognet		Info.drive0CMOS = j;
3726143729Scognet
3727143729Scognet		j = i & 0x0f;
3728143729Scognet		if (i == 0x0f) {
3729143729Scognet			outb (0x70, 0x1a);
3730143729Scognet			j = inb (0x71);
3731143729Scognet		}
3732143729Scognet		Info.drive1CMOS = j;
3733143729Scognet
3734143729Scognet		Info.numDrives = *((char *)ptok(0x475));
3735215843Sbrian#else /* ASR_IOCTL_COMPAT */
3736215843Sbrian		bzero(&Info, sizeof(Info));
3737143729Scognet#endif /* ASR_IOCTL_COMPAT */
3738143729Scognet
373996554Sobrien		Info.processorFamily = ASR_sig.dsProcessorFamily;
374096614Sobrien#if defined(__i386__)
374196554Sobrien		switch (cpu) {
374296554Sobrien		case CPU_386SX: case CPU_386:
374396554Sobrien			Info.processorType = PROC_386; break;
374496554Sobrien		case CPU_486SX: case CPU_486:
374596554Sobrien			Info.processorType = PROC_486; break;
374696554Sobrien		case CPU_586:
374796554Sobrien			Info.processorType = PROC_PENTIUM; break;
374896554Sobrien		case CPU_686:
374996554Sobrien			Info.processorType = PROC_SEXIUM; break;
375096554Sobrien		}
375175062Sscottl#endif
375275062Sscottl
375396554Sobrien		Info.osType = OS_BSDI_UNIX;
375496554Sobrien		Info.osMajorVersion = osrelease[0] - '0';
375596554Sobrien		Info.osMinorVersion = osrelease[2] - '0';
375696554Sobrien		/* Info.osRevision = 0; */
375796554Sobrien		/* Info.osSubRevision = 0; */
375896554Sobrien		Info.busType = SI_PCI_BUS;
3759128945Sscottl		Info.flags = SI_OSversionValid|SI_BusTypeValid|SI_NO_SmartROM;
376065312Smsmith
3761143729Scognet#ifdef ASR_IOCTL_COMPAT
3762143729Scognet		Info.flags |= SI_CMOS_Valid | SI_NumDrivesValid;
3763143729Scognet		/* Go Out And Look For I2O SmartROM */
3764143729Scognet		for(j = 0xC8000; j < 0xE0000; j += 2048) {
3765143729Scognet			int k;
3766143729Scognet
3767143729Scognet			cp = ptok(j);
3768143729Scognet			if (*((unsigned short *)cp) != 0xAA55) {
3769143729Scognet				continue;
3770143729Scognet			}
3771143729Scognet			j += (cp[2] * 512) - 2048;
3772143729Scognet			if ((*((u_long *)(cp + 6))
3773143729Scognet			  != ('S' + (' ' * 256) + (' ' * 65536L)))
3774143729Scognet			 || (*((u_long *)(cp + 10))
3775143729Scognet			  != ('I' + ('2' * 256) + ('0' * 65536L)))) {
3776143729Scognet				continue;
3777143729Scognet			}
3778143729Scognet			cp += 0x24;
3779143729Scognet			for (k = 0; k < 64; ++k) {
3780143729Scognet				if (*((unsigned short *)cp)
3781143729Scognet				 == (' ' + ('v' * 256))) {
3782143729Scognet					break;
3783143729Scognet				}
3784143729Scognet			}
3785143729Scognet			if (k < 64) {
3786143729Scognet				Info.smartROMMajorVersion
3787143729Scognet				    = *((unsigned char *)(cp += 4)) - '0';
3788143729Scognet				Info.smartROMMinorVersion
3789143729Scognet				    = *((unsigned char *)(cp += 2));
3790143729Scognet				Info.smartROMRevision
3791143729Scognet				    = *((unsigned char *)(++cp));
3792143729Scognet				Info.flags |= SI_SmartROMverValid;
3793143729Scognet				Info.flags &= ~SI_NO_SmartROM;
3794143729Scognet				break;
3795143729Scognet			}
3796143729Scognet		}
3797143729Scognet		/* Get The Conventional Memory Size From CMOS */
3798143729Scognet		outb (0x70, 0x16);
3799143729Scognet		j = inb (0x71);
3800143729Scognet		j <<= 8;
3801143729Scognet		outb (0x70, 0x15);
3802143729Scognet		j |= inb(0x71);
3803143729Scognet		Info.conventionalMemSize = j;
3804143729Scognet
3805143729Scognet		/* Get The Extended Memory Found At Power On From CMOS */
3806143729Scognet		outb (0x70, 0x31);
3807143729Scognet		j = inb (0x71);
3808143729Scognet		j <<= 8;
3809143729Scognet		outb (0x70, 0x30);
3810143729Scognet		j |= inb(0x71);
3811143729Scognet		Info.extendedMemSize = j;
3812143729Scognet		Info.flags |= SI_MemorySizeValid;
3813143729Scognet
3814143729Scognet		/* Copy Out The Info Structure To The User */
3815143729Scognet		if (cmd & 0xFFFF0000)
3816143729Scognet			bcopy(&Info, data, sizeof(Info));
3817143729Scognet		else
3818143729Scognet#endif /* ASR_IOCTL_COMPAT */
3819128945Sscottl		error = copyout(&Info, *(caddr_t *)data, sizeof(Info));
382096554Sobrien		return (error); }
382165312Smsmith
382296554Sobrien		/* Get The BlinkLED State */
382396554Sobrien	case DPT_BLINKLED:
382496554Sobrien		i = ASR_getBlinkLedCode (sc);
3825143729Scognet		if (i == -1)
382696554Sobrien			i = 0;
3827143729Scognet#ifdef ASR_IOCTL_COMPAT
3828143729Scognet		if (cmd & 0xffff0000)
3829143729Scognet			bcopy(&i, data, sizeof(i));
3830143729Scognet		else
3831143729Scognet#endif /* ASR_IOCTL_COMPAT */
3832128945Sscottl		error = copyout(&i, *(caddr_t *)data, sizeof(i));
383396554Sobrien		break;
383465312Smsmith
383596554Sobrien		/* Send an I2O command */
383696554Sobrien	case I2OUSRCMD:
3837128786Sscottl		return (ASR_queue_i(sc, *((PI2O_MESSAGE_FRAME *)data)));
383865312Smsmith
383996554Sobrien		/* Reset and re-initialize the adapter */
384096554Sobrien	case I2ORESETCMD:
3841128786Sscottl		return (ASR_reset(sc));
384265312Smsmith
384396554Sobrien		/* Rescan the LCT table and resynchronize the information */
384496554Sobrien	case I2ORESCANCMD:
3845128786Sscottl		return (ASR_rescan(sc));
384696554Sobrien	}
384796554Sobrien	return (EINVAL);
384865312Smsmith} /* asr_ioctl */
3849