xref: /illumos-gate/usr/src/uts/common/io/aac/aac.c (revision 3fe80ca4)
1 /*
2  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /*
6  * Copyright 2023 Oxide Computer Company
7  * Copyright (c) 2018, Joyent, Inc.
8  * Copyright 2005-08 Adaptec, Inc.
9  * Copyright (c) 2005-08 Adaptec Inc., Achim Leubner
10  * Copyright (c) 2000 Michael Smith
11  * Copyright (c) 2001 Scott Long
12  * Copyright (c) 2000 BSDi
13  * All rights reserved.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 #include <sys/modctl.h>
37 #include <sys/conf.h>
38 #include <sys/cmn_err.h>
39 #include <sys/ddi.h>
40 #include <sys/devops.h>
41 #include <sys/pci.h>
42 #include <sys/types.h>
43 #include <sys/ddidmareq.h>
44 #include <sys/scsi/scsi.h>
45 #include <sys/ksynch.h>
46 #include <sys/sunddi.h>
47 #include <sys/byteorder.h>
48 #include "aac_regs.h"
49 #include "aac.h"
50 
51 /*
52  * FMA header files
53  */
54 #include <sys/ddifm.h>
55 #include <sys/fm/protocol.h>
56 #include <sys/fm/util.h>
57 #include <sys/fm/io/ddi.h>
58 
59 /*
60  * For minor nodes created by the SCSA framework, minor numbers are
61  * formed by left-shifting instance by INST_MINOR_SHIFT and OR in a
62  * number less than 64.
63  *
64  * To support cfgadm, need to confirm the SCSA framework by creating
65  * devctl/scsi and driver specific minor nodes under SCSA format,
66  * and calling scsi_hba_xxx() functions aacordingly.
67  */
68 
69 #define	AAC_MINOR		32
70 #define	INST2AAC(x)		(((x) << INST_MINOR_SHIFT) | AAC_MINOR)
71 #define	AAC_SCSA_MINOR(x)	((x) & TRAN_MINOR_MASK)
72 #define	AAC_IS_SCSA_NODE(x)	((x) == DEVCTL_MINOR || (x) == SCSI_MINOR)
73 
74 #define	SD2TRAN(sd)		((sd)->sd_address.a_hba_tran)
75 #define	AAC_TRAN2SOFTS(tran) ((struct aac_softstate *)(tran)->tran_hba_private)
76 #define	AAC_DIP2TRAN(dip)	((scsi_hba_tran_t *)ddi_get_driver_private(dip))
77 #define	AAC_DIP2SOFTS(dip)	(AAC_TRAN2SOFTS(AAC_DIP2TRAN(dip)))
78 #define	SD2AAC(sd)		(AAC_TRAN2SOFTS(SD2TRAN(sd)))
79 #define	AAC_PD(t)		((t) - AAC_MAX_LD)
80 #define	AAC_DEV(softs, t)	(((t) < AAC_MAX_LD) ? \
81 				&(softs)->containers[(t)].dev : \
82 				((t) < AAC_MAX_DEV(softs)) ? \
83 				&(softs)->nondasds[AAC_PD(t)].dev : NULL)
84 #define	AAC_DEVCFG_BEGIN(softs, tgt) \
85 				aac_devcfg((softs), (tgt), 1)
86 #define	AAC_DEVCFG_END(softs, tgt) \
87 				aac_devcfg((softs), (tgt), 0)
88 #define	PKT2AC(pkt)		((struct aac_cmd *)(pkt)->pkt_ha_private)
89 #define	AAC_BUSYWAIT(cond, timeout /* in millisecond */) { \
90 		if (!(cond)) { \
91 			int count = (timeout) * 10; \
92 			while (count) { \
93 				drv_usecwait(100); \
94 				if (cond) \
95 					break; \
96 				count--; \
97 			} \
98 			(timeout) = (count + 9) / 10; \
99 		} \
100 	}
101 
102 #define	AAC_SENSE_DATA_DESCR_LEN \
103 	(sizeof (struct scsi_descr_sense_hdr) + \
104 	sizeof (struct scsi_information_sense_descr))
105 #define	AAC_ARQ64_LENGTH \
106 	(sizeof (struct scsi_arq_status) + \
107 	AAC_SENSE_DATA_DESCR_LEN - SENSE_LENGTH)
108 
109 /* NOTE: GETG4ADDRTL(cdbp) is int32_t */
110 #define	AAC_GETGXADDR(cmdlen, cdbp) \
111 	((cmdlen == 6) ? GETG0ADDR(cdbp) : \
112 	(cmdlen == 10) ? (uint32_t)GETG1ADDR(cdbp) : \
113 	((uint64_t)GETG4ADDR(cdbp) << 32) | (uint32_t)GETG4ADDRTL(cdbp))
114 
115 #define	AAC_CDB_INQUIRY_CMDDT	0x02
116 #define	AAC_CDB_INQUIRY_EVPD	0x01
117 #define	AAC_VPD_PAGE_CODE	1
118 #define	AAC_VPD_PAGE_LENGTH	3
119 #define	AAC_VPD_PAGE_DATA	4
120 #define	AAC_VPD_ID_CODESET	0
121 #define	AAC_VPD_ID_TYPE		1
122 #define	AAC_VPD_ID_LENGTH	3
123 #define	AAC_VPD_ID_DATA		4
124 
125 #define	AAC_SCSI_RPTLUNS_HEAD_SIZE			0x08
126 #define	AAC_SCSI_RPTLUNS_ADDR_SIZE			0x08
127 #define	AAC_SCSI_RPTLUNS_ADDR_MASK			0xC0
128 /* 00b - peripheral device addressing method */
129 #define	AAC_SCSI_RPTLUNS_ADDR_PERIPHERAL		0x00
130 /* 01b - flat space addressing method */
131 #define	AAC_SCSI_RPTLUNS_ADDR_FLAT_SPACE		0x40
132 /* 10b - logical unit addressing method */
133 #define	AAC_SCSI_RPTLUNS_ADDR_LOGICAL_UNIT		0x80
134 
135 /* Return the size of FIB with data part type data_type */
136 #define	AAC_FIB_SIZEOF(data_type) \
137 	(sizeof (struct aac_fib_header) + sizeof (data_type))
138 /* Return the container size defined in mir */
139 #define	AAC_MIR_SIZE(softs, acc, mir) \
140 	(((softs)->flags & AAC_FLAGS_LBA_64BIT) ? \
141 	(uint64_t)ddi_get32((acc), &(mir)->MntObj.Capacity) + \
142 	((uint64_t)ddi_get32((acc), &(mir)->MntObj.CapacityHigh) << 32) : \
143 	(uint64_t)ddi_get32((acc), &(mir)->MntObj.Capacity))
144 
145 /* The last entry of aac_cards[] is for unknown cards */
146 #define	AAC_UNKNOWN_CARD \
147 	(sizeof (aac_cards) / sizeof (struct aac_card_type) - 1)
148 #define	CARD_IS_UNKNOWN(i)	(i == AAC_UNKNOWN_CARD)
149 #define	BUF_IS_READ(bp)		((bp)->b_flags & B_READ)
150 #define	AAC_IS_Q_EMPTY(q)	((q)->q_head == NULL)
151 #define	AAC_CMDQ(acp)		(!((acp)->flags & AAC_CMD_SYNC))
152 
153 #define	PCI_MEM_GET32(softs, off) \
154 	ddi_get32((softs)->pci_mem_handle, \
155 	    (void *)((softs)->pci_mem_base_vaddr + (off)))
156 #define	PCI_MEM_PUT32(softs, off, val) \
157 	ddi_put32((softs)->pci_mem_handle, \
158 	    (void *)((softs)->pci_mem_base_vaddr + (off)), \
159 	    (uint32_t)(val))
160 #define	PCI_MEM_GET16(softs, off) \
161 	ddi_get16((softs)->pci_mem_handle, \
162 	(void *)((softs)->pci_mem_base_vaddr + (off)))
163 #define	PCI_MEM_PUT16(softs, off, val) \
164 	ddi_put16((softs)->pci_mem_handle, \
165 	(void *)((softs)->pci_mem_base_vaddr + (off)), (uint16_t)(val))
166 /* Write host data at valp to device mem[off] repeatedly count times */
167 #define	PCI_MEM_REP_PUT8(softs, off, valp, count) \
168 	ddi_rep_put8((softs)->pci_mem_handle, (uint8_t *)(valp), \
169 	    (uint8_t *)((softs)->pci_mem_base_vaddr + (off)), \
170 	    count, DDI_DEV_AUTOINCR)
171 /* Read device data at mem[off] to host addr valp repeatedly count times */
172 #define	PCI_MEM_REP_GET8(softs, off, valp, count) \
173 	ddi_rep_get8((softs)->pci_mem_handle, (uint8_t *)(valp), \
174 	    (uint8_t *)((softs)->pci_mem_base_vaddr + (off)), \
175 	    count, DDI_DEV_AUTOINCR)
176 #define	AAC_GET_FIELD8(acc, d, s, field) \
177 	(d)->field = ddi_get8(acc, (uint8_t *)&(s)->field)
178 #define	AAC_GET_FIELD32(acc, d, s, field) \
179 	(d)->field = ddi_get32(acc, (uint32_t *)&(s)->field)
180 #define	AAC_GET_FIELD64(acc, d, s, field) \
181 	(d)->field = ddi_get64(acc, (uint64_t *)&(s)->field)
182 #define	AAC_REP_GET_FIELD8(acc, d, s, field, r) \
183 	ddi_rep_get8((acc), (uint8_t *)&(d)->field, \
184 	    (uint8_t *)&(s)->field, (r), DDI_DEV_AUTOINCR)
185 #define	AAC_REP_GET_FIELD32(acc, d, s, field, r) \
186 	ddi_rep_get32((acc), (uint32_t *)&(d)->field, \
187 	    (uint32_t *)&(s)->field, (r), DDI_DEV_AUTOINCR)
188 
189 #define	AAC_ENABLE_INTR(softs) { \
190 		if (softs->flags & AAC_FLAGS_NEW_COMM) \
191 			PCI_MEM_PUT32(softs, AAC_OIMR, ~AAC_DB_INTR_NEW); \
192 		else \
193 			PCI_MEM_PUT32(softs, AAC_OIMR, ~AAC_DB_INTR_BITS); \
194 		softs->state |= AAC_STATE_INTR; \
195 	}
196 
197 #define	AAC_DISABLE_INTR(softs)	{ \
198 		PCI_MEM_PUT32(softs, AAC_OIMR, ~0); \
199 		softs->state &= ~AAC_STATE_INTR; \
200 	}
201 #define	AAC_STATUS_CLR(softs, mask)	PCI_MEM_PUT32(softs, AAC_ODBR, mask)
202 #define	AAC_STATUS_GET(softs)		PCI_MEM_GET32(softs, AAC_ODBR)
203 #define	AAC_NOTIFY(softs, val)		PCI_MEM_PUT32(softs, AAC_IDBR, val)
204 #define	AAC_OUTB_GET(softs)		PCI_MEM_GET32(softs, AAC_OQUE)
205 #define	AAC_OUTB_SET(softs, val)	PCI_MEM_PUT32(softs, AAC_OQUE, val)
206 #define	AAC_FWSTATUS_GET(softs)	\
207 	((softs)->aac_if.aif_get_fwstatus(softs))
208 #define	AAC_MAILBOX_GET(softs, mb) \
209 	((softs)->aac_if.aif_get_mailbox((softs), (mb)))
210 #define	AAC_MAILBOX_SET(softs, cmd, arg0, arg1, arg2, arg3) \
211 	((softs)->aac_if.aif_set_mailbox((softs), (cmd), \
212 	    (arg0), (arg1), (arg2), (arg3)))
213 
214 #define	AAC_MGT_SLOT_NUM	2
215 #define	AAC_THROTTLE_DRAIN	-1
216 
217 #define	AAC_QUIESCE_TICK	1	/* 1 second */
218 #define	AAC_QUIESCE_TIMEOUT	180	/* 180 seconds */
219 #define	AAC_DEFAULT_TICK	10	/* 10 seconds */
220 #define	AAC_SYNC_TICK		(30*60)	/* 30 minutes */
221 
222 /* Poll time for aac_do_poll_io() */
223 #define	AAC_POLL_TIME		60	/* 60 seconds */
224 
225 /* IOP reset */
226 #define	AAC_IOP_RESET_SUCCEED		0	/* IOP reset succeed */
227 #define	AAC_IOP_RESET_FAILED		-1	/* IOP reset failed */
228 #define	AAC_IOP_RESET_ABNORMAL		-2	/* Reset operation abnormal */
229 
230 /*
231  * Hardware access functions
232  */
233 static int aac_rx_get_fwstatus(struct aac_softstate *);
234 static int aac_rx_get_mailbox(struct aac_softstate *, int);
235 static void aac_rx_set_mailbox(struct aac_softstate *, uint32_t, uint32_t,
236     uint32_t, uint32_t, uint32_t);
237 static int aac_rkt_get_fwstatus(struct aac_softstate *);
238 static int aac_rkt_get_mailbox(struct aac_softstate *, int);
239 static void aac_rkt_set_mailbox(struct aac_softstate *, uint32_t, uint32_t,
240     uint32_t, uint32_t, uint32_t);
241 
242 /*
243  * SCSA function prototypes
244  */
245 static int aac_attach(dev_info_t *, ddi_attach_cmd_t);
246 static int aac_detach(dev_info_t *, ddi_detach_cmd_t);
247 static int aac_reset(dev_info_t *, ddi_reset_cmd_t);
248 static int aac_quiesce(dev_info_t *);
249 static int aac_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
250 
251 /*
252  * Interrupt handler functions
253  */
254 static int aac_query_intrs(struct aac_softstate *, int);
255 static int aac_add_intrs(struct aac_softstate *);
256 static void aac_remove_intrs(struct aac_softstate *);
257 static int aac_enable_intrs(struct aac_softstate *);
258 static int aac_disable_intrs(struct aac_softstate *);
259 static uint_t aac_intr_old(caddr_t, caddr_t);
260 static uint_t aac_intr_new(caddr_t, caddr_t);
261 static uint_t aac_softintr(caddr_t);
262 
263 /*
264  * Internal functions in attach
265  */
266 static int aac_check_card_type(struct aac_softstate *);
267 static int aac_check_firmware(struct aac_softstate *);
268 static int aac_common_attach(struct aac_softstate *);
269 static void aac_common_detach(struct aac_softstate *);
270 static int aac_probe_containers(struct aac_softstate *);
271 static int aac_alloc_comm_space(struct aac_softstate *);
272 static int aac_setup_comm_space(struct aac_softstate *);
273 static void aac_free_comm_space(struct aac_softstate *);
274 static int aac_hba_setup(struct aac_softstate *);
275 
276 /*
277  * Sync FIB operation functions
278  */
279 int aac_sync_mbcommand(struct aac_softstate *, uint32_t, uint32_t,
280     uint32_t, uint32_t, uint32_t, uint32_t *);
281 static int aac_sync_fib(struct aac_softstate *, uint16_t, uint16_t);
282 
283 /*
284  * Command queue operation functions
285  */
286 static void aac_cmd_initq(struct aac_cmd_queue *);
287 static void aac_cmd_enqueue(struct aac_cmd_queue *, struct aac_cmd *);
288 static struct aac_cmd *aac_cmd_dequeue(struct aac_cmd_queue *);
289 static void aac_cmd_delete(struct aac_cmd_queue *, struct aac_cmd *);
290 
291 /*
292  * FIB queue operation functions
293  */
294 static int aac_fib_enqueue(struct aac_softstate *, int, uint32_t, uint32_t);
295 static int aac_fib_dequeue(struct aac_softstate *, int, int *);
296 
297 /*
298  * Slot operation functions
299  */
300 static int aac_create_slots(struct aac_softstate *);
301 static void aac_destroy_slots(struct aac_softstate *);
302 static void aac_alloc_fibs(struct aac_softstate *);
303 static void aac_destroy_fibs(struct aac_softstate *);
304 static struct aac_slot *aac_get_slot(struct aac_softstate *);
305 static void aac_release_slot(struct aac_softstate *, struct aac_slot *);
306 static int aac_alloc_fib(struct aac_softstate *, struct aac_slot *);
307 static void aac_free_fib(struct aac_slot *);
308 
309 /*
310  * Internal functions
311  */
312 static void aac_cmd_fib_header(struct aac_softstate *, struct aac_cmd *,
313     uint16_t);
314 static void aac_cmd_fib_rawio(struct aac_softstate *, struct aac_cmd *);
315 static void aac_cmd_fib_brw64(struct aac_softstate *, struct aac_cmd *);
316 static void aac_cmd_fib_brw(struct aac_softstate *, struct aac_cmd *);
317 static void aac_cmd_fib_sync(struct aac_softstate *, struct aac_cmd *);
318 static void aac_cmd_fib_scsi32(struct aac_softstate *, struct aac_cmd *);
319 static void aac_cmd_fib_scsi64(struct aac_softstate *, struct aac_cmd *);
320 static void aac_cmd_fib_startstop(struct aac_softstate *, struct aac_cmd *);
321 static void aac_start_waiting_io(struct aac_softstate *);
322 static void aac_drain_comp_q(struct aac_softstate *);
323 int aac_do_io(struct aac_softstate *, struct aac_cmd *);
324 static int aac_sync_fib_slot_bind(struct aac_softstate *, struct aac_cmd *);
325 static void aac_sync_fib_slot_release(struct aac_softstate *, struct aac_cmd *);
326 static void aac_start_io(struct aac_softstate *, struct aac_cmd *);
327 static int aac_do_poll_io(struct aac_softstate *, struct aac_cmd *);
328 static int aac_do_sync_io(struct aac_softstate *, struct aac_cmd *);
329 static int aac_send_command(struct aac_softstate *, struct aac_slot *);
330 static void aac_cmd_timeout(struct aac_softstate *, struct aac_cmd *);
331 static int aac_dma_sync_ac(struct aac_cmd *);
332 static int aac_shutdown(struct aac_softstate *);
333 static int aac_reset_adapter(struct aac_softstate *);
334 static int aac_do_quiesce(struct aac_softstate *softs);
335 static int aac_do_unquiesce(struct aac_softstate *softs);
336 static void aac_unhold_bus(struct aac_softstate *, int);
337 static void aac_set_throttle(struct aac_softstate *, struct aac_device *,
338     int, int);
339 
340 /*
341  * Adapter Initiated FIB handling function
342  */
343 static void aac_save_aif(struct aac_softstate *, ddi_acc_handle_t,
344     struct aac_fib *, int);
345 static int aac_handle_aif(struct aac_softstate *, struct aac_aif_command *);
346 
347 /*
348  * Event handling related functions
349  */
350 static void aac_timer(void *);
351 static void aac_event_thread(struct aac_softstate *);
352 static void aac_event_disp(struct aac_softstate *, int);
353 
354 /*
355  * IOCTL interface related functions
356  */
357 static int aac_open(dev_t *, int, int, cred_t *);
358 static int aac_close(dev_t, int, int, cred_t *);
359 static int aac_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
360 extern int aac_do_ioctl(struct aac_softstate *, dev_t, int, intptr_t, int);
361 
362 /*
363  * FMA Prototypes
364  */
365 static void aac_fm_init(struct aac_softstate *);
366 static void aac_fm_fini(struct aac_softstate *);
367 static int aac_fm_error_cb(dev_info_t *, ddi_fm_error_t *, const void *);
368 int aac_check_acc_handle(ddi_acc_handle_t);
369 int aac_check_dma_handle(ddi_dma_handle_t);
370 void aac_fm_ereport(struct aac_softstate *, char *);
371 
372 /*
373  * Auto enumeration functions
374  */
375 static dev_info_t *aac_find_child(struct aac_softstate *, uint16_t, uint8_t);
376 static int aac_tran_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t,
377     void *, dev_info_t **);
378 static int aac_handle_dr(struct aac_softstate *, int, int, int);
379 
380 extern pri_t minclsyspri;
381 
382 #ifdef DEBUG
383 /*
384  * UART	debug output support
385  */
386 
387 #define	AAC_PRINT_BUFFER_SIZE		512
388 #define	AAC_PRINT_TIMEOUT		250	/* 1/4 sec. = 250 msec. */
389 
390 #define	AAC_FW_DBG_STRLEN_OFFSET	0x00
391 #define	AAC_FW_DBG_FLAGS_OFFSET		0x04
392 #define	AAC_FW_DBG_BLED_OFFSET		0x08
393 
394 static int aac_get_fw_debug_buffer(struct aac_softstate *);
395 static void aac_print_scmd(struct aac_softstate *, struct aac_cmd *);
396 static void aac_print_aif(struct aac_softstate *, struct aac_aif_command *);
397 
398 static char aac_prt_buf[AAC_PRINT_BUFFER_SIZE];
399 static char aac_fmt[] = " %s";
400 static char aac_fmt_header[] = " %s.%d: %s";
401 static kmutex_t aac_prt_mutex;
402 
403 /*
404  * Debug flags to be put into the softstate flags field
405  * when initialized
406  */
407 uint32_t aac_debug_flags =
408 /*    AACDB_FLAGS_KERNEL_PRINT | */
409 /*    AACDB_FLAGS_FW_PRINT |	*/
410 /*    AACDB_FLAGS_MISC |	*/
411 /*    AACDB_FLAGS_FUNC1 |	*/
412 /*    AACDB_FLAGS_FUNC2 |	*/
413 /*    AACDB_FLAGS_SCMD |	*/
414 /*    AACDB_FLAGS_AIF |		*/
415 /*    AACDB_FLAGS_FIB |		*/
416 /*    AACDB_FLAGS_IOCTL |	*/
417 0;
418 uint32_t aac_debug_fib_flags =
419 /*    AACDB_FLAGS_FIB_RW |	*/
420 /*    AACDB_FLAGS_FIB_IOCTL |	*/
421 /*    AACDB_FLAGS_FIB_SRB |	*/
422 /*    AACDB_FLAGS_FIB_SYNC |	*/
423 /*    AACDB_FLAGS_FIB_HEADER |	*/
424 /*    AACDB_FLAGS_FIB_TIMEOUT |	*/
425 0;
426 
427 #endif /* DEBUG */
428 
429 static struct cb_ops aac_cb_ops = {
430 	aac_open,	/* open */
431 	aac_close,	/* close */
432 	nodev,		/* strategy */
433 	nodev,		/* print */
434 	nodev,		/* dump */
435 	nodev,		/* read */
436 	nodev,		/* write */
437 	aac_ioctl,	/* ioctl */
438 	nodev,		/* devmap */
439 	nodev,		/* mmap */
440 	nodev,		/* segmap */
441 	nochpoll,	/* poll */
442 	ddi_prop_op,	/* cb_prop_op */
443 	NULL,		/* streamtab */
444 	D_64BIT | D_NEW | D_MP | D_HOTPLUG,	/* cb_flag */
445 	CB_REV,		/* cb_rev */
446 	nodev,		/* async I/O read entry point */
447 	nodev		/* async I/O write entry point */
448 };
449 
450 static struct dev_ops aac_dev_ops = {
451 	DEVO_REV,
452 	0,
453 	aac_getinfo,
454 	nulldev,
455 	nulldev,
456 	aac_attach,
457 	aac_detach,
458 	aac_reset,
459 	&aac_cb_ops,
460 	NULL,
461 	NULL,
462 	aac_quiesce,
463 };
464 
465 static struct modldrv aac_modldrv = {
466 	&mod_driverops,
467 	"AAC Driver " AAC_DRIVER_VERSION,
468 	&aac_dev_ops,
469 };
470 
471 static struct modlinkage aac_modlinkage = {
472 	MODREV_1,
473 	&aac_modldrv,
474 	NULL
475 };
476 
477 static struct aac_softstate  *aac_softstatep;
478 
479 /*
480  * Supported card list
481  * ordered in vendor id, subvendor id, subdevice id, and device id
482  */
483 static struct aac_card_type aac_cards[] = {
484 	{0x1028, 0x1, 0x1028, 0x1, AAC_HWIF_I960RX,
485 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
486 	    "Dell", "PERC 3/Di"},
487 	{0x1028, 0x2, 0x1028, 0x2, AAC_HWIF_I960RX,
488 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
489 	    "Dell", "PERC 3/Di"},
490 	{0x1028, 0x3, 0x1028, 0x3, AAC_HWIF_I960RX,
491 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
492 	    "Dell", "PERC 3/Si"},
493 	{0x1028, 0x8, 0x1028, 0xcf, AAC_HWIF_I960RX,
494 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
495 	    "Dell", "PERC 3/Di"},
496 	{0x1028, 0x4, 0x1028, 0xd0, AAC_HWIF_I960RX,
497 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
498 	    "Dell", "PERC 3/Si"},
499 	{0x1028, 0x2, 0x1028, 0xd1, AAC_HWIF_I960RX,
500 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
501 	    "Dell", "PERC 3/Di"},
502 	{0x1028, 0x2, 0x1028, 0xd9, AAC_HWIF_I960RX,
503 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
504 	    "Dell", "PERC 3/Di"},
505 	{0x1028, 0xa, 0x1028, 0x106, AAC_HWIF_I960RX,
506 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
507 	    "Dell", "PERC 3/Di"},
508 	{0x1028, 0xa, 0x1028, 0x11b, AAC_HWIF_I960RX,
509 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
510 	    "Dell", "PERC 3/Di"},
511 	{0x1028, 0xa, 0x1028, 0x121, AAC_HWIF_I960RX,
512 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
513 	    "Dell", "PERC 3/Di"},
514 	{0x9005, 0x285, 0x1028, 0x287, AAC_HWIF_I960RX,
515 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
516 	    "Dell", "PERC 320/DC"},
517 	{0x9005, 0x285, 0x1028, 0x291, AAC_HWIF_I960RX,
518 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Dell", "CERC SR2"},
519 
520 	{0x9005, 0x285, 0x1014, 0x2f2, AAC_HWIF_I960RX,
521 	    0, AAC_TYPE_SCSI, "IBM", "ServeRAID 8i"},
522 	{0x9005, 0x285, 0x1014, 0x34d, AAC_HWIF_I960RX,
523 	    0, AAC_TYPE_SAS, "IBM", "ServeRAID 8s"},
524 	{0x9005, 0x286, 0x1014, 0x9580, AAC_HWIF_RKT,
525 	    0, AAC_TYPE_SAS, "IBM", "ServeRAID 8k"},
526 
527 	{0x9005, 0x285, 0x103c, 0x3227, AAC_HWIF_I960RX,
528 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2610SA"},
529 	{0x9005, 0x285, 0xe11, 0x295, AAC_HWIF_I960RX,
530 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2610SA"},
531 
532 	{0x9005, 0x285, 0x9005, 0x285, AAC_HWIF_I960RX,
533 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
534 	    "Adaptec", "2200S"},
535 	{0x9005, 0x285, 0x9005, 0x286, AAC_HWIF_I960RX,
536 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
537 	    "Adaptec", "2120S"},
538 	{0x9005, 0x285, 0x9005, 0x287, AAC_HWIF_I960RX,
539 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
540 	    "Adaptec", "2200S"},
541 	{0x9005, 0x285, 0x9005, 0x288, AAC_HWIF_I960RX,
542 	    0, AAC_TYPE_SCSI, "Adaptec", "3230S"},
543 	{0x9005, 0x285, 0x9005, 0x289, AAC_HWIF_I960RX,
544 	    0, AAC_TYPE_SCSI, "Adaptec", "3240S"},
545 	{0x9005, 0x285, 0x9005, 0x28a, AAC_HWIF_I960RX,
546 	    0, AAC_TYPE_SCSI, "Adaptec", "2020ZCR"},
547 	{0x9005, 0x285, 0x9005, 0x28b, AAC_HWIF_I960RX,
548 	    0, AAC_TYPE_SCSI, "Adaptec", "2025ZCR"},
549 	{0x9005, 0x286, 0x9005, 0x28c, AAC_HWIF_RKT,
550 	    0, AAC_TYPE_SCSI, "Adaptec", "2230S"},
551 	{0x9005, 0x286, 0x9005, 0x28d, AAC_HWIF_RKT,
552 	    0, AAC_TYPE_SCSI, "Adaptec", "2130S"},
553 	{0x9005, 0x285, 0x9005, 0x28e, AAC_HWIF_I960RX,
554 	    0, AAC_TYPE_SATA, "Adaptec", "2020SA"},
555 	{0x9005, 0x285, 0x9005, 0x28f, AAC_HWIF_I960RX,
556 	    0, AAC_TYPE_SATA, "Adaptec", "2025SA"},
557 	{0x9005, 0x285, 0x9005, 0x290, AAC_HWIF_I960RX,
558 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2410SA"},
559 	{0x9005, 0x285, 0x9005, 0x292, AAC_HWIF_I960RX,
560 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2810SA"},
561 	{0x9005, 0x285, 0x9005, 0x293, AAC_HWIF_I960RX,
562 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "21610SA"},
563 	{0x9005, 0x285, 0x9005, 0x294, AAC_HWIF_I960RX,
564 	    0, AAC_TYPE_SATA, "Adaptec", "2026ZCR"},
565 	{0x9005, 0x285, 0x9005, 0x296, AAC_HWIF_I960RX,
566 	    0, AAC_TYPE_SCSI, "Adaptec", "2240S"},
567 	{0x9005, 0x285, 0x9005, 0x297, AAC_HWIF_I960RX,
568 	    0, AAC_TYPE_SAS, "Adaptec", "4005SAS"},
569 	{0x9005, 0x285, 0x9005, 0x298, AAC_HWIF_I960RX,
570 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 4000"},
571 	{0x9005, 0x285, 0x9005, 0x299, AAC_HWIF_I960RX,
572 	    0, AAC_TYPE_SAS, "Adaptec", "4800SAS"},
573 	{0x9005, 0x285, 0x9005, 0x29a, AAC_HWIF_I960RX,
574 	    0, AAC_TYPE_SAS, "Adaptec", "4805SAS"},
575 	{0x9005, 0x286, 0x9005, 0x29b, AAC_HWIF_RKT,
576 	    0, AAC_TYPE_SATA, "Adaptec", "2820SA"},
577 	{0x9005, 0x286, 0x9005, 0x29c, AAC_HWIF_RKT,
578 	    0, AAC_TYPE_SATA, "Adaptec", "2620SA"},
579 	{0x9005, 0x286, 0x9005, 0x29d, AAC_HWIF_RKT,
580 	    0, AAC_TYPE_SATA, "Adaptec", "2420SA"},
581 	{0x9005, 0x286, 0x9005, 0x29e, AAC_HWIF_RKT,
582 	    0, AAC_TYPE_SATA, "ICP", "9024RO"},
583 	{0x9005, 0x286, 0x9005, 0x29f, AAC_HWIF_RKT,
584 	    0, AAC_TYPE_SATA, "ICP", "9014RO"},
585 	{0x9005, 0x286, 0x9005, 0x2a0, AAC_HWIF_RKT,
586 	    0, AAC_TYPE_SATA, "ICP", "9047MA"},
587 	{0x9005, 0x286, 0x9005, 0x2a1, AAC_HWIF_RKT,
588 	    0, AAC_TYPE_SATA, "ICP", "9087MA"},
589 	{0x9005, 0x285, 0x9005, 0x2a4, AAC_HWIF_I960RX,
590 	    0, AAC_TYPE_SAS, "ICP", "9085LI"},
591 	{0x9005, 0x285, 0x9005, 0x2a5, AAC_HWIF_I960RX,
592 	    0, AAC_TYPE_SAS, "ICP", "5085BR"},
593 	{0x9005, 0x286, 0x9005, 0x2a6, AAC_HWIF_RKT,
594 	    0, AAC_TYPE_SATA, "ICP", "9067MA"},
595 	{0x9005, 0x285, 0x9005, 0x2b5, AAC_HWIF_I960RX,
596 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5445"},
597 	{0x9005, 0x285, 0x9005, 0x2b6, AAC_HWIF_I960RX,
598 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5805"},
599 	{0x9005, 0x285, 0x9005, 0x2b7, AAC_HWIF_I960RX,
600 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5085"},
601 	{0x9005, 0x285, 0x9005, 0x2b8, AAC_HWIF_I960RX,
602 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5445SL"},
603 	{0x9005, 0x285, 0x9005, 0x2b9, AAC_HWIF_I960RX,
604 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5085SL"},
605 	{0x9005, 0x285, 0x9005, 0x2ba, AAC_HWIF_I960RX,
606 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5805SL"},
607 
608 	{0, 0, 0, 0, AAC_HWIF_UNKNOWN,
609 	    0, AAC_TYPE_UNKNOWN, "Unknown", "AAC card"},
610 };
611 
612 /*
613  * Hardware access functions for i960 based cards
614  */
615 static struct aac_interface aac_rx_interface = {
616 	aac_rx_get_fwstatus,
617 	aac_rx_get_mailbox,
618 	aac_rx_set_mailbox
619 };
620 
621 /*
622  * Hardware access functions for Rocket based cards
623  */
624 static struct aac_interface aac_rkt_interface = {
625 	aac_rkt_get_fwstatus,
626 	aac_rkt_get_mailbox,
627 	aac_rkt_set_mailbox
628 };
629 
630 ddi_device_acc_attr_t aac_acc_attr = {
631 	DDI_DEVICE_ATTR_V1,
632 	DDI_STRUCTURE_LE_ACC,
633 	DDI_STRICTORDER_ACC,
634 	DDI_DEFAULT_ACC
635 };
636 
637 static struct {
638 	int	size;
639 	int	notify;
640 } aac_qinfo[] = {
641 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
642 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
643 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
644 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
645 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
646 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
647 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
648 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
649 };
650 
651 /*
652  * Default aac dma attributes
653  */
654 static ddi_dma_attr_t aac_dma_attr = {
655 	DMA_ATTR_V0,
656 	0,		/* lowest usable address */
657 	0xffffffffull,	/* high DMA address range */
658 	0xffffffffull,	/* DMA counter register */
659 	AAC_DMA_ALIGN,	/* DMA address alignment */
660 	1,		/* DMA burstsizes */
661 	1,		/* min effective DMA size */
662 	0xffffffffull,	/* max DMA xfer size */
663 	0xffffffffull,	/* segment boundary */
664 	1,		/* s/g list length */
665 	AAC_BLK_SIZE,	/* granularity of device */
666 	0		/* DMA transfer flags */
667 };
668 
669 static int aac_tick = AAC_DEFAULT_TICK;	/* tick for the internal timer */
670 static uint32_t aac_timebase = 0;	/* internal timer in seconds */
671 
672 /*
673  * Warlock directives
674  *
675  * Different variables with the same types have to be protected by the
676  * same mutex; otherwise, warlock will complain with "variables don't
677  * seem to be protected consistently". For example,
678  * aac_softstate::{q_wait, q_comp} are type of aac_cmd_queue, and protected
679  * by aac_softstate::{io_lock, q_comp_mutex} respectively. We have to
680  * declare them as protected explictly at aac_cmd_dequeue().
681  */
682 _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_pkt scsi_cdb scsi_status \
683     scsi_arq_status scsi_descr_sense_hdr scsi_information_sense_descr \
684     mode_format mode_geometry mode_header aac_cmd))
685 _NOTE(SCHEME_PROTECTS_DATA("unique per aac_cmd", aac_fib ddi_dma_cookie_t \
686     aac_sge))
687 _NOTE(SCHEME_PROTECTS_DATA("unique per aac_fib", aac_blockread aac_blockwrite \
688     aac_blockread64 aac_raw_io aac_sg_entry aac_sg_entry64 aac_sg_entryraw \
689     aac_sg_table aac_srb))
690 _NOTE(SCHEME_PROTECTS_DATA("unique to sync fib and cdb", scsi_inquiry))
691 _NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_device scsi_address))
692 _NOTE(SCHEME_PROTECTS_DATA("unique to scsi_transport", buf))
693 
694 int
_init(void)695 _init(void)
696 {
697 	int rval = 0;
698 
699 #ifdef DEBUG
700 	mutex_init(&aac_prt_mutex, NULL, MUTEX_DRIVER, NULL);
701 #endif
702 	DBCALLED(NULL, 1);
703 
704 	if ((rval = ddi_soft_state_init((void *)&aac_softstatep,
705 	    sizeof (struct aac_softstate), 0)) != 0)
706 		goto error;
707 
708 	if ((rval = scsi_hba_init(&aac_modlinkage)) != 0) {
709 		ddi_soft_state_fini((void *)&aac_softstatep);
710 		goto error;
711 	}
712 
713 	if ((rval = mod_install(&aac_modlinkage)) != 0) {
714 		ddi_soft_state_fini((void *)&aac_softstatep);
715 		scsi_hba_fini(&aac_modlinkage);
716 		goto error;
717 	}
718 	return (rval);
719 
720 error:
721 	AACDB_PRINT(NULL, CE_WARN, "Mod init error!");
722 #ifdef DEBUG
723 	mutex_destroy(&aac_prt_mutex);
724 #endif
725 	return (rval);
726 }
727 
728 int
_info(struct modinfo * modinfop)729 _info(struct modinfo *modinfop)
730 {
731 	DBCALLED(NULL, 1);
732 	return (mod_info(&aac_modlinkage, modinfop));
733 }
734 
735 /*
736  * An HBA driver cannot be unload unless you reboot,
737  * so this function will be of no use.
738  */
739 int
_fini(void)740 _fini(void)
741 {
742 	int rval;
743 
744 	DBCALLED(NULL, 1);
745 
746 	if ((rval = mod_remove(&aac_modlinkage)) != 0)
747 		goto error;
748 
749 	scsi_hba_fini(&aac_modlinkage);
750 	ddi_soft_state_fini((void *)&aac_softstatep);
751 #ifdef DEBUG
752 	mutex_destroy(&aac_prt_mutex);
753 #endif
754 	return (0);
755 
756 error:
757 	AACDB_PRINT(NULL, CE_WARN, "AAC is busy, cannot unload!");
758 	return (rval);
759 }
760 
761 static int
aac_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)762 aac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
763 {
764 	int instance, i;
765 	struct aac_softstate *softs = NULL;
766 	int attach_state = 0;
767 	char *data;
768 
769 	DBCALLED(NULL, 1);
770 
771 	switch (cmd) {
772 	case DDI_ATTACH:
773 		break;
774 	case DDI_RESUME:
775 		return (DDI_FAILURE);
776 	default:
777 		return (DDI_FAILURE);
778 	}
779 
780 	instance = ddi_get_instance(dip);
781 
782 	/* Get soft state */
783 	if (ddi_soft_state_zalloc(aac_softstatep, instance) != DDI_SUCCESS) {
784 		AACDB_PRINT(softs, CE_WARN, "Cannot alloc soft state");
785 		goto error;
786 	}
787 	softs = ddi_get_soft_state(aac_softstatep, instance);
788 	attach_state |= AAC_ATTACH_SOFTSTATE_ALLOCED;
789 
790 	softs->instance = instance;
791 	softs->devinfo_p = dip;
792 	softs->buf_dma_attr = softs->addr_dma_attr = aac_dma_attr;
793 	softs->addr_dma_attr.dma_attr_granular = 1;
794 	softs->acc_attr = aac_acc_attr;
795 	softs->reg_attr = aac_acc_attr;
796 	softs->card = AAC_UNKNOWN_CARD;
797 #ifdef DEBUG
798 	softs->debug_flags = aac_debug_flags;
799 	softs->debug_fib_flags = aac_debug_fib_flags;
800 #endif
801 
802 	/* Initialize FMA */
803 	aac_fm_init(softs);
804 
805 	/* Check the card type */
806 	if (aac_check_card_type(softs) == AACERR) {
807 		AACDB_PRINT(softs, CE_WARN, "Card not supported");
808 		goto error;
809 	}
810 	/* We have found the right card and everything is OK */
811 	attach_state |= AAC_ATTACH_CARD_DETECTED;
812 
813 	/* Map PCI mem space */
814 	if (ddi_regs_map_setup(dip, 1,
815 	    (caddr_t *)&softs->pci_mem_base_vaddr, 0,
816 	    softs->map_size_min, &softs->reg_attr,
817 	    &softs->pci_mem_handle) != DDI_SUCCESS)
818 		goto error;
819 
820 	softs->map_size = softs->map_size_min;
821 	attach_state |= AAC_ATTACH_PCI_MEM_MAPPED;
822 
823 	AAC_DISABLE_INTR(softs);
824 
825 	/* Init mutexes and condvars */
826 	mutex_init(&softs->io_lock, NULL, MUTEX_DRIVER,
827 	    DDI_INTR_PRI(softs->intr_pri));
828 	mutex_init(&softs->q_comp_mutex, NULL, MUTEX_DRIVER,
829 	    DDI_INTR_PRI(softs->intr_pri));
830 	mutex_init(&softs->time_mutex, NULL, MUTEX_DRIVER,
831 	    DDI_INTR_PRI(softs->intr_pri));
832 	mutex_init(&softs->ev_lock, NULL, MUTEX_DRIVER,
833 	    DDI_INTR_PRI(softs->intr_pri));
834 	mutex_init(&softs->aifq_mutex, NULL,
835 	    MUTEX_DRIVER, DDI_INTR_PRI(softs->intr_pri));
836 	cv_init(&softs->event, NULL, CV_DRIVER, NULL);
837 	cv_init(&softs->sync_fib_cv, NULL, CV_DRIVER, NULL);
838 	cv_init(&softs->drain_cv, NULL, CV_DRIVER, NULL);
839 	cv_init(&softs->event_wait_cv, NULL, CV_DRIVER, NULL);
840 	cv_init(&softs->event_disp_cv, NULL, CV_DRIVER, NULL);
841 	cv_init(&softs->aifq_cv, NULL, CV_DRIVER, NULL);
842 	attach_state |= AAC_ATTACH_KMUTEX_INITED;
843 
844 	/* Init the cmd queues */
845 	for (i = 0; i < AAC_CMDQ_NUM; i++)
846 		aac_cmd_initq(&softs->q_wait[i]);
847 	aac_cmd_initq(&softs->q_busy);
848 	aac_cmd_initq(&softs->q_comp);
849 
850 	/* Check for legacy device naming support */
851 	softs->legacy = 1; /* default to use legacy name */
852 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
853 	    "legacy-name-enable", &data) == DDI_SUCCESS)) {
854 		if (strcmp(data, "no") == 0) {
855 			AACDB_PRINT(softs, CE_NOTE, "legacy-name disabled");
856 			softs->legacy = 0;
857 		}
858 		ddi_prop_free(data);
859 	}
860 
861 	/*
862 	 * Everything has been set up till now,
863 	 * we will do some common attach.
864 	 */
865 	mutex_enter(&softs->io_lock);
866 	if (aac_common_attach(softs) == AACERR) {
867 		mutex_exit(&softs->io_lock);
868 		goto error;
869 	}
870 	mutex_exit(&softs->io_lock);
871 	attach_state |= AAC_ATTACH_COMM_SPACE_SETUP;
872 
873 	/* Check for buf breakup support */
874 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
875 	    "breakup-enable", &data) == DDI_SUCCESS)) {
876 		if (strcmp(data, "yes") == 0) {
877 			AACDB_PRINT(softs, CE_NOTE, "buf breakup enabled");
878 			softs->flags |= AAC_FLAGS_BRKUP;
879 		}
880 		ddi_prop_free(data);
881 	}
882 	softs->dma_max = softs->buf_dma_attr.dma_attr_maxxfer;
883 	if (softs->flags & AAC_FLAGS_BRKUP) {
884 		softs->dma_max = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
885 		    DDI_PROP_DONTPASS, "dma-max", softs->dma_max);
886 	}
887 
888 	if (aac_hba_setup(softs) != AACOK)
889 		goto error;
890 	attach_state |= AAC_ATTACH_SCSI_TRAN_SETUP;
891 
892 	/* Create devctl/scsi nodes for cfgadm */
893 	if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
894 	    INST2DEVCTL(instance), DDI_NT_SCSI_NEXUS, 0) != DDI_SUCCESS) {
895 		AACDB_PRINT(softs, CE_WARN, "failed to create devctl node");
896 		goto error;
897 	}
898 	attach_state |= AAC_ATTACH_CREATE_DEVCTL;
899 
900 	if (ddi_create_minor_node(dip, "scsi", S_IFCHR, INST2SCSI(instance),
901 	    DDI_NT_SCSI_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
902 		AACDB_PRINT(softs, CE_WARN, "failed to create scsi node");
903 		goto error;
904 	}
905 	attach_state |= AAC_ATTACH_CREATE_SCSI;
906 
907 	/* Create aac node for app. to issue ioctls */
908 	if (ddi_create_minor_node(dip, "aac", S_IFCHR, INST2AAC(instance),
909 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
910 		AACDB_PRINT(softs, CE_WARN, "failed to create aac node");
911 		goto error;
912 	}
913 
914 	/* Common attach is OK, so we are attached! */
915 	softs->state |= AAC_STATE_RUN;
916 
917 	/* Create event thread */
918 	softs->fibctx_p = &softs->aifctx;
919 	if ((softs->event_thread = thread_create(NULL, 0, aac_event_thread,
920 	    softs, 0, &p0, TS_RUN, minclsyspri)) == NULL) {
921 		AACDB_PRINT(softs, CE_WARN, "aif thread create failed");
922 		softs->state &= ~AAC_STATE_RUN;
923 		goto error;
924 	}
925 
926 	aac_unhold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
927 
928 	/* Create a thread for command timeout */
929 	softs->timeout_id = timeout(aac_timer, (void *)softs,
930 	    (aac_tick * drv_usectohz(1000000)));
931 
932 	/* Common attach is OK, so we are attached! */
933 	ddi_report_dev(dip);
934 	AACDB_PRINT(softs, CE_NOTE, "aac attached ok");
935 	return (DDI_SUCCESS);
936 
937 error:
938 	if (attach_state & AAC_ATTACH_CREATE_SCSI)
939 		ddi_remove_minor_node(dip, "scsi");
940 	if (attach_state & AAC_ATTACH_CREATE_DEVCTL)
941 		ddi_remove_minor_node(dip, "devctl");
942 	if (attach_state & AAC_ATTACH_COMM_SPACE_SETUP)
943 		aac_common_detach(softs);
944 	if (attach_state & AAC_ATTACH_SCSI_TRAN_SETUP) {
945 		(void) scsi_hba_detach(dip);
946 		scsi_hba_tran_free(AAC_DIP2TRAN(dip));
947 	}
948 	if (attach_state & AAC_ATTACH_KMUTEX_INITED) {
949 		mutex_destroy(&softs->io_lock);
950 		mutex_destroy(&softs->q_comp_mutex);
951 		mutex_destroy(&softs->time_mutex);
952 		mutex_destroy(&softs->ev_lock);
953 		mutex_destroy(&softs->aifq_mutex);
954 		cv_destroy(&softs->event);
955 		cv_destroy(&softs->sync_fib_cv);
956 		cv_destroy(&softs->drain_cv);
957 		cv_destroy(&softs->event_wait_cv);
958 		cv_destroy(&softs->event_disp_cv);
959 		cv_destroy(&softs->aifq_cv);
960 	}
961 	if (attach_state & AAC_ATTACH_PCI_MEM_MAPPED)
962 		ddi_regs_map_free(&softs->pci_mem_handle);
963 	aac_fm_fini(softs);
964 	if (attach_state & AAC_ATTACH_CARD_DETECTED)
965 		softs->card = AACERR;
966 	if (attach_state & AAC_ATTACH_SOFTSTATE_ALLOCED)
967 		ddi_soft_state_free(aac_softstatep, instance);
968 	return (DDI_FAILURE);
969 }
970 
971 static int
aac_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)972 aac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
973 {
974 	scsi_hba_tran_t *tran = AAC_DIP2TRAN(dip);
975 	struct aac_softstate *softs = AAC_TRAN2SOFTS(tran);
976 
977 	DBCALLED(softs, 1);
978 
979 	switch (cmd) {
980 	case DDI_DETACH:
981 		break;
982 	case DDI_SUSPEND:
983 		return (DDI_FAILURE);
984 	default:
985 		return (DDI_FAILURE);
986 	}
987 
988 	mutex_enter(&softs->io_lock);
989 	AAC_DISABLE_INTR(softs);
990 	softs->state = AAC_STATE_STOPPED;
991 
992 	ddi_remove_minor_node(dip, "aac");
993 	ddi_remove_minor_node(dip, "scsi");
994 	ddi_remove_minor_node(dip, "devctl");
995 	mutex_exit(&softs->io_lock);
996 
997 	aac_common_detach(softs);
998 
999 	mutex_enter(&softs->io_lock);
1000 	(void) scsi_hba_detach(dip);
1001 	scsi_hba_tran_free(tran);
1002 	mutex_exit(&softs->io_lock);
1003 
1004 	/* Stop timer */
1005 	mutex_enter(&softs->time_mutex);
1006 	if (softs->timeout_id) {
1007 		timeout_id_t tid = softs->timeout_id;
1008 		softs->timeout_id = 0;
1009 
1010 		mutex_exit(&softs->time_mutex);
1011 		(void) untimeout(tid);
1012 		mutex_enter(&softs->time_mutex);
1013 	}
1014 	mutex_exit(&softs->time_mutex);
1015 
1016 	/* Destroy event thread */
1017 	mutex_enter(&softs->ev_lock);
1018 	cv_signal(&softs->event_disp_cv);
1019 	cv_wait(&softs->event_wait_cv, &softs->ev_lock);
1020 	mutex_exit(&softs->ev_lock);
1021 
1022 	cv_destroy(&softs->aifq_cv);
1023 	cv_destroy(&softs->event_disp_cv);
1024 	cv_destroy(&softs->event_wait_cv);
1025 	cv_destroy(&softs->drain_cv);
1026 	cv_destroy(&softs->sync_fib_cv);
1027 	cv_destroy(&softs->event);
1028 	mutex_destroy(&softs->aifq_mutex);
1029 	mutex_destroy(&softs->ev_lock);
1030 	mutex_destroy(&softs->time_mutex);
1031 	mutex_destroy(&softs->q_comp_mutex);
1032 	mutex_destroy(&softs->io_lock);
1033 
1034 	ddi_regs_map_free(&softs->pci_mem_handle);
1035 	aac_fm_fini(softs);
1036 	softs->hwif = AAC_HWIF_UNKNOWN;
1037 	softs->card = AAC_UNKNOWN_CARD;
1038 	ddi_soft_state_free(aac_softstatep, ddi_get_instance(dip));
1039 
1040 	return (DDI_SUCCESS);
1041 }
1042 
1043 /*ARGSUSED*/
1044 static int
aac_reset(dev_info_t * dip,ddi_reset_cmd_t cmd)1045 aac_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
1046 {
1047 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
1048 
1049 	DBCALLED(softs, 1);
1050 
1051 	mutex_enter(&softs->io_lock);
1052 	AAC_DISABLE_INTR(softs);
1053 	(void) aac_shutdown(softs);
1054 	mutex_exit(&softs->io_lock);
1055 
1056 	return (DDI_SUCCESS);
1057 }
1058 
1059 /*
1060  * quiesce(9E) entry point.
1061  *
1062  * This function is called when the system is single-threaded at high
1063  * PIL with preemption disabled. Therefore, this function must not be
1064  * blocked.
1065  *
1066  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
1067  * DDI_FAILURE indicates an error condition and should almost never happen.
1068  */
1069 static int
aac_quiesce(dev_info_t * dip)1070 aac_quiesce(dev_info_t *dip)
1071 {
1072 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
1073 
1074 	if (softs == NULL)
1075 		return (DDI_FAILURE);
1076 
1077 	_NOTE(ASSUMING_PROTECTED(softs->state))
1078 	AAC_DISABLE_INTR(softs);
1079 
1080 	return (DDI_SUCCESS);
1081 }
1082 
1083 /* ARGSUSED */
1084 static int
aac_getinfo(dev_info_t * self,ddi_info_cmd_t infocmd,void * arg,void ** result)1085 aac_getinfo(dev_info_t *self, ddi_info_cmd_t infocmd, void *arg,
1086     void **result)
1087 {
1088 	int error = DDI_SUCCESS;
1089 
1090 	switch (infocmd) {
1091 	case DDI_INFO_DEVT2INSTANCE:
1092 		*result = (void *)(intptr_t)(MINOR2INST(getminor((dev_t)arg)));
1093 		break;
1094 	default:
1095 		error = DDI_FAILURE;
1096 	}
1097 	return (error);
1098 }
1099 
1100 /*
1101  * Bring the controller down to a dormant state and detach all child devices.
1102  * This function is called before detach or system shutdown.
1103  * Note: we can assume that the q_wait on the controller is empty, as we
1104  * won't allow shutdown if any device is open.
1105  */
1106 static int
aac_shutdown(struct aac_softstate * softs)1107 aac_shutdown(struct aac_softstate *softs)
1108 {
1109 	ddi_acc_handle_t acc;
1110 	struct aac_close_command *cc;
1111 	int rval;
1112 
1113 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
1114 	acc = softs->sync_ac.slotp->fib_acc_handle;
1115 
1116 	cc = (struct aac_close_command *)&softs->sync_ac.slotp->fibp->data[0];
1117 
1118 	ddi_put32(acc, &cc->Command, VM_CloseAll);
1119 	ddi_put32(acc, &cc->ContainerId, 0xfffffffful);
1120 
1121 	/* Flush all caches, set FW to write through mode */
1122 	rval = aac_sync_fib(softs, ContainerCommand,
1123 	    AAC_FIB_SIZEOF(struct aac_close_command));
1124 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
1125 
1126 	AACDB_PRINT(softs, CE_NOTE,
1127 	    "shutting down aac %s", (rval == AACOK) ? "ok" : "fail");
1128 	return (rval);
1129 }
1130 
1131 static uint_t
aac_softintr(caddr_t arg)1132 aac_softintr(caddr_t arg)
1133 {
1134 	struct aac_softstate *softs = (void *)arg;
1135 
1136 	if (!AAC_IS_Q_EMPTY(&softs->q_comp)) {
1137 		aac_drain_comp_q(softs);
1138 	}
1139 	return (DDI_INTR_CLAIMED);
1140 }
1141 
1142 /*
1143  * Setup auto sense data for pkt
1144  */
1145 static void
aac_set_arq_data(struct scsi_pkt * pkt,uchar_t key,uchar_t add_code,uchar_t qual_code,uint64_t info)1146 aac_set_arq_data(struct scsi_pkt *pkt, uchar_t key,
1147     uchar_t add_code, uchar_t qual_code, uint64_t info)
1148 {
1149 	struct scsi_arq_status *arqstat = (void *)(pkt->pkt_scbp);
1150 
1151 	*pkt->pkt_scbp = STATUS_CHECK; /* CHECK CONDITION */
1152 	pkt->pkt_state |= STATE_ARQ_DONE;
1153 
1154 	*(uint8_t *)&arqstat->sts_rqpkt_status = STATUS_GOOD;
1155 	arqstat->sts_rqpkt_reason = CMD_CMPLT;
1156 	arqstat->sts_rqpkt_resid = 0;
1157 	arqstat->sts_rqpkt_state =
1158 	    STATE_GOT_BUS |
1159 	    STATE_GOT_TARGET |
1160 	    STATE_SENT_CMD |
1161 	    STATE_XFERRED_DATA;
1162 	arqstat->sts_rqpkt_statistics = 0;
1163 
1164 	if (info <= 0xfffffffful) {
1165 		arqstat->sts_sensedata.es_valid = 1;
1166 		arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
1167 		arqstat->sts_sensedata.es_code = CODE_FMT_FIXED_CURRENT;
1168 		arqstat->sts_sensedata.es_key = key;
1169 		arqstat->sts_sensedata.es_add_code = add_code;
1170 		arqstat->sts_sensedata.es_qual_code = qual_code;
1171 
1172 		arqstat->sts_sensedata.es_info_1 = (info >> 24) & 0xFF;
1173 		arqstat->sts_sensedata.es_info_2 = (info >> 16) & 0xFF;
1174 		arqstat->sts_sensedata.es_info_3 = (info >>  8) & 0xFF;
1175 		arqstat->sts_sensedata.es_info_4 = info & 0xFF;
1176 	} else { /* 64-bit LBA */
1177 		struct scsi_descr_sense_hdr *dsp;
1178 		struct scsi_information_sense_descr *isd;
1179 
1180 		dsp = (struct scsi_descr_sense_hdr *)&arqstat->sts_sensedata;
1181 		dsp->ds_class = CLASS_EXTENDED_SENSE;
1182 		dsp->ds_code = CODE_FMT_DESCR_CURRENT;
1183 		dsp->ds_key = key;
1184 		dsp->ds_add_code = add_code;
1185 		dsp->ds_qual_code = qual_code;
1186 		dsp->ds_addl_sense_length =
1187 		    sizeof (struct scsi_information_sense_descr);
1188 
1189 		isd = (struct scsi_information_sense_descr *)(dsp+1);
1190 		isd->isd_descr_type = DESCR_INFORMATION;
1191 		isd->isd_valid = 1;
1192 		isd->isd_information[0] = (info >> 56) & 0xFF;
1193 		isd->isd_information[1] = (info >> 48) & 0xFF;
1194 		isd->isd_information[2] = (info >> 40) & 0xFF;
1195 		isd->isd_information[3] = (info >> 32) & 0xFF;
1196 		isd->isd_information[4] = (info >> 24) & 0xFF;
1197 		isd->isd_information[5] = (info >> 16) & 0xFF;
1198 		isd->isd_information[6] = (info >>  8) & 0xFF;
1199 		isd->isd_information[7] = (info) & 0xFF;
1200 	}
1201 }
1202 
1203 /*
1204  * Setup auto sense data for HARDWARE ERROR
1205  */
1206 static void
aac_set_arq_data_hwerr(struct aac_cmd * acp)1207 aac_set_arq_data_hwerr(struct aac_cmd *acp)
1208 {
1209 	union scsi_cdb *cdbp;
1210 	uint64_t err_blkno;
1211 
1212 	cdbp = (void *)acp->pkt->pkt_cdbp;
1213 	err_blkno = AAC_GETGXADDR(acp->cmdlen, cdbp);
1214 	aac_set_arq_data(acp->pkt, KEY_HARDWARE_ERROR, 0x00, 0x00, err_blkno);
1215 }
1216 
1217 /*
1218  * Send a command to the adapter in New Comm. interface
1219  */
1220 static int
aac_send_command(struct aac_softstate * softs,struct aac_slot * slotp)1221 aac_send_command(struct aac_softstate *softs, struct aac_slot *slotp)
1222 {
1223 	uint32_t index, device;
1224 
1225 	index = PCI_MEM_GET32(softs, AAC_IQUE);
1226 	if (index == 0xffffffffUL) {
1227 		index = PCI_MEM_GET32(softs, AAC_IQUE);
1228 		if (index == 0xffffffffUL)
1229 			return (AACERR);
1230 	}
1231 
1232 	device = index;
1233 	PCI_MEM_PUT32(softs, device,
1234 	    (uint32_t)(slotp->fib_phyaddr & 0xfffffffful));
1235 	device += 4;
1236 	PCI_MEM_PUT32(softs, device, (uint32_t)(slotp->fib_phyaddr >> 32));
1237 	device += 4;
1238 	PCI_MEM_PUT32(softs, device, slotp->acp->fib_size);
1239 	PCI_MEM_PUT32(softs, AAC_IQUE, index);
1240 	return (AACOK);
1241 }
1242 
1243 static void
aac_end_io(struct aac_softstate * softs,struct aac_cmd * acp)1244 aac_end_io(struct aac_softstate *softs, struct aac_cmd *acp)
1245 {
1246 	struct aac_device *dvp = acp->dvp;
1247 	int q = AAC_CMDQ(acp);
1248 
1249 	if (acp->slotp) { /* outstanding cmd */
1250 		if (!(acp->flags & AAC_CMD_IN_SYNC_SLOT)) {
1251 			aac_release_slot(softs, acp->slotp);
1252 			acp->slotp = NULL;
1253 		}
1254 		if (dvp) {
1255 			dvp->ncmds[q]--;
1256 			if (dvp->throttle[q] == AAC_THROTTLE_DRAIN &&
1257 			    dvp->ncmds[q] == 0 && q == AAC_CMDQ_ASYNC)
1258 				aac_set_throttle(softs, dvp, q,
1259 				    softs->total_slots);
1260 			/*
1261 			 * Setup auto sense data for UNIT ATTENTION
1262 			 * Each lun should generate a unit attention
1263 			 * condition when reset.
1264 			 * Phys. drives are treated as logical ones
1265 			 * during error recovery.
1266 			 */
1267 			if (dvp->type == AAC_DEV_LD) {
1268 				struct aac_container *ctp =
1269 				    (struct aac_container *)dvp;
1270 				if (ctp->reset == 0)
1271 					goto noreset;
1272 
1273 				AACDB_PRINT(softs, CE_NOTE,
1274 				    "Unit attention: reset");
1275 				ctp->reset = 0;
1276 				aac_set_arq_data(acp->pkt, KEY_UNIT_ATTENTION,
1277 				    0x29, 0x02, 0);
1278 			}
1279 		}
1280 noreset:
1281 		softs->bus_ncmds[q]--;
1282 		aac_cmd_delete(&softs->q_busy, acp);
1283 	} else { /* cmd in waiting queue */
1284 		aac_cmd_delete(&softs->q_wait[q], acp);
1285 	}
1286 
1287 	if (!(acp->flags & (AAC_CMD_NO_CB | AAC_CMD_NO_INTR))) { /* async IO */
1288 		mutex_enter(&softs->q_comp_mutex);
1289 		aac_cmd_enqueue(&softs->q_comp, acp);
1290 		mutex_exit(&softs->q_comp_mutex);
1291 	} else if (acp->flags & AAC_CMD_NO_CB) { /* sync IO */
1292 		cv_broadcast(&softs->event);
1293 	}
1294 }
1295 
1296 static void
aac_handle_io(struct aac_softstate * softs,int index)1297 aac_handle_io(struct aac_softstate *softs, int index)
1298 {
1299 	struct aac_slot *slotp;
1300 	struct aac_cmd *acp;
1301 	uint32_t fast;
1302 
1303 	fast = index & AAC_SENDERADDR_MASK_FAST_RESPONSE;
1304 	index >>= 2;
1305 
1306 	/* Make sure firmware reported index is valid */
1307 	ASSERT(index >= 0 && index < softs->total_slots);
1308 	slotp = &softs->io_slot[index];
1309 	ASSERT(slotp->index == index);
1310 	acp = slotp->acp;
1311 
1312 	if (acp == NULL || acp->slotp != slotp) {
1313 		cmn_err(CE_WARN,
1314 		    "Firmware error: invalid slot index received from FW");
1315 		return;
1316 	}
1317 
1318 	acp->flags |= AAC_CMD_CMPLT;
1319 	(void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
1320 
1321 	if (aac_check_dma_handle(slotp->fib_dma_handle) == DDI_SUCCESS) {
1322 		/*
1323 		 * For fast response IO, the firmware do not return any FIB
1324 		 * data, so we need to fill in the FIB status and state so that
1325 		 * FIB users can handle it correctly.
1326 		 */
1327 		if (fast) {
1328 			uint32_t state;
1329 
1330 			state = ddi_get32(slotp->fib_acc_handle,
1331 			    &slotp->fibp->Header.XferState);
1332 			/*
1333 			 * Update state for CPU not for device, no DMA sync
1334 			 * needed
1335 			 */
1336 			ddi_put32(slotp->fib_acc_handle,
1337 			    &slotp->fibp->Header.XferState,
1338 			    state | AAC_FIBSTATE_DONEADAP);
1339 			ddi_put32(slotp->fib_acc_handle,
1340 			    (void *)&slotp->fibp->data[0], ST_OK);
1341 		}
1342 
1343 		/* Handle completed ac */
1344 		acp->ac_comp(softs, acp);
1345 	} else {
1346 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
1347 		acp->flags |= AAC_CMD_ERR;
1348 		if (acp->pkt) {
1349 			acp->pkt->pkt_reason = CMD_TRAN_ERR;
1350 			acp->pkt->pkt_statistics = 0;
1351 		}
1352 	}
1353 	aac_end_io(softs, acp);
1354 }
1355 
1356 /*
1357  * Interrupt handler for New Comm. interface
1358  * New Comm. interface use a different mechanism for interrupt. No explict
1359  * message queues, and driver need only accesses the mapped PCI mem space to
1360  * find the completed FIB or AIF.
1361  */
1362 static int
aac_process_intr_new(struct aac_softstate * softs)1363 aac_process_intr_new(struct aac_softstate *softs)
1364 {
1365 	uint32_t index;
1366 
1367 	index = AAC_OUTB_GET(softs);
1368 	if (index == 0xfffffffful)
1369 		index = AAC_OUTB_GET(softs);
1370 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
1371 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
1372 		return (0);
1373 	}
1374 	if (index != 0xfffffffful) {
1375 		do {
1376 			if ((index & AAC_SENDERADDR_MASK_AIF) == 0) {
1377 				aac_handle_io(softs, index);
1378 			} else if (index != 0xfffffffeul) {
1379 				struct aac_fib *fibp;	/* FIB in AIF queue */
1380 				uint16_t fib_size;
1381 
1382 				/*
1383 				 * 0xfffffffe means that the controller wants
1384 				 * more work, ignore it for now. Otherwise,
1385 				 * AIF received.
1386 				 */
1387 				index &= ~2;
1388 
1389 				fibp = (struct aac_fib *)(softs-> \
1390 				    pci_mem_base_vaddr + index);
1391 				fib_size = PCI_MEM_GET16(softs, index + \
1392 				    offsetof(struct aac_fib, Header.Size));
1393 
1394 				aac_save_aif(softs, softs->pci_mem_handle,
1395 				    fibp, fib_size);
1396 
1397 				/*
1398 				 * AIF memory is owned by the adapter, so let it
1399 				 * know that we are done with it.
1400 				 */
1401 				AAC_OUTB_SET(softs, index);
1402 				AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_READY);
1403 			}
1404 
1405 			index = AAC_OUTB_GET(softs);
1406 		} while (index != 0xfffffffful);
1407 
1408 		/*
1409 		 * Process waiting cmds before start new ones to
1410 		 * ensure first IOs are serviced first.
1411 		 */
1412 		aac_start_waiting_io(softs);
1413 		return (AAC_DB_COMMAND_READY);
1414 	} else {
1415 		return (0);
1416 	}
1417 }
1418 
1419 static uint_t
aac_intr_new(caddr_t arg,caddr_t arg1 __unused)1420 aac_intr_new(caddr_t arg, caddr_t arg1 __unused)
1421 {
1422 	struct aac_softstate *softs = (void *)arg;
1423 	uint_t rval;
1424 
1425 	mutex_enter(&softs->io_lock);
1426 	if (aac_process_intr_new(softs))
1427 		rval = DDI_INTR_CLAIMED;
1428 	else
1429 		rval = DDI_INTR_UNCLAIMED;
1430 	mutex_exit(&softs->io_lock);
1431 
1432 	aac_drain_comp_q(softs);
1433 	return (rval);
1434 }
1435 
1436 /*
1437  * Interrupt handler for old interface
1438  * Explicit message queues are used to send FIB to and get completed FIB from
1439  * the adapter. Driver and adapter maitain the queues in the producer/consumer
1440  * manner. The driver has to query the queues to find the completed FIB.
1441  */
1442 static int
aac_process_intr_old(struct aac_softstate * softs)1443 aac_process_intr_old(struct aac_softstate *softs)
1444 {
1445 	uint16_t status;
1446 
1447 	status = AAC_STATUS_GET(softs);
1448 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
1449 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
1450 		return (DDI_INTR_UNCLAIMED);
1451 	}
1452 	if (status & AAC_DB_RESPONSE_READY) {
1453 		int slot_idx;
1454 
1455 		/* ACK the intr */
1456 		AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_READY);
1457 		(void) AAC_STATUS_GET(softs);
1458 		while (aac_fib_dequeue(softs, AAC_HOST_NORM_RESP_Q,
1459 		    &slot_idx) == AACOK)
1460 			aac_handle_io(softs, slot_idx);
1461 
1462 		/*
1463 		 * Process waiting cmds before start new ones to
1464 		 * ensure first IOs are serviced first.
1465 		 */
1466 		aac_start_waiting_io(softs);
1467 		return (AAC_DB_RESPONSE_READY);
1468 	} else if (status & AAC_DB_COMMAND_READY) {
1469 		int aif_idx;
1470 
1471 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_READY);
1472 		(void) AAC_STATUS_GET(softs);
1473 		if (aac_fib_dequeue(softs, AAC_HOST_NORM_CMD_Q, &aif_idx) ==
1474 		    AACOK) {
1475 			ddi_acc_handle_t acc = softs->comm_space_acc_handle;
1476 			struct aac_fib *fibp;	/* FIB in communication space */
1477 			uint16_t fib_size;
1478 			uint32_t fib_xfer_state;
1479 			uint32_t addr, size;
1480 
1481 			ASSERT((aif_idx >= 0) && (aif_idx < AAC_ADAPTER_FIBS));
1482 
1483 #define	AAC_SYNC_AIF(softs, aif_idx, type) \
1484 	{ (void) ddi_dma_sync((softs)->comm_space_dma_handle, \
1485 	    offsetof(struct aac_comm_space, \
1486 	    adapter_fibs[(aif_idx)]), AAC_FIB_SIZE, \
1487 	    (type)); }
1488 
1489 			/* Copy AIF from adapter to the empty AIF slot */
1490 			AAC_SYNC_AIF(softs, aif_idx, DDI_DMA_SYNC_FORCPU);
1491 			fibp = &softs->comm_space->adapter_fibs[aif_idx];
1492 			fib_size = ddi_get16(acc, &fibp->Header.Size);
1493 
1494 			aac_save_aif(softs, acc, fibp, fib_size);
1495 
1496 			/* Complete AIF back to adapter with good status */
1497 			fib_xfer_state = LE_32(fibp->Header.XferState);
1498 			if (fib_xfer_state & AAC_FIBSTATE_FROMADAP) {
1499 				ddi_put32(acc, &fibp->Header.XferState,
1500 				    fib_xfer_state | AAC_FIBSTATE_DONEHOST);
1501 				ddi_put32(acc, (void *)&fibp->data[0], ST_OK);
1502 				if (fib_size > AAC_FIB_SIZE)
1503 					ddi_put16(acc, &fibp->Header.Size,
1504 					    AAC_FIB_SIZE);
1505 				AAC_SYNC_AIF(softs, aif_idx,
1506 				    DDI_DMA_SYNC_FORDEV);
1507 			}
1508 
1509 			/* Put the AIF response on the response queue */
1510 			addr = ddi_get32(acc,
1511 			    &softs->comm_space->adapter_fibs[aif_idx]. \
1512 			    Header.SenderFibAddress);
1513 			size = (uint32_t)ddi_get16(acc,
1514 			    &softs->comm_space->adapter_fibs[aif_idx]. \
1515 			    Header.Size);
1516 			ddi_put32(acc,
1517 			    &softs->comm_space->adapter_fibs[aif_idx]. \
1518 			    Header.ReceiverFibAddress, addr);
1519 			if (aac_fib_enqueue(softs, AAC_ADAP_NORM_RESP_Q,
1520 			    addr, size) == AACERR)
1521 				cmn_err(CE_NOTE, "!AIF ack failed");
1522 		}
1523 		return (AAC_DB_COMMAND_READY);
1524 	} else if (status & AAC_DB_PRINTF_READY) {
1525 		/* ACK the intr */
1526 		AAC_STATUS_CLR(softs, AAC_DB_PRINTF_READY);
1527 		(void) AAC_STATUS_GET(softs);
1528 		(void) ddi_dma_sync(softs->comm_space_dma_handle,
1529 		    offsetof(struct aac_comm_space, adapter_print_buf),
1530 		    AAC_ADAPTER_PRINT_BUFSIZE, DDI_DMA_SYNC_FORCPU);
1531 		if (aac_check_dma_handle(softs->comm_space_dma_handle) ==
1532 		    DDI_SUCCESS)
1533 			cmn_err(CE_NOTE, "MSG From Adapter: %s",
1534 			    softs->comm_space->adapter_print_buf);
1535 		else
1536 			ddi_fm_service_impact(softs->devinfo_p,
1537 			    DDI_SERVICE_UNAFFECTED);
1538 		AAC_NOTIFY(softs, AAC_DB_PRINTF_READY);
1539 		return (AAC_DB_PRINTF_READY);
1540 	} else if (status & AAC_DB_COMMAND_NOT_FULL) {
1541 		/*
1542 		 * Without these two condition statements, the OS could hang
1543 		 * after a while, especially if there are a lot of AIF's to
1544 		 * handle, for instance if a drive is pulled from an array
1545 		 * under heavy load.
1546 		 */
1547 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_NOT_FULL);
1548 		return (AAC_DB_COMMAND_NOT_FULL);
1549 	} else if (status & AAC_DB_RESPONSE_NOT_FULL) {
1550 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_NOT_FULL);
1551 		AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_NOT_FULL);
1552 		return (AAC_DB_RESPONSE_NOT_FULL);
1553 	} else {
1554 		return (0);
1555 	}
1556 }
1557 
1558 static uint_t
aac_intr_old(caddr_t arg,caddr_t arg1 __unused)1559 aac_intr_old(caddr_t arg, caddr_t arg1 __unused)
1560 {
1561 	struct aac_softstate *softs = (void *)arg;
1562 	int rval;
1563 
1564 	mutex_enter(&softs->io_lock);
1565 	if (aac_process_intr_old(softs))
1566 		rval = DDI_INTR_CLAIMED;
1567 	else
1568 		rval = DDI_INTR_UNCLAIMED;
1569 	mutex_exit(&softs->io_lock);
1570 
1571 	aac_drain_comp_q(softs);
1572 	return (rval);
1573 }
1574 
1575 /*
1576  * Query FIXED or MSI interrupts
1577  */
1578 static int
aac_query_intrs(struct aac_softstate * softs,int intr_type)1579 aac_query_intrs(struct aac_softstate *softs, int intr_type)
1580 {
1581 	dev_info_t *dip = softs->devinfo_p;
1582 	int avail, actual, count;
1583 	int i, flag, ret;
1584 
1585 	AACDB_PRINT(softs, CE_NOTE,
1586 	    "aac_query_intrs:interrupt type 0x%x", intr_type);
1587 
1588 	/* Get number of interrupts */
1589 	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
1590 	if ((ret != DDI_SUCCESS) || (count == 0)) {
1591 		AACDB_PRINT(softs, CE_WARN,
1592 		    "ddi_intr_get_nintrs() failed, ret %d count %d",
1593 		    ret, count);
1594 		return (DDI_FAILURE);
1595 	}
1596 
1597 	/* Get number of available interrupts */
1598 	ret = ddi_intr_get_navail(dip, intr_type, &avail);
1599 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
1600 		AACDB_PRINT(softs, CE_WARN,
1601 		    "ddi_intr_get_navail() failed, ret %d avail %d",
1602 		    ret, avail);
1603 		return (DDI_FAILURE);
1604 	}
1605 
1606 	AACDB_PRINT(softs, CE_NOTE,
1607 	    "ddi_intr_get_nvail returned %d, navail() returned %d",
1608 	    count, avail);
1609 
1610 	/* Allocate an array of interrupt handles */
1611 	softs->intr_size = count * sizeof (ddi_intr_handle_t);
1612 	softs->htable = kmem_alloc(softs->intr_size, KM_SLEEP);
1613 
1614 	if (intr_type == DDI_INTR_TYPE_MSI) {
1615 		count = 1; /* only one vector needed by now */
1616 		flag = DDI_INTR_ALLOC_STRICT;
1617 	} else { /* must be DDI_INTR_TYPE_FIXED */
1618 		flag = DDI_INTR_ALLOC_NORMAL;
1619 	}
1620 
1621 	/* Call ddi_intr_alloc() */
1622 	ret = ddi_intr_alloc(dip, softs->htable, intr_type, 0,
1623 	    count, &actual, flag);
1624 
1625 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
1626 		AACDB_PRINT(softs, CE_WARN,
1627 		    "ddi_intr_alloc() failed, ret = %d", ret);
1628 		actual = 0;
1629 		goto error;
1630 	}
1631 
1632 	if (actual < count) {
1633 		AACDB_PRINT(softs, CE_NOTE,
1634 		    "Requested: %d, Received: %d", count, actual);
1635 		goto error;
1636 	}
1637 
1638 	softs->intr_cnt = actual;
1639 
1640 	/* Get priority for first msi, assume remaining are all the same */
1641 	if ((ret = ddi_intr_get_pri(softs->htable[0],
1642 	    &softs->intr_pri)) != DDI_SUCCESS) {
1643 		AACDB_PRINT(softs, CE_WARN,
1644 		    "ddi_intr_get_pri() failed, ret = %d", ret);
1645 		goto error;
1646 	}
1647 
1648 	/* Test for high level mutex */
1649 	if (softs->intr_pri >= ddi_intr_get_hilevel_pri()) {
1650 		AACDB_PRINT(softs, CE_WARN,
1651 		    "aac_query_intrs: Hi level interrupt not supported");
1652 		goto error;
1653 	}
1654 
1655 	return (DDI_SUCCESS);
1656 
1657 error:
1658 	/* Free already allocated intr */
1659 	for (i = 0; i < actual; i++)
1660 		(void) ddi_intr_free(softs->htable[i]);
1661 
1662 	kmem_free(softs->htable, softs->intr_size);
1663 	return (DDI_FAILURE);
1664 }
1665 
1666 
1667 /*
1668  * Register FIXED or MSI interrupts, and enable them
1669  */
1670 static int
aac_add_intrs(struct aac_softstate * softs)1671 aac_add_intrs(struct aac_softstate *softs)
1672 {
1673 	int i, ret;
1674 	int actual;
1675 	ddi_intr_handler_t *aac_intr;
1676 
1677 	actual = softs->intr_cnt;
1678 	aac_intr = ((softs->flags & AAC_FLAGS_NEW_COMM) ?
1679 	    aac_intr_new : aac_intr_old);
1680 
1681 	/* Call ddi_intr_add_handler() */
1682 	for (i = 0; i < actual; i++) {
1683 		if ((ret = ddi_intr_add_handler(softs->htable[i],
1684 		    aac_intr, (caddr_t)softs, NULL)) != DDI_SUCCESS) {
1685 			cmn_err(CE_WARN,
1686 			    "ddi_intr_add_handler() failed ret = %d", ret);
1687 
1688 			/* Free already allocated intr */
1689 			for (i = 0; i < actual; i++)
1690 				(void) ddi_intr_free(softs->htable[i]);
1691 
1692 			kmem_free(softs->htable, softs->intr_size);
1693 			return (DDI_FAILURE);
1694 		}
1695 	}
1696 
1697 	if ((ret = ddi_intr_get_cap(softs->htable[0], &softs->intr_cap))
1698 	    != DDI_SUCCESS) {
1699 		cmn_err(CE_WARN, "ddi_intr_get_cap() failed, ret = %d", ret);
1700 
1701 		/* Free already allocated intr */
1702 		for (i = 0; i < actual; i++)
1703 			(void) ddi_intr_free(softs->htable[i]);
1704 
1705 		kmem_free(softs->htable, softs->intr_size);
1706 		return (DDI_FAILURE);
1707 	}
1708 
1709 	return (DDI_SUCCESS);
1710 }
1711 
1712 /*
1713  * Unregister FIXED or MSI interrupts
1714  */
1715 static void
aac_remove_intrs(struct aac_softstate * softs)1716 aac_remove_intrs(struct aac_softstate *softs)
1717 {
1718 	int i;
1719 
1720 	/* Disable all interrupts */
1721 	(void) aac_disable_intrs(softs);
1722 	/* Call ddi_intr_remove_handler() */
1723 	for (i = 0; i < softs->intr_cnt; i++) {
1724 		(void) ddi_intr_remove_handler(softs->htable[i]);
1725 		(void) ddi_intr_free(softs->htable[i]);
1726 	}
1727 
1728 	kmem_free(softs->htable, softs->intr_size);
1729 }
1730 
1731 static int
aac_enable_intrs(struct aac_softstate * softs)1732 aac_enable_intrs(struct aac_softstate *softs)
1733 {
1734 	int rval = AACOK;
1735 
1736 	if (softs->intr_cap & DDI_INTR_FLAG_BLOCK) {
1737 		/* for MSI block enable */
1738 		if (ddi_intr_block_enable(softs->htable, softs->intr_cnt) !=
1739 		    DDI_SUCCESS)
1740 			rval = AACERR;
1741 	} else {
1742 		int i;
1743 
1744 		/* Call ddi_intr_enable() for legacy/MSI non block enable */
1745 		for (i = 0; i < softs->intr_cnt; i++) {
1746 			if (ddi_intr_enable(softs->htable[i]) != DDI_SUCCESS)
1747 				rval = AACERR;
1748 		}
1749 	}
1750 	return (rval);
1751 }
1752 
1753 static int
aac_disable_intrs(struct aac_softstate * softs)1754 aac_disable_intrs(struct aac_softstate *softs)
1755 {
1756 	int rval = AACOK;
1757 
1758 	if (softs->intr_cap & DDI_INTR_FLAG_BLOCK) {
1759 		/* Call ddi_intr_block_disable() */
1760 		if (ddi_intr_block_disable(softs->htable, softs->intr_cnt) !=
1761 		    DDI_SUCCESS)
1762 			rval = AACERR;
1763 	} else {
1764 		int i;
1765 
1766 		for (i = 0; i < softs->intr_cnt; i++) {
1767 			if (ddi_intr_disable(softs->htable[i]) != DDI_SUCCESS)
1768 				rval = AACERR;
1769 		}
1770 	}
1771 	return (rval);
1772 }
1773 
1774 /*
1775  * Set pkt_reason and OR in pkt_statistics flag
1776  */
1777 static void
aac_set_pkt_reason(struct aac_softstate * softs,struct aac_cmd * acp,uchar_t reason,uint_t stat)1778 aac_set_pkt_reason(struct aac_softstate *softs, struct aac_cmd *acp,
1779     uchar_t reason, uint_t stat)
1780 {
1781 #ifndef __lock_lint
1782 	_NOTE(ARGUNUSED(softs))
1783 #endif
1784 	if (acp->pkt->pkt_reason == CMD_CMPLT)
1785 		acp->pkt->pkt_reason = reason;
1786 	acp->pkt->pkt_statistics |= stat;
1787 }
1788 
1789 /*
1790  * Handle a finished pkt of soft SCMD
1791  */
1792 static void
aac_soft_callback(struct aac_softstate * softs,struct aac_cmd * acp)1793 aac_soft_callback(struct aac_softstate *softs, struct aac_cmd *acp)
1794 {
1795 	ASSERT(acp->pkt);
1796 
1797 	acp->flags |= AAC_CMD_CMPLT;
1798 
1799 	acp->pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | \
1800 	    STATE_SENT_CMD | STATE_GOT_STATUS;
1801 	if (acp->pkt->pkt_state & STATE_XFERRED_DATA)
1802 		acp->pkt->pkt_resid = 0;
1803 
1804 	/* AAC_CMD_NO_INTR means no complete callback */
1805 	if (!(acp->flags & AAC_CMD_NO_INTR)) {
1806 		mutex_enter(&softs->q_comp_mutex);
1807 		aac_cmd_enqueue(&softs->q_comp, acp);
1808 		mutex_exit(&softs->q_comp_mutex);
1809 		ddi_trigger_softintr(softs->softint_id);
1810 	}
1811 }
1812 
1813 /*
1814  * Handlers for completed IOs, common to aac_intr_new() and aac_intr_old()
1815  */
1816 
1817 /*
1818  * Handle completed logical device IO command
1819  */
1820 /*ARGSUSED*/
1821 static void
aac_ld_complete(struct aac_softstate * softs,struct aac_cmd * acp)1822 aac_ld_complete(struct aac_softstate *softs, struct aac_cmd *acp)
1823 {
1824 	struct aac_slot *slotp = acp->slotp;
1825 	struct aac_blockread_response *resp;
1826 	uint32_t status;
1827 
1828 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
1829 	ASSERT(!(acp->flags & AAC_CMD_NO_CB));
1830 
1831 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
1832 
1833 	/*
1834 	 * block_read/write has a similar response header, use blockread
1835 	 * response for both.
1836 	 */
1837 	resp = (struct aac_blockread_response *)&slotp->fibp->data[0];
1838 	status = ddi_get32(slotp->fib_acc_handle, &resp->Status);
1839 	if (status == ST_OK) {
1840 		acp->pkt->pkt_resid = 0;
1841 		acp->pkt->pkt_state |= STATE_XFERRED_DATA;
1842 	} else {
1843 		aac_set_arq_data_hwerr(acp);
1844 	}
1845 }
1846 
1847 /*
1848  * Handle completed phys. device IO command
1849  */
1850 static void
aac_pd_complete(struct aac_softstate * softs,struct aac_cmd * acp)1851 aac_pd_complete(struct aac_softstate *softs, struct aac_cmd *acp)
1852 {
1853 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
1854 	struct aac_fib *fibp = acp->slotp->fibp;
1855 	struct scsi_pkt *pkt = acp->pkt;
1856 	struct aac_srb_reply *resp;
1857 	uint32_t resp_status;
1858 
1859 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
1860 	ASSERT(!(acp->flags & AAC_CMD_NO_CB));
1861 
1862 	resp = (struct aac_srb_reply *)&fibp->data[0];
1863 	resp_status = ddi_get32(acc, &resp->status);
1864 
1865 	/* First check FIB status */
1866 	if (resp_status == ST_OK) {
1867 		uint32_t scsi_status;
1868 		uint32_t srb_status;
1869 		uint32_t data_xfer_length;
1870 
1871 		scsi_status = ddi_get32(acc, &resp->scsi_status);
1872 		srb_status = ddi_get32(acc, &resp->srb_status);
1873 		data_xfer_length = ddi_get32(acc, &resp->data_xfer_length);
1874 
1875 		*pkt->pkt_scbp = (uint8_t)scsi_status;
1876 		pkt->pkt_state |= STATE_GOT_STATUS;
1877 		if (scsi_status == STATUS_GOOD) {
1878 			uchar_t cmd = ((union scsi_cdb *)(void *)
1879 			    (pkt->pkt_cdbp))->scc_cmd;
1880 
1881 			/* Next check SRB status */
1882 			switch (srb_status & 0x3f) {
1883 			case SRB_STATUS_DATA_OVERRUN:
1884 				AACDB_PRINT(softs, CE_NOTE, "DATA_OVERRUN: " \
1885 				    "scmd=%d, xfer=%d, buflen=%d",
1886 				    (uint32_t)cmd, data_xfer_length,
1887 				    acp->bcount);
1888 
1889 				switch (cmd) {
1890 				case SCMD_READ:
1891 				case SCMD_WRITE:
1892 				case SCMD_READ_G1:
1893 				case SCMD_WRITE_G1:
1894 				case SCMD_READ_G4:
1895 				case SCMD_WRITE_G4:
1896 				case SCMD_READ_G5:
1897 				case SCMD_WRITE_G5:
1898 					aac_set_pkt_reason(softs, acp,
1899 					    CMD_DATA_OVR, 0);
1900 					break;
1901 				}
1902 				/*FALLTHRU*/
1903 			case SRB_STATUS_ERROR_RECOVERY:
1904 			case SRB_STATUS_PENDING:
1905 			case SRB_STATUS_SUCCESS:
1906 				/*
1907 				 * pkt_resid should only be calculated if the
1908 				 * status is ERROR_RECOVERY/PENDING/SUCCESS/
1909 				 * OVERRUN/UNDERRUN
1910 				 */
1911 				if (data_xfer_length) {
1912 					pkt->pkt_state |= STATE_XFERRED_DATA;
1913 					pkt->pkt_resid = acp->bcount - \
1914 					    data_xfer_length;
1915 					ASSERT(pkt->pkt_resid >= 0);
1916 				}
1917 				break;
1918 			case SRB_STATUS_ABORTED:
1919 				AACDB_PRINT(softs, CE_NOTE,
1920 				    "SRB_STATUS_ABORTED, xfer=%d, resid=%d",
1921 				    data_xfer_length, pkt->pkt_resid);
1922 				aac_set_pkt_reason(softs, acp, CMD_ABORTED,
1923 				    STAT_ABORTED);
1924 				break;
1925 			case SRB_STATUS_ABORT_FAILED:
1926 				AACDB_PRINT(softs, CE_NOTE,
1927 				    "SRB_STATUS_ABORT_FAILED, xfer=%d, " \
1928 				    "resid=%d", data_xfer_length,
1929 				    pkt->pkt_resid);
1930 				aac_set_pkt_reason(softs, acp, CMD_ABORT_FAIL,
1931 				    0);
1932 				break;
1933 			case SRB_STATUS_PARITY_ERROR:
1934 				AACDB_PRINT(softs, CE_NOTE,
1935 				    "SRB_STATUS_PARITY_ERROR, xfer=%d, " \
1936 				    "resid=%d", data_xfer_length,
1937 				    pkt->pkt_resid);
1938 				aac_set_pkt_reason(softs, acp, CMD_PER_FAIL, 0);
1939 				break;
1940 			case SRB_STATUS_NO_DEVICE:
1941 			case SRB_STATUS_INVALID_PATH_ID:
1942 			case SRB_STATUS_INVALID_TARGET_ID:
1943 			case SRB_STATUS_INVALID_LUN:
1944 			case SRB_STATUS_SELECTION_TIMEOUT:
1945 #ifdef DEBUG
1946 				if (AAC_DEV_IS_VALID(acp->dvp)) {
1947 					AACDB_PRINT(softs, CE_NOTE,
1948 					    "SRB_STATUS_NO_DEVICE(%d), " \
1949 					    "xfer=%d, resid=%d ",
1950 					    srb_status & 0x3f,
1951 					    data_xfer_length, pkt->pkt_resid);
1952 				}
1953 #endif
1954 				aac_set_pkt_reason(softs, acp, CMD_DEV_GONE, 0);
1955 				break;
1956 			case SRB_STATUS_COMMAND_TIMEOUT:
1957 			case SRB_STATUS_TIMEOUT:
1958 				AACDB_PRINT(softs, CE_NOTE,
1959 				    "SRB_STATUS_COMMAND_TIMEOUT, xfer=%d, " \
1960 				    "resid=%d", data_xfer_length,
1961 				    pkt->pkt_resid);
1962 				aac_set_pkt_reason(softs, acp, CMD_TIMEOUT,
1963 				    STAT_TIMEOUT);
1964 				break;
1965 			case SRB_STATUS_BUS_RESET:
1966 				AACDB_PRINT(softs, CE_NOTE,
1967 				    "SRB_STATUS_BUS_RESET, xfer=%d, " \
1968 				    "resid=%d", data_xfer_length,
1969 				    pkt->pkt_resid);
1970 				aac_set_pkt_reason(softs, acp, CMD_RESET,
1971 				    STAT_BUS_RESET);
1972 				break;
1973 			default:
1974 				AACDB_PRINT(softs, CE_NOTE, "srb_status=%d, " \
1975 				    "xfer=%d, resid=%d", srb_status & 0x3f,
1976 				    data_xfer_length, pkt->pkt_resid);
1977 				aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
1978 				break;
1979 			}
1980 		} else if (scsi_status == STATUS_CHECK) {
1981 			/* CHECK CONDITION */
1982 			struct scsi_arq_status *arqstat =
1983 			    (void *)(pkt->pkt_scbp);
1984 			uint32_t sense_data_size;
1985 
1986 			pkt->pkt_state |= STATE_ARQ_DONE;
1987 
1988 			*(uint8_t *)&arqstat->sts_rqpkt_status = STATUS_GOOD;
1989 			arqstat->sts_rqpkt_reason = CMD_CMPLT;
1990 			arqstat->sts_rqpkt_resid = 0;
1991 			arqstat->sts_rqpkt_state =
1992 			    STATE_GOT_BUS |
1993 			    STATE_GOT_TARGET |
1994 			    STATE_SENT_CMD |
1995 			    STATE_XFERRED_DATA;
1996 			arqstat->sts_rqpkt_statistics = 0;
1997 
1998 			sense_data_size = ddi_get32(acc,
1999 			    &resp->sense_data_size);
2000 			ASSERT(sense_data_size <= AAC_SENSE_BUFFERSIZE);
2001 			AACDB_PRINT(softs, CE_NOTE,
2002 			    "CHECK CONDITION: sense len=%d, xfer len=%d",
2003 			    sense_data_size, data_xfer_length);
2004 
2005 			if (sense_data_size > SENSE_LENGTH)
2006 				sense_data_size = SENSE_LENGTH;
2007 			ddi_rep_get8(acc, (uint8_t *)&arqstat->sts_sensedata,
2008 			    (uint8_t *)resp->sense_data, sense_data_size,
2009 			    DDI_DEV_AUTOINCR);
2010 		} else {
2011 			AACDB_PRINT(softs, CE_WARN, "invaild scsi status: " \
2012 			    "scsi_status=%d, srb_status=%d",
2013 			    scsi_status, srb_status);
2014 			aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
2015 		}
2016 	} else {
2017 		AACDB_PRINT(softs, CE_NOTE, "SRB failed: fib status %d",
2018 		    resp_status);
2019 		aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
2020 	}
2021 }
2022 
2023 /*
2024  * Handle completed IOCTL command
2025  */
2026 /*ARGSUSED*/
2027 void
aac_ioctl_complete(struct aac_softstate * softs,struct aac_cmd * acp)2028 aac_ioctl_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2029 {
2030 	struct aac_slot *slotp = acp->slotp;
2031 
2032 	/*
2033 	 * NOTE: Both aac_ioctl_send_fib() and aac_send_raw_srb()
2034 	 * may wait on softs->event, so use cv_broadcast() instead
2035 	 * of cv_signal().
2036 	 */
2037 	ASSERT(acp->flags & AAC_CMD_SYNC);
2038 	ASSERT(acp->flags & AAC_CMD_NO_CB);
2039 
2040 	/* Get the size of the response FIB from its FIB.Header.Size field */
2041 	acp->fib_size = ddi_get16(slotp->fib_acc_handle,
2042 	    &slotp->fibp->Header.Size);
2043 
2044 	ASSERT(acp->fib_size <= softs->aac_max_fib_size);
2045 	ddi_rep_get8(slotp->fib_acc_handle, (uint8_t *)acp->fibp,
2046 	    (uint8_t *)slotp->fibp, acp->fib_size, DDI_DEV_AUTOINCR);
2047 }
2048 
2049 /*
2050  * Handle completed sync fib command
2051  */
2052 /*ARGSUSED*/
2053 void
aac_sync_complete(struct aac_softstate * softs,struct aac_cmd * acp)2054 aac_sync_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2055 {
2056 }
2057 
2058 /*
2059  * Handle completed Flush command
2060  */
2061 /*ARGSUSED*/
2062 static void
aac_synccache_complete(struct aac_softstate * softs,struct aac_cmd * acp)2063 aac_synccache_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2064 {
2065 	struct aac_slot *slotp = acp->slotp;
2066 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
2067 	struct aac_synchronize_reply *resp;
2068 	uint32_t status;
2069 
2070 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
2071 
2072 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
2073 
2074 	resp = (struct aac_synchronize_reply *)&slotp->fibp->data[0];
2075 	status = ddi_get32(acc, &resp->Status);
2076 	if (status != CT_OK)
2077 		aac_set_arq_data_hwerr(acp);
2078 }
2079 
2080 /*ARGSUSED*/
2081 static void
aac_startstop_complete(struct aac_softstate * softs,struct aac_cmd * acp)2082 aac_startstop_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2083 {
2084 	struct aac_slot *slotp = acp->slotp;
2085 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
2086 	struct aac_Container_resp *resp;
2087 	uint32_t status;
2088 
2089 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
2090 
2091 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
2092 
2093 	resp = (struct aac_Container_resp *)&slotp->fibp->data[0];
2094 	status = ddi_get32(acc, &resp->Status);
2095 	if (status != 0) {
2096 		AACDB_PRINT(softs, CE_WARN, "Cannot start/stop a unit");
2097 		aac_set_arq_data_hwerr(acp);
2098 	}
2099 }
2100 
2101 /*
2102  * Access PCI space to see if the driver can support the card
2103  */
2104 static int
aac_check_card_type(struct aac_softstate * softs)2105 aac_check_card_type(struct aac_softstate *softs)
2106 {
2107 	ddi_acc_handle_t pci_config_handle;
2108 	int card_index;
2109 	uint32_t pci_cmd;
2110 
2111 	/* Map pci configuration space */
2112 	if ((pci_config_setup(softs->devinfo_p, &pci_config_handle)) !=
2113 	    DDI_SUCCESS) {
2114 		AACDB_PRINT(softs, CE_WARN, "Cannot setup pci config space");
2115 		return (AACERR);
2116 	}
2117 
2118 	softs->vendid = pci_config_get16(pci_config_handle, PCI_CONF_VENID);
2119 	softs->devid = pci_config_get16(pci_config_handle, PCI_CONF_DEVID);
2120 	softs->subvendid = pci_config_get16(pci_config_handle,
2121 	    PCI_CONF_SUBVENID);
2122 	softs->subsysid = pci_config_get16(pci_config_handle,
2123 	    PCI_CONF_SUBSYSID);
2124 
2125 	card_index = 0;
2126 	while (!CARD_IS_UNKNOWN(card_index)) {
2127 		if ((aac_cards[card_index].vendor == softs->vendid) &&
2128 		    (aac_cards[card_index].device == softs->devid) &&
2129 		    (aac_cards[card_index].subvendor == softs->subvendid) &&
2130 		    (aac_cards[card_index].subsys == softs->subsysid)) {
2131 			break;
2132 		}
2133 		card_index++;
2134 	}
2135 
2136 	softs->card = card_index;
2137 	softs->hwif = aac_cards[card_index].hwif;
2138 
2139 	/*
2140 	 * Unknown aac card
2141 	 * do a generic match based on the VendorID and DeviceID to
2142 	 * support the new cards in the aac family
2143 	 */
2144 	if (CARD_IS_UNKNOWN(card_index)) {
2145 		if (softs->vendid != 0x9005) {
2146 			AACDB_PRINT(softs, CE_WARN,
2147 			    "Unknown vendor 0x%x", softs->vendid);
2148 			goto error;
2149 		}
2150 		switch (softs->devid) {
2151 		case 0x285:
2152 			softs->hwif = AAC_HWIF_I960RX;
2153 			break;
2154 		case 0x286:
2155 			softs->hwif = AAC_HWIF_RKT;
2156 			break;
2157 		default:
2158 			AACDB_PRINT(softs, CE_WARN,
2159 			    "Unknown device \"pci9005,%x\"", softs->devid);
2160 			goto error;
2161 		}
2162 	}
2163 
2164 	/* Set hardware dependent interface */
2165 	switch (softs->hwif) {
2166 	case AAC_HWIF_I960RX:
2167 		softs->aac_if = aac_rx_interface;
2168 		softs->map_size_min = AAC_MAP_SIZE_MIN_RX;
2169 		break;
2170 	case AAC_HWIF_RKT:
2171 		softs->aac_if = aac_rkt_interface;
2172 		softs->map_size_min = AAC_MAP_SIZE_MIN_RKT;
2173 		break;
2174 	default:
2175 		AACDB_PRINT(softs, CE_WARN,
2176 		    "Unknown hardware interface %d", softs->hwif);
2177 		goto error;
2178 	}
2179 
2180 	/* Set card names */
2181 	(void *)strncpy(softs->vendor_name, aac_cards[card_index].vid,
2182 	    AAC_VENDOR_LEN);
2183 	(void *)strncpy(softs->product_name, aac_cards[card_index].desc,
2184 	    AAC_PRODUCT_LEN);
2185 
2186 	/* Set up quirks */
2187 	softs->flags = aac_cards[card_index].quirks;
2188 
2189 	/* Force the busmaster enable bit on */
2190 	pci_cmd = pci_config_get16(pci_config_handle, PCI_CONF_COMM);
2191 	if ((pci_cmd & PCI_COMM_ME) == 0) {
2192 		pci_cmd |= PCI_COMM_ME;
2193 		pci_config_put16(pci_config_handle, PCI_CONF_COMM, pci_cmd);
2194 		pci_cmd = pci_config_get16(pci_config_handle, PCI_CONF_COMM);
2195 		if ((pci_cmd & PCI_COMM_ME) == 0) {
2196 			cmn_err(CE_CONT, "?Cannot enable busmaster bit");
2197 			goto error;
2198 		}
2199 	}
2200 
2201 	/* Set memory base to map */
2202 	softs->pci_mem_base_paddr = 0xfffffff0UL & \
2203 	    pci_config_get32(pci_config_handle, PCI_CONF_BASE0);
2204 
2205 	pci_config_teardown(&pci_config_handle);
2206 
2207 	return (AACOK); /* card type detected */
2208 error:
2209 	pci_config_teardown(&pci_config_handle);
2210 	return (AACERR); /* no matched card found */
2211 }
2212 
2213 /*
2214  * Do the usual interrupt handler setup stuff.
2215  */
2216 static int
aac_register_intrs(struct aac_softstate * softs)2217 aac_register_intrs(struct aac_softstate *softs)
2218 {
2219 	dev_info_t *dip;
2220 	int intr_types;
2221 
2222 	ASSERT(softs->devinfo_p);
2223 	dip = softs->devinfo_p;
2224 
2225 	/* Get the type of device intrrupts */
2226 	if (ddi_intr_get_supported_types(dip, &intr_types) != DDI_SUCCESS) {
2227 		AACDB_PRINT(softs, CE_WARN,
2228 		    "ddi_intr_get_supported_types() failed");
2229 		return (AACERR);
2230 	}
2231 	AACDB_PRINT(softs, CE_NOTE,
2232 	    "ddi_intr_get_supported_types() ret: 0x%x", intr_types);
2233 
2234 	/* Query interrupt, and alloc/init all needed struct */
2235 	if (intr_types & DDI_INTR_TYPE_MSI) {
2236 		if (aac_query_intrs(softs, DDI_INTR_TYPE_MSI)
2237 		    != DDI_SUCCESS) {
2238 			AACDB_PRINT(softs, CE_WARN,
2239 			    "MSI interrupt query failed");
2240 			return (AACERR);
2241 		}
2242 		softs->intr_type = DDI_INTR_TYPE_MSI;
2243 	} else if (intr_types & DDI_INTR_TYPE_FIXED) {
2244 		if (aac_query_intrs(softs, DDI_INTR_TYPE_FIXED)
2245 		    != DDI_SUCCESS) {
2246 			AACDB_PRINT(softs, CE_WARN,
2247 			    "FIXED interrupt query failed");
2248 			return (AACERR);
2249 		}
2250 		softs->intr_type = DDI_INTR_TYPE_FIXED;
2251 	} else {
2252 		AACDB_PRINT(softs, CE_WARN,
2253 		    "Device cannot suppport both FIXED and MSI interrupts");
2254 		return (AACERR);
2255 	}
2256 
2257 	/* Connect interrupt handlers */
2258 	if (aac_add_intrs(softs) != DDI_SUCCESS) {
2259 		AACDB_PRINT(softs, CE_WARN,
2260 		    "Interrupt registration failed, intr type: %s",
2261 		    softs->intr_type == DDI_INTR_TYPE_MSI ? "MSI" : "FIXED");
2262 		return (AACERR);
2263 	}
2264 	(void) aac_enable_intrs(softs);
2265 
2266 	if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &softs->softint_id,
2267 	    NULL, NULL, aac_softintr, (caddr_t)softs) != DDI_SUCCESS) {
2268 		AACDB_PRINT(softs, CE_WARN,
2269 		    "Can not setup soft interrupt handler!");
2270 		aac_remove_intrs(softs);
2271 		return (AACERR);
2272 	}
2273 
2274 	return (AACOK);
2275 }
2276 
2277 static void
aac_unregister_intrs(struct aac_softstate * softs)2278 aac_unregister_intrs(struct aac_softstate *softs)
2279 {
2280 	aac_remove_intrs(softs);
2281 	ddi_remove_softintr(softs->softint_id);
2282 }
2283 
2284 /*
2285  * Check the firmware to determine the features to support and the FIB
2286  * parameters to use.
2287  */
2288 static int
aac_check_firmware(struct aac_softstate * softs)2289 aac_check_firmware(struct aac_softstate *softs)
2290 {
2291 	uint32_t options;
2292 	uint32_t atu_size;
2293 	ddi_acc_handle_t pci_handle;
2294 	uint8_t *data;
2295 	uint32_t max_fibs;
2296 	uint32_t max_fib_size;
2297 	uint32_t sg_tablesize;
2298 	uint32_t max_sectors;
2299 	uint32_t status;
2300 
2301 	max_fibs = 0;
2302 	max_sectors = 0;
2303 	sg_tablesize = 0;
2304 
2305 	/* Get supported options */
2306 	if ((aac_sync_mbcommand(softs, AAC_MONKER_GETINFO, 0, 0, 0, 0,
2307 	    &status)) != AACOK) {
2308 		if (status != SRB_STATUS_INVALID_REQUEST) {
2309 			cmn_err(CE_CONT,
2310 			    "?Fatal error: request adapter info error");
2311 			return (AACERR);
2312 		}
2313 		options = 0;
2314 		atu_size = 0;
2315 	} else {
2316 		options = AAC_MAILBOX_GET(softs, 1);
2317 		atu_size = AAC_MAILBOX_GET(softs, 2);
2318 	}
2319 
2320 	if (softs->state & AAC_STATE_RESET) {
2321 		if ((softs->support_opt == options) &&
2322 		    (softs->atu_size == atu_size))
2323 			return (AACOK);
2324 
2325 		cmn_err(CE_WARN,
2326 		    "?Fatal error: firmware changed, system needs reboot");
2327 		return (AACERR);
2328 	}
2329 
2330 	/*
2331 	 * The following critical settings are initialized only once during
2332 	 * driver attachment.
2333 	 */
2334 	softs->support_opt = options;
2335 	softs->atu_size = atu_size;
2336 
2337 	/* Process supported options */
2338 	if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
2339 	    (softs->flags & AAC_FLAGS_NO4GB) == 0) {
2340 		AACDB_PRINT(softs, CE_NOTE, "!Enable FIB map 4GB window");
2341 		softs->flags |= AAC_FLAGS_4GB_WINDOW;
2342 	} else {
2343 		/*
2344 		 * Quirk AAC_FLAGS_NO4GB is for FIB address and thus comm space
2345 		 * only. IO is handled by the DMA engine which does not suffer
2346 		 * from the ATU window programming workarounds necessary for
2347 		 * CPU copy operations.
2348 		 */
2349 		softs->addr_dma_attr.dma_attr_addr_lo = 0x2000ull;
2350 		softs->addr_dma_attr.dma_attr_addr_hi = 0x7fffffffull;
2351 	}
2352 
2353 	if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0) {
2354 		AACDB_PRINT(softs, CE_NOTE, "!Enable SG map 64-bit address");
2355 		softs->buf_dma_attr.dma_attr_addr_hi = 0xffffffffffffffffull;
2356 		softs->buf_dma_attr.dma_attr_seg = 0xffffffffffffffffull;
2357 		softs->flags |= AAC_FLAGS_SG_64BIT;
2358 	}
2359 
2360 	if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) {
2361 		softs->flags |= AAC_FLAGS_ARRAY_64BIT;
2362 		AACDB_PRINT(softs, CE_NOTE, "!Enable 64-bit array size");
2363 	}
2364 
2365 	if (options & AAC_SUPPORTED_NONDASD) {
2366 		if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, softs->devinfo_p, 0,
2367 		    "nondasd-enable", (char **)&data) == DDI_SUCCESS)) {
2368 			if (strcmp((char *)data, "yes") == 0) {
2369 				AACDB_PRINT(softs, CE_NOTE,
2370 				    "!Enable Non-DASD access");
2371 				softs->flags |= AAC_FLAGS_NONDASD;
2372 			}
2373 			ddi_prop_free(data);
2374 		}
2375 	}
2376 
2377 	/* Read preferred settings */
2378 	max_fib_size = 0;
2379 	if ((aac_sync_mbcommand(softs, AAC_MONKER_GETCOMMPREF,
2380 	    0, 0, 0, 0, NULL)) == AACOK) {
2381 		options = AAC_MAILBOX_GET(softs, 1);
2382 		max_fib_size = (options & 0xffff);
2383 		max_sectors = (options >> 16) << 1;
2384 		options = AAC_MAILBOX_GET(softs, 2);
2385 		sg_tablesize = (options >> 16);
2386 		options = AAC_MAILBOX_GET(softs, 3);
2387 		max_fibs = (options & 0xffff);
2388 	}
2389 
2390 	/* Enable new comm. and rawio at the same time */
2391 	if ((softs->support_opt & AAC_SUPPORTED_NEW_COMM) &&
2392 	    (max_fib_size != 0)) {
2393 		/* read out and save PCI MBR */
2394 		if ((atu_size > softs->map_size) &&
2395 		    (ddi_regs_map_setup(softs->devinfo_p, 1,
2396 		    (caddr_t *)&data, 0, atu_size, &softs->reg_attr,
2397 		    &pci_handle) == DDI_SUCCESS)) {
2398 			ddi_regs_map_free(&softs->pci_mem_handle);
2399 			softs->pci_mem_handle = pci_handle;
2400 			softs->pci_mem_base_vaddr = data;
2401 			softs->map_size = atu_size;
2402 		}
2403 		if (atu_size == softs->map_size) {
2404 			softs->flags |= AAC_FLAGS_NEW_COMM;
2405 			AACDB_PRINT(softs, CE_NOTE,
2406 			    "!Enable New Comm. interface");
2407 		}
2408 	}
2409 
2410 	/* Set FIB parameters */
2411 	if (softs->flags & AAC_FLAGS_NEW_COMM) {
2412 		softs->aac_max_fibs = max_fibs;
2413 		softs->aac_max_fib_size = max_fib_size;
2414 		softs->aac_max_sectors = max_sectors;
2415 		softs->aac_sg_tablesize = sg_tablesize;
2416 
2417 		softs->flags |= AAC_FLAGS_RAW_IO;
2418 		AACDB_PRINT(softs, CE_NOTE, "!Enable RawIO");
2419 	} else {
2420 		softs->aac_max_fibs =
2421 		    (softs->flags & AAC_FLAGS_256FIBS) ? 256 : 512;
2422 		softs->aac_max_fib_size = AAC_FIB_SIZE;
2423 		softs->aac_max_sectors = 128;	/* 64K */
2424 		if (softs->flags & AAC_FLAGS_17SG)
2425 			softs->aac_sg_tablesize = 17;
2426 		else if (softs->flags & AAC_FLAGS_34SG)
2427 			softs->aac_sg_tablesize = 34;
2428 		else if (softs->flags & AAC_FLAGS_SG_64BIT)
2429 			softs->aac_sg_tablesize = (AAC_FIB_DATASIZE -
2430 			    sizeof (struct aac_blockwrite64) +
2431 			    sizeof (struct aac_sg_entry64)) /
2432 			    sizeof (struct aac_sg_entry64);
2433 		else
2434 			softs->aac_sg_tablesize = (AAC_FIB_DATASIZE -
2435 			    sizeof (struct aac_blockwrite) +
2436 			    sizeof (struct aac_sg_entry)) /
2437 			    sizeof (struct aac_sg_entry);
2438 	}
2439 
2440 	if ((softs->flags & AAC_FLAGS_RAW_IO) &&
2441 	    (softs->flags & AAC_FLAGS_ARRAY_64BIT)) {
2442 		softs->flags |= AAC_FLAGS_LBA_64BIT;
2443 		AACDB_PRINT(softs, CE_NOTE, "!Enable 64-bit array");
2444 	}
2445 	softs->buf_dma_attr.dma_attr_sgllen = softs->aac_sg_tablesize;
2446 	softs->buf_dma_attr.dma_attr_maxxfer = softs->aac_max_sectors << 9;
2447 	/*
2448 	 * 64K maximum segment size in scatter gather list is controlled by
2449 	 * the NEW_COMM bit in the adapter information. If not set, the card
2450 	 * can only accept a maximum of 64K. It is not recommended to permit
2451 	 * more than 128KB of total transfer size to the adapters because
2452 	 * performance is negatively impacted.
2453 	 *
2454 	 * For new comm, segment size equals max xfer size. For old comm,
2455 	 * we use 64K for both.
2456 	 */
2457 	softs->buf_dma_attr.dma_attr_count_max =
2458 	    softs->buf_dma_attr.dma_attr_maxxfer - 1;
2459 
2460 	/* Setup FIB operations */
2461 	if (softs->flags & AAC_FLAGS_RAW_IO)
2462 		softs->aac_cmd_fib = aac_cmd_fib_rawio;
2463 	else if (softs->flags & AAC_FLAGS_SG_64BIT)
2464 		softs->aac_cmd_fib = aac_cmd_fib_brw64;
2465 	else
2466 		softs->aac_cmd_fib = aac_cmd_fib_brw;
2467 	softs->aac_cmd_fib_scsi = (softs->flags & AAC_FLAGS_SG_64BIT) ? \
2468 	    aac_cmd_fib_scsi64 : aac_cmd_fib_scsi32;
2469 
2470 	/* 64-bit LBA needs descriptor format sense data */
2471 	softs->slen = sizeof (struct scsi_arq_status);
2472 	if ((softs->flags & AAC_FLAGS_LBA_64BIT) &&
2473 	    softs->slen < AAC_ARQ64_LENGTH)
2474 		softs->slen = AAC_ARQ64_LENGTH;
2475 
2476 	AACDB_PRINT(softs, CE_NOTE,
2477 	    "!max_fibs %d max_fibsize 0x%x max_sectors %d max_sg %d",
2478 	    softs->aac_max_fibs, softs->aac_max_fib_size,
2479 	    softs->aac_max_sectors, softs->aac_sg_tablesize);
2480 
2481 	return (AACOK);
2482 }
2483 
2484 static void
aac_fsa_rev(struct aac_softstate * softs,struct FsaRev * fsarev0,struct FsaRev * fsarev1)2485 aac_fsa_rev(struct aac_softstate *softs, struct FsaRev *fsarev0,
2486     struct FsaRev *fsarev1)
2487 {
2488 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
2489 
2490 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.dash);
2491 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.type);
2492 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.minor);
2493 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.major);
2494 	AAC_GET_FIELD32(acc, fsarev1, fsarev0, buildNumber);
2495 }
2496 
2497 /*
2498  * The following function comes from Adaptec:
2499  *
2500  * Query adapter information and supplement adapter information
2501  */
2502 static int
aac_get_adapter_info(struct aac_softstate * softs,struct aac_adapter_info * ainfr,struct aac_supplement_adapter_info * sinfr)2503 aac_get_adapter_info(struct aac_softstate *softs,
2504     struct aac_adapter_info *ainfr, struct aac_supplement_adapter_info *sinfr)
2505 {
2506 	struct aac_cmd *acp = &softs->sync_ac;
2507 	ddi_acc_handle_t acc;
2508 	struct aac_fib *fibp;
2509 	struct aac_adapter_info *ainfp;
2510 	struct aac_supplement_adapter_info *sinfp;
2511 	int rval;
2512 
2513 	(void) aac_sync_fib_slot_bind(softs, acp);
2514 	acc = acp->slotp->fib_acc_handle;
2515 	fibp = acp->slotp->fibp;
2516 
2517 	ddi_put8(acc, &fibp->data[0], 0);
2518 	if (aac_sync_fib(softs, RequestAdapterInfo,
2519 	    AAC_FIB_SIZEOF(struct aac_adapter_info)) != AACOK) {
2520 		AACDB_PRINT(softs, CE_WARN, "RequestAdapterInfo failed");
2521 		rval = AACERR;
2522 		goto finish;
2523 	}
2524 	ainfp = (struct aac_adapter_info *)fibp->data;
2525 	if (ainfr) {
2526 		AAC_GET_FIELD32(acc, ainfr, ainfp, SupportedOptions);
2527 		AAC_GET_FIELD32(acc, ainfr, ainfp, PlatformBase);
2528 		AAC_GET_FIELD32(acc, ainfr, ainfp, CpuArchitecture);
2529 		AAC_GET_FIELD32(acc, ainfr, ainfp, CpuVariant);
2530 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClockSpeed);
2531 		AAC_GET_FIELD32(acc, ainfr, ainfp, ExecutionMem);
2532 		AAC_GET_FIELD32(acc, ainfr, ainfp, BufferMem);
2533 		AAC_GET_FIELD32(acc, ainfr, ainfp, TotalMem);
2534 		aac_fsa_rev(softs, &ainfp->KernelRevision,
2535 		    &ainfr->KernelRevision);
2536 		aac_fsa_rev(softs, &ainfp->MonitorRevision,
2537 		    &ainfr->MonitorRevision);
2538 		aac_fsa_rev(softs, &ainfp->HardwareRevision,
2539 		    &ainfr->HardwareRevision);
2540 		aac_fsa_rev(softs, &ainfp->BIOSRevision,
2541 		    &ainfr->BIOSRevision);
2542 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClusteringEnabled);
2543 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClusterChannelMask);
2544 		AAC_GET_FIELD64(acc, ainfr, ainfp, SerialNumber);
2545 		AAC_GET_FIELD32(acc, ainfr, ainfp, batteryPlatform);
2546 		AAC_GET_FIELD32(acc, ainfr, ainfp, SupportedOptions);
2547 		AAC_GET_FIELD32(acc, ainfr, ainfp, OemVariant);
2548 	}
2549 	if (sinfr) {
2550 		if (!(softs->support_opt &
2551 		    AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO)) {
2552 			AACDB_PRINT(softs, CE_WARN,
2553 			    "SupplementAdapterInfo not supported");
2554 			rval = AACERR;
2555 			goto finish;
2556 		}
2557 		ddi_put8(acc, &fibp->data[0], 0);
2558 		if (aac_sync_fib(softs, RequestSupplementAdapterInfo,
2559 		    AAC_FIB_SIZEOF(struct aac_supplement_adapter_info))
2560 		    != AACOK) {
2561 			AACDB_PRINT(softs, CE_WARN,
2562 			    "RequestSupplementAdapterInfo failed");
2563 			rval = AACERR;
2564 			goto finish;
2565 		}
2566 		sinfp = (struct aac_supplement_adapter_info *)fibp->data;
2567 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, AdapterTypeText[0], 17+1);
2568 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, Pad[0], 2);
2569 		AAC_GET_FIELD32(acc, sinfr, sinfp, FlashMemoryByteSize);
2570 		AAC_GET_FIELD32(acc, sinfr, sinfp, FlashImageId);
2571 		AAC_GET_FIELD32(acc, sinfr, sinfp, MaxNumberPorts);
2572 		AAC_GET_FIELD32(acc, sinfr, sinfp, Version);
2573 		AAC_GET_FIELD32(acc, sinfr, sinfp, FeatureBits);
2574 		AAC_GET_FIELD8(acc, sinfr, sinfp, SlotNumber);
2575 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, ReservedPad0[0], 3);
2576 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, BuildDate[0], 12);
2577 		AAC_GET_FIELD32(acc, sinfr, sinfp, CurrentNumberPorts);
2578 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, VpdInfo,
2579 		    sizeof (struct vpd_info));
2580 		aac_fsa_rev(softs, &sinfp->FlashFirmwareRevision,
2581 		    &sinfr->FlashFirmwareRevision);
2582 		AAC_GET_FIELD32(acc, sinfr, sinfp, RaidTypeMorphOptions);
2583 		aac_fsa_rev(softs, &sinfp->FlashFirmwareBootRevision,
2584 		    &sinfr->FlashFirmwareBootRevision);
2585 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, MfgPcbaSerialNo,
2586 		    MFG_PCBA_SERIAL_NUMBER_WIDTH);
2587 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, MfgWWNName[0],
2588 		    MFG_WWN_WIDTH);
2589 		AAC_GET_FIELD32(acc, sinfr, sinfp, SupportedOptions2);
2590 		AAC_GET_FIELD32(acc, sinfr, sinfp, ExpansionFlag);
2591 		if (sinfr->ExpansionFlag == 1) {
2592 			AAC_GET_FIELD32(acc, sinfr, sinfp, FeatureBits3);
2593 			AAC_GET_FIELD32(acc, sinfr, sinfp,
2594 			    SupportedPerformanceMode);
2595 			AAC_REP_GET_FIELD32(acc, sinfr, sinfp,
2596 			    ReservedGrowth[0], 80);
2597 		}
2598 	}
2599 	rval = AACOK;
2600 finish:
2601 	aac_sync_fib_slot_release(softs, acp);
2602 	return (rval);
2603 }
2604 
2605 static int
aac_get_bus_info(struct aac_softstate * softs,uint32_t * bus_max,uint32_t * tgt_max)2606 aac_get_bus_info(struct aac_softstate *softs, uint32_t *bus_max,
2607     uint32_t *tgt_max)
2608 {
2609 	struct aac_cmd *acp = &softs->sync_ac;
2610 	ddi_acc_handle_t acc;
2611 	struct aac_fib *fibp;
2612 	struct aac_ctcfg *c_cmd;
2613 	struct aac_ctcfg_resp *c_resp;
2614 	uint32_t scsi_method_id;
2615 	struct aac_bus_info *cmd;
2616 	struct aac_bus_info_response *resp;
2617 	int rval;
2618 
2619 	(void) aac_sync_fib_slot_bind(softs, acp);
2620 	acc = acp->slotp->fib_acc_handle;
2621 	fibp = acp->slotp->fibp;
2622 
2623 	/* Detect MethodId */
2624 	c_cmd = (struct aac_ctcfg *)&fibp->data[0];
2625 	ddi_put32(acc, &c_cmd->Command, VM_ContainerConfig);
2626 	ddi_put32(acc, &c_cmd->cmd, CT_GET_SCSI_METHOD);
2627 	ddi_put32(acc, &c_cmd->param, 0);
2628 	rval = aac_sync_fib(softs, ContainerCommand,
2629 	    AAC_FIB_SIZEOF(struct aac_ctcfg));
2630 	c_resp = (struct aac_ctcfg_resp *)&fibp->data[0];
2631 	if (rval != AACOK || ddi_get32(acc, &c_resp->Status) != 0) {
2632 		AACDB_PRINT(softs, CE_WARN,
2633 		    "VM_ContainerConfig command fail");
2634 		rval = AACERR;
2635 		goto finish;
2636 	}
2637 	scsi_method_id = ddi_get32(acc, &c_resp->param);
2638 
2639 	/* Detect phys. bus count and max. target id first */
2640 	cmd = (struct aac_bus_info *)&fibp->data[0];
2641 	ddi_put32(acc, &cmd->Command, VM_Ioctl);
2642 	ddi_put32(acc, &cmd->ObjType, FT_DRIVE); /* physical drive */
2643 	ddi_put32(acc, &cmd->MethodId, scsi_method_id);
2644 	ddi_put32(acc, &cmd->ObjectId, 0);
2645 	ddi_put32(acc, &cmd->CtlCmd, GetBusInfo);
2646 	/*
2647 	 * For VM_Ioctl, the firmware uses the Header.Size filled from the
2648 	 * driver as the size to be returned. Therefore the driver has to use
2649 	 * sizeof (struct aac_bus_info_response) because it is greater than
2650 	 * sizeof (struct aac_bus_info).
2651 	 */
2652 	rval = aac_sync_fib(softs, ContainerCommand,
2653 	    AAC_FIB_SIZEOF(struct aac_bus_info_response));
2654 	resp = (struct aac_bus_info_response *)cmd;
2655 
2656 	/* Scan all coordinates with INQUIRY */
2657 	if ((rval != AACOK) || (ddi_get32(acc, &resp->Status) != 0)) {
2658 		AACDB_PRINT(softs, CE_WARN, "GetBusInfo command fail");
2659 		rval = AACERR;
2660 		goto finish;
2661 	}
2662 	*bus_max = ddi_get32(acc, &resp->BusCount);
2663 	*tgt_max = ddi_get32(acc, &resp->TargetsPerBus);
2664 
2665 finish:
2666 	aac_sync_fib_slot_release(softs, acp);
2667 	return (AACOK);
2668 }
2669 
2670 /*
2671  * The following function comes from Adaptec:
2672  *
2673  * Routine to be called during initialization of communications with
2674  * the adapter to handle possible adapter configuration issues. When
2675  * the adapter first boots up, it examines attached drives, etc, and
2676  * potentially comes up with a new or revised configuration (relative to
2677  * what's stored in it's NVRAM). Additionally it may discover problems
2678  * that make the current physical configuration unworkable (currently
2679  * applicable only to cluster configuration issues).
2680  *
2681  * If there are no configuration issues or the issues are considered
2682  * trival by the adapter, it will set it's configuration status to
2683  * "FSACT_CONTINUE" and execute the "commit confiuguration" action
2684  * automatically on it's own.
2685  *
2686  * However, if there are non-trivial issues, the adapter will set it's
2687  * internal configuration status to "FSACT_PAUSE" or "FASCT_ABORT"
2688  * and wait for some agent on the host to issue the "\ContainerCommand
2689  * \VM_ContainerConfig\CT_COMMIT_CONFIG" FIB command to cause the
2690  * adapter to commit the new/updated configuration and enable
2691  * un-inhibited operation.  The host agent should first issue the
2692  * "\ContainerCommand\VM_ContainerConfig\CT_GET_CONFIG_STATUS" FIB
2693  * command to obtain information about config issues detected by
2694  * the adapter.
2695  *
2696  * Normally the adapter's PC BIOS will execute on the host following
2697  * adapter poweron and reset and will be responsible for querring the
2698  * adapter with CT_GET_CONFIG_STATUS and issuing the CT_COMMIT_CONFIG
2699  * command if appropriate.
2700  *
2701  * However, with the introduction of IOP reset support, the adapter may
2702  * boot up without the benefit of the adapter's PC BIOS host agent.
2703  * This routine is intended to take care of these issues in situations
2704  * where BIOS doesn't execute following adapter poweron or reset.  The
2705  * CT_COMMIT_CONFIG command is a no-op if it's already been issued, so
2706  * there is no harm in doing this when it's already been done.
2707  */
2708 static int
aac_handle_adapter_config_issues(struct aac_softstate * softs)2709 aac_handle_adapter_config_issues(struct aac_softstate *softs)
2710 {
2711 	struct aac_cmd *acp = &softs->sync_ac;
2712 	ddi_acc_handle_t acc;
2713 	struct aac_fib *fibp;
2714 	struct aac_Container *cmd;
2715 	struct aac_Container_resp *resp;
2716 	struct aac_cf_status_header *cfg_sts_hdr;
2717 	uint32_t resp_status;
2718 	uint32_t ct_status;
2719 	uint32_t cfg_stat_action;
2720 	int rval;
2721 
2722 	(void) aac_sync_fib_slot_bind(softs, acp);
2723 	acc = acp->slotp->fib_acc_handle;
2724 	fibp = acp->slotp->fibp;
2725 
2726 	/* Get adapter config status */
2727 	cmd = (struct aac_Container *)&fibp->data[0];
2728 
2729 	bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
2730 	ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
2731 	ddi_put32(acc, &cmd->CTCommand.command, CT_GET_CONFIG_STATUS);
2732 	ddi_put32(acc, &cmd->CTCommand.param[CNT_SIZE],
2733 	    sizeof (struct aac_cf_status_header));
2734 	rval = aac_sync_fib(softs, ContainerCommand,
2735 	    AAC_FIB_SIZEOF(struct aac_Container));
2736 	resp = (struct aac_Container_resp *)cmd;
2737 	cfg_sts_hdr = (struct aac_cf_status_header *)resp->CTResponse.data;
2738 
2739 	resp_status = ddi_get32(acc, &resp->Status);
2740 	ct_status = ddi_get32(acc, &resp->CTResponse.param[0]);
2741 	if ((rval == AACOK) && (resp_status == 0) && (ct_status == CT_OK)) {
2742 		cfg_stat_action = ddi_get32(acc, &cfg_sts_hdr->action);
2743 
2744 		/* Commit configuration if it's reasonable to do so. */
2745 		if (cfg_stat_action <= CFACT_PAUSE) {
2746 			bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
2747 			ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
2748 			ddi_put32(acc, &cmd->CTCommand.command,
2749 			    CT_COMMIT_CONFIG);
2750 			rval = aac_sync_fib(softs, ContainerCommand,
2751 			    AAC_FIB_SIZEOF(struct aac_Container));
2752 
2753 			resp_status = ddi_get32(acc, &resp->Status);
2754 			ct_status = ddi_get32(acc, &resp->CTResponse.param[0]);
2755 			if ((rval == AACOK) && (resp_status == 0) &&
2756 			    (ct_status == CT_OK))
2757 				/* Successful completion */
2758 				rval = AACMPE_OK;
2759 			else
2760 				/* Auto-commit aborted due to error(s). */
2761 				rval = AACMPE_COMMIT_CONFIG;
2762 		} else {
2763 			/*
2764 			 * Auto-commit aborted due to adapter indicating
2765 			 * configuration issue(s) too dangerous to auto-commit.
2766 			 */
2767 			rval = AACMPE_CONFIG_STATUS;
2768 		}
2769 	} else {
2770 		cmn_err(CE_WARN, "!Configuration issue, auto-commit aborted");
2771 		rval = AACMPE_CONFIG_STATUS;
2772 	}
2773 
2774 	aac_sync_fib_slot_release(softs, acp);
2775 	return (rval);
2776 }
2777 
2778 /*
2779  * Hardware initialization and resource allocation
2780  */
2781 static int
aac_common_attach(struct aac_softstate * softs)2782 aac_common_attach(struct aac_softstate *softs)
2783 {
2784 	uint32_t status;
2785 	int i;
2786 	struct aac_supplement_adapter_info sinf;
2787 
2788 	DBCALLED(softs, 1);
2789 
2790 	/*
2791 	 * Do a little check here to make sure there aren't any outstanding
2792 	 * FIBs in the message queue. At this point there should not be and
2793 	 * if there are they are probably left over from another instance of
2794 	 * the driver like when the system crashes and the crash dump driver
2795 	 * gets loaded.
2796 	 */
2797 	while (AAC_OUTB_GET(softs) != 0xfffffffful)
2798 		;
2799 
2800 	/*
2801 	 * Wait the card to complete booting up before do anything that
2802 	 * attempts to communicate with it.
2803 	 */
2804 	status = AAC_FWSTATUS_GET(softs);
2805 	if (status == AAC_SELF_TEST_FAILED || status == AAC_KERNEL_PANIC)
2806 		goto error;
2807 	i = AAC_FWUP_TIMEOUT * 1000; /* set timeout */
2808 	AAC_BUSYWAIT(AAC_FWSTATUS_GET(softs) & AAC_KERNEL_UP_AND_RUNNING, i);
2809 	if (i == 0) {
2810 		cmn_err(CE_CONT, "?Fatal error: controller not ready");
2811 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
2812 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2813 		goto error;
2814 	}
2815 
2816 	/* Read and set card supported options and settings */
2817 	if (aac_check_firmware(softs) == AACERR) {
2818 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
2819 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2820 		goto error;
2821 	}
2822 
2823 	/* Add interrupt handlers */
2824 	if (aac_register_intrs(softs) == AACERR) {
2825 		cmn_err(CE_CONT,
2826 		    "?Fatal error: interrupts register failed");
2827 		goto error;
2828 	}
2829 
2830 	/* Setup communication space with the card */
2831 	if (softs->comm_space_dma_handle == NULL) {
2832 		if (aac_alloc_comm_space(softs) != AACOK)
2833 			goto error;
2834 	}
2835 	if (aac_setup_comm_space(softs) != AACOK) {
2836 		cmn_err(CE_CONT, "?Setup communication space failed");
2837 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
2838 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2839 		goto error;
2840 	}
2841 
2842 #ifdef DEBUG
2843 	if (aac_get_fw_debug_buffer(softs) != AACOK)
2844 		cmn_err(CE_CONT, "?firmware UART trace not supported");
2845 #endif
2846 
2847 	/* Allocate slots */
2848 	if ((softs->total_slots == 0) && (aac_create_slots(softs) != AACOK)) {
2849 		cmn_err(CE_CONT, "?Fatal error: slots allocate failed");
2850 		goto error;
2851 	}
2852 	AACDB_PRINT(softs, CE_NOTE, "%d slots allocated", softs->total_slots);
2853 
2854 	/* Allocate FIBs */
2855 	if (softs->total_fibs < softs->total_slots) {
2856 		aac_alloc_fibs(softs);
2857 		if (softs->total_fibs == 0)
2858 			goto error;
2859 		AACDB_PRINT(softs, CE_NOTE, "%d fibs allocated",
2860 		    softs->total_fibs);
2861 	}
2862 
2863 	AAC_STATUS_CLR(softs, ~0); /* Clear out all interrupts */
2864 	AAC_ENABLE_INTR(softs); /* Enable the interrupts we can handle */
2865 
2866 	if (aac_get_adapter_info(softs, NULL, &sinf) == AACOK) {
2867 		softs->feature_bits = sinf.FeatureBits;
2868 		softs->support_opt2 = sinf.SupportedOptions2;
2869 
2870 		/* Get adapter names */
2871 		if (CARD_IS_UNKNOWN(softs->card)) {
2872 			char *p, *p0, *p1;
2873 
2874 			/*
2875 			 * Now find the controller name in supp_adapter_info->
2876 			 * AdapterTypeText. Use the first word as the vendor
2877 			 * and the other words as the product name.
2878 			 */
2879 			AACDB_PRINT(softs, CE_NOTE, "sinf.AdapterTypeText = "
2880 			    "\"%s\"", sinf.AdapterTypeText);
2881 			p = sinf.AdapterTypeText;
2882 			p0 = p1 = NULL;
2883 			/* Skip heading spaces */
2884 			while (*p && (*p == ' ' || *p == '\t'))
2885 				p++;
2886 			p0 = p;
2887 			while (*p && (*p != ' ' && *p != '\t'))
2888 				p++;
2889 			/* Remove middle spaces */
2890 			while (*p && (*p == ' ' || *p == '\t'))
2891 				*p++ = 0;
2892 			p1 = p;
2893 			/* Remove trailing spaces */
2894 			p = p1 + strlen(p1) - 1;
2895 			while (p > p1 && (*p == ' ' || *p == '\t'))
2896 				*p-- = 0;
2897 			if (*p0 && *p1) {
2898 				(void *)strncpy(softs->vendor_name, p0,
2899 				    AAC_VENDOR_LEN);
2900 				(void *)strncpy(softs->product_name, p1,
2901 				    AAC_PRODUCT_LEN);
2902 			} else {
2903 				cmn_err(CE_WARN,
2904 				    "?adapter name mis-formatted\n");
2905 				if (*p0)
2906 					(void *)strncpy(softs->product_name,
2907 					    p0, AAC_PRODUCT_LEN);
2908 			}
2909 		}
2910 	} else {
2911 		cmn_err(CE_CONT, "?Query adapter information failed");
2912 	}
2913 
2914 
2915 	cmn_err(CE_NOTE,
2916 	    "!aac driver %d.%02d.%02d-%d, found card: " \
2917 	    "%s %s(pci0x%x.%x.%x.%x) at 0x%x",
2918 	    AAC_DRIVER_MAJOR_VERSION,
2919 	    AAC_DRIVER_MINOR_VERSION,
2920 	    AAC_DRIVER_BUGFIX_LEVEL,
2921 	    AAC_DRIVER_BUILD,
2922 	    softs->vendor_name, softs->product_name,
2923 	    softs->vendid, softs->devid, softs->subvendid, softs->subsysid,
2924 	    softs->pci_mem_base_paddr);
2925 
2926 	/* Perform acceptance of adapter-detected config changes if possible */
2927 	if (aac_handle_adapter_config_issues(softs) != AACMPE_OK) {
2928 		cmn_err(CE_CONT, "?Handle adapter config issues failed");
2929 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
2930 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2931 		goto error;
2932 	}
2933 
2934 	/* Setup containers (logical devices) */
2935 	if (aac_probe_containers(softs) != AACOK) {
2936 		cmn_err(CE_CONT, "?Fatal error: get container info error");
2937 		goto error;
2938 	}
2939 
2940 	/* Check for JBOD support. Default disable */
2941 	char *data;
2942 	if (softs->feature_bits & AAC_FEATURE_SUPPORTED_JBOD) {
2943 		if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, softs->devinfo_p,
2944 		    0, "jbod-enable", &data) == DDI_SUCCESS)) {
2945 			if (strcmp(data, "yes") == 0) {
2946 				AACDB_PRINT(softs, CE_NOTE,
2947 				    "Enable JBOD access");
2948 				softs->flags |= AAC_FLAGS_JBOD;
2949 			}
2950 			ddi_prop_free(data);
2951 		}
2952 	}
2953 
2954 	/* Setup phys. devices */
2955 	if (softs->flags & (AAC_FLAGS_NONDASD | AAC_FLAGS_JBOD)) {
2956 		uint32_t bus_max, tgt_max;
2957 		uint32_t bus, tgt;
2958 		int index;
2959 
2960 		if (aac_get_bus_info(softs, &bus_max, &tgt_max) != AACOK) {
2961 			cmn_err(CE_CONT, "?Fatal error: get bus info error");
2962 			goto error;
2963 		}
2964 		AACDB_PRINT(softs, CE_NOTE, "bus_max=%d, tgt_max=%d",
2965 		    bus_max, tgt_max);
2966 		if (bus_max != softs->bus_max || tgt_max != softs->tgt_max) {
2967 			if (softs->state & AAC_STATE_RESET) {
2968 				cmn_err(CE_WARN,
2969 				    "?Fatal error: bus map changed");
2970 				goto error;
2971 			}
2972 			softs->bus_max = bus_max;
2973 			softs->tgt_max = tgt_max;
2974 			if (softs->nondasds) {
2975 				kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
2976 				    sizeof (struct aac_nondasd));
2977 			}
2978 			softs->nondasds = kmem_zalloc(AAC_MAX_PD(softs) * \
2979 			    sizeof (struct aac_nondasd), KM_SLEEP);
2980 
2981 			index = 0;
2982 			for (bus = 0; bus < softs->bus_max; bus++) {
2983 				for (tgt = 0; tgt < softs->tgt_max; tgt++) {
2984 					struct aac_nondasd *dvp =
2985 					    &softs->nondasds[index++];
2986 					dvp->dev.type = AAC_DEV_PD;
2987 					dvp->bus = bus;
2988 					dvp->tid = tgt;
2989 				}
2990 			}
2991 		}
2992 	}
2993 
2994 	/* Check dma & acc handles allocated in attach */
2995 	if (aac_check_dma_handle(softs->comm_space_dma_handle) != DDI_SUCCESS) {
2996 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2997 		goto error;
2998 	}
2999 
3000 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
3001 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
3002 		goto error;
3003 	}
3004 
3005 	for (i = 0; i < softs->total_slots; i++) {
3006 		if (aac_check_dma_handle(softs->io_slot[i].fib_dma_handle) !=
3007 		    DDI_SUCCESS) {
3008 			ddi_fm_service_impact(softs->devinfo_p,
3009 			    DDI_SERVICE_LOST);
3010 			goto error;
3011 		}
3012 	}
3013 
3014 	return (AACOK);
3015 error:
3016 	if (softs->state & AAC_STATE_RESET)
3017 		return (AACERR);
3018 	if (softs->nondasds) {
3019 		kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
3020 		    sizeof (struct aac_nondasd));
3021 		softs->nondasds = NULL;
3022 	}
3023 	if (softs->total_fibs > 0)
3024 		aac_destroy_fibs(softs);
3025 	if (softs->total_slots > 0)
3026 		aac_destroy_slots(softs);
3027 	if (softs->comm_space_dma_handle)
3028 		aac_free_comm_space(softs);
3029 	return (AACERR);
3030 }
3031 
3032 /*
3033  * Hardware shutdown and resource release
3034  */
3035 static void
aac_common_detach(struct aac_softstate * softs)3036 aac_common_detach(struct aac_softstate *softs)
3037 {
3038 	DBCALLED(softs, 1);
3039 
3040 	aac_unregister_intrs(softs);
3041 
3042 	mutex_enter(&softs->io_lock);
3043 	(void) aac_shutdown(softs);
3044 
3045 	if (softs->nondasds) {
3046 		kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
3047 		    sizeof (struct aac_nondasd));
3048 		softs->nondasds = NULL;
3049 	}
3050 	aac_destroy_fibs(softs);
3051 	aac_destroy_slots(softs);
3052 	aac_free_comm_space(softs);
3053 	mutex_exit(&softs->io_lock);
3054 }
3055 
3056 /*
3057  * Send a synchronous command to the controller and wait for a result.
3058  * Indicate if the controller completed the command with an error status.
3059  */
3060 int
aac_sync_mbcommand(struct aac_softstate * softs,uint32_t cmd,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3,uint32_t * statusp)3061 aac_sync_mbcommand(struct aac_softstate *softs, uint32_t cmd,
3062     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3,
3063     uint32_t *statusp)
3064 {
3065 	int timeout;
3066 	uint32_t status;
3067 
3068 	if (statusp != NULL)
3069 		*statusp = SRB_STATUS_SUCCESS;
3070 
3071 	/* Fill in mailbox */
3072 	AAC_MAILBOX_SET(softs, cmd, arg0, arg1, arg2, arg3);
3073 
3074 	/* Ensure the sync command doorbell flag is cleared */
3075 	AAC_STATUS_CLR(softs, AAC_DB_SYNC_COMMAND);
3076 
3077 	/* Then set it to signal the adapter */
3078 	AAC_NOTIFY(softs, AAC_DB_SYNC_COMMAND);
3079 
3080 	/* Spin waiting for the command to complete */
3081 	timeout = AAC_IMMEDIATE_TIMEOUT * 1000;
3082 	AAC_BUSYWAIT(AAC_STATUS_GET(softs) & AAC_DB_SYNC_COMMAND, timeout);
3083 	if (!timeout) {
3084 		AACDB_PRINT(softs, CE_WARN,
3085 		    "Sync command timed out after %d seconds (0x%x)!",
3086 		    AAC_IMMEDIATE_TIMEOUT, AAC_FWSTATUS_GET(softs));
3087 		return (AACERR);
3088 	}
3089 
3090 	/* Clear the completion flag */
3091 	AAC_STATUS_CLR(softs, AAC_DB_SYNC_COMMAND);
3092 
3093 	/* Get the command status */
3094 	status = AAC_MAILBOX_GET(softs, 0);
3095 	if (statusp != NULL)
3096 		*statusp = status;
3097 	if (status != SRB_STATUS_SUCCESS) {
3098 		AACDB_PRINT(softs, CE_WARN,
3099 		    "Sync command fail: status = 0x%x", status);
3100 		return (AACERR);
3101 	}
3102 
3103 	return (AACOK);
3104 }
3105 
3106 /*
3107  * Send a synchronous FIB to the adapter and wait for its completion
3108  */
3109 static int
aac_sync_fib(struct aac_softstate * softs,uint16_t cmd,uint16_t fibsize)3110 aac_sync_fib(struct aac_softstate *softs, uint16_t cmd, uint16_t fibsize)
3111 {
3112 	struct aac_cmd *acp = &softs->sync_ac;
3113 
3114 	acp->flags = AAC_CMD_SYNC | AAC_CMD_IN_SYNC_SLOT;
3115 	if (softs->state & AAC_STATE_INTR)
3116 		acp->flags |= AAC_CMD_NO_CB;
3117 	else
3118 		acp->flags |= AAC_CMD_NO_INTR;
3119 
3120 	acp->ac_comp = aac_sync_complete;
3121 	acp->timeout = AAC_SYNC_TIMEOUT;
3122 	acp->fib_size = fibsize;
3123 
3124 	/*
3125 	 * Only need to setup sync fib header, caller should have init
3126 	 * fib data
3127 	 */
3128 	aac_cmd_fib_header(softs, acp, cmd);
3129 
3130 	(void) ddi_dma_sync(acp->slotp->fib_dma_handle, 0, fibsize,
3131 	    DDI_DMA_SYNC_FORDEV);
3132 
3133 	aac_start_io(softs, acp);
3134 
3135 	if (softs->state & AAC_STATE_INTR)
3136 		return (aac_do_sync_io(softs, acp));
3137 	else
3138 		return (aac_do_poll_io(softs, acp));
3139 }
3140 
3141 static void
aac_cmd_initq(struct aac_cmd_queue * q)3142 aac_cmd_initq(struct aac_cmd_queue *q)
3143 {
3144 	q->q_head = NULL;
3145 	q->q_tail = (struct aac_cmd *)&q->q_head;
3146 }
3147 
3148 /*
3149  * Remove a cmd from the head of q
3150  */
3151 static struct aac_cmd *
aac_cmd_dequeue(struct aac_cmd_queue * q)3152 aac_cmd_dequeue(struct aac_cmd_queue *q)
3153 {
3154 	struct aac_cmd *acp;
3155 
3156 	_NOTE(ASSUMING_PROTECTED(*q))
3157 
3158 	if ((acp = q->q_head) != NULL) {
3159 		if ((q->q_head = acp->next) != NULL)
3160 			acp->next = NULL;
3161 		else
3162 			q->q_tail = (struct aac_cmd *)&q->q_head;
3163 		acp->prev = NULL;
3164 	}
3165 	return (acp);
3166 }
3167 
3168 /*
3169  * Add a cmd to the tail of q
3170  */
3171 static void
aac_cmd_enqueue(struct aac_cmd_queue * q,struct aac_cmd * acp)3172 aac_cmd_enqueue(struct aac_cmd_queue *q, struct aac_cmd *acp)
3173 {
3174 	ASSERT(acp->next == NULL);
3175 	acp->prev = q->q_tail;
3176 	q->q_tail->next = acp;
3177 	q->q_tail = acp;
3178 }
3179 
3180 /*
3181  * Remove the cmd ac from q
3182  */
3183 static void
aac_cmd_delete(struct aac_cmd_queue * q,struct aac_cmd * acp)3184 aac_cmd_delete(struct aac_cmd_queue *q, struct aac_cmd *acp)
3185 {
3186 	if (acp->prev) {
3187 		if ((acp->prev->next = acp->next) != NULL) {
3188 			acp->next->prev = acp->prev;
3189 			acp->next = NULL;
3190 		} else {
3191 			q->q_tail = acp->prev;
3192 		}
3193 		acp->prev = NULL;
3194 	}
3195 	/* ac is not in the queue */
3196 }
3197 
3198 /*
3199  * Atomically insert an entry into the nominated queue, returns 0 on success or
3200  * AACERR if the queue is full.
3201  *
3202  * Note: it would be more efficient to defer notifying the controller in
3203  *	 the case where we may be inserting several entries in rapid succession,
3204  *	 but implementing this usefully may be difficult (it would involve a
3205  *	 separate queue/notify interface).
3206  */
3207 static int
aac_fib_enqueue(struct aac_softstate * softs,int queue,uint32_t fib_addr,uint32_t fib_size)3208 aac_fib_enqueue(struct aac_softstate *softs, int queue, uint32_t fib_addr,
3209     uint32_t fib_size)
3210 {
3211 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
3212 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
3213 	uint32_t pi, ci;
3214 
3215 	DBCALLED(softs, 2);
3216 
3217 	ASSERT(queue == AAC_ADAP_NORM_CMD_Q || queue == AAC_ADAP_NORM_RESP_Q);
3218 
3219 	/* Get the producer/consumer indices */
3220 	(void) ddi_dma_sync(dma, (uintptr_t)softs->qtablep->qt_qindex[queue] - \
3221 	    (uintptr_t)softs->comm_space, sizeof (uint32_t) * 2,
3222 	    DDI_DMA_SYNC_FORCPU);
3223 	if (aac_check_dma_handle(dma) != DDI_SUCCESS) {
3224 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
3225 		return (AACERR);
3226 	}
3227 
3228 	pi = ddi_get32(acc,
3229 	    &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX]);
3230 	ci = ddi_get32(acc,
3231 	    &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX]);
3232 
3233 	/*
3234 	 * Wrap the queue first before we check the queue to see
3235 	 * if it is full
3236 	 */
3237 	if (pi >= aac_qinfo[queue].size)
3238 		pi = 0;
3239 
3240 	/* XXX queue full */
3241 	if ((pi + 1) == ci)
3242 		return (AACERR);
3243 
3244 	/* Fill in queue entry */
3245 	ddi_put32(acc, &((softs->qentries[queue] + pi)->aq_fib_size), fib_size);
3246 	ddi_put32(acc, &((softs->qentries[queue] + pi)->aq_fib_addr), fib_addr);
3247 	(void) ddi_dma_sync(dma, (uintptr_t)(softs->qentries[queue] + pi) - \
3248 	    (uintptr_t)softs->comm_space, sizeof (struct aac_queue_entry),
3249 	    DDI_DMA_SYNC_FORDEV);
3250 
3251 	/* Update producer index */
3252 	ddi_put32(acc, &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX],
3253 	    pi + 1);
3254 	(void) ddi_dma_sync(dma,
3255 	    (uintptr_t)&softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX] - \
3256 	    (uintptr_t)softs->comm_space, sizeof (uint32_t),
3257 	    DDI_DMA_SYNC_FORDEV);
3258 
3259 	if (aac_qinfo[queue].notify != 0)
3260 		AAC_NOTIFY(softs, aac_qinfo[queue].notify);
3261 	return (AACOK);
3262 }
3263 
3264 /*
3265  * Atomically remove one entry from the nominated queue, returns 0 on
3266  * success or AACERR if the queue is empty.
3267  */
3268 static int
aac_fib_dequeue(struct aac_softstate * softs,int queue,int * idxp)3269 aac_fib_dequeue(struct aac_softstate *softs, int queue, int *idxp)
3270 {
3271 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
3272 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
3273 	uint32_t pi, ci;
3274 	int unfull = 0;
3275 
3276 	DBCALLED(softs, 2);
3277 
3278 	ASSERT(idxp);
3279 
3280 	/* Get the producer/consumer indices */
3281 	(void) ddi_dma_sync(dma, (uintptr_t)softs->qtablep->qt_qindex[queue] - \
3282 	    (uintptr_t)softs->comm_space, sizeof (uint32_t) * 2,
3283 	    DDI_DMA_SYNC_FORCPU);
3284 	pi = ddi_get32(acc,
3285 	    &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX]);
3286 	ci = ddi_get32(acc,
3287 	    &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX]);
3288 
3289 	/* Check for queue empty */
3290 	if (ci == pi)
3291 		return (AACERR);
3292 
3293 	if (pi >= aac_qinfo[queue].size)
3294 		pi = 0;
3295 
3296 	/* Check for queue full */
3297 	if (ci == pi + 1)
3298 		unfull = 1;
3299 
3300 	/*
3301 	 * The controller does not wrap the queue,
3302 	 * so we have to do it by ourselves
3303 	 */
3304 	if (ci >= aac_qinfo[queue].size)
3305 		ci = 0;
3306 
3307 	/* Fetch the entry */
3308 	(void) ddi_dma_sync(dma, (uintptr_t)(softs->qentries[queue] + pi) - \
3309 	    (uintptr_t)softs->comm_space, sizeof (struct aac_queue_entry),
3310 	    DDI_DMA_SYNC_FORCPU);
3311 	if (aac_check_dma_handle(dma) != DDI_SUCCESS) {
3312 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
3313 		return (AACERR);
3314 	}
3315 
3316 	switch (queue) {
3317 	case AAC_HOST_NORM_RESP_Q:
3318 	case AAC_HOST_HIGH_RESP_Q:
3319 		*idxp = ddi_get32(acc,
3320 		    &(softs->qentries[queue] + ci)->aq_fib_addr);
3321 		break;
3322 
3323 	case AAC_HOST_NORM_CMD_Q:
3324 	case AAC_HOST_HIGH_CMD_Q:
3325 		*idxp = ddi_get32(acc,
3326 		    &(softs->qentries[queue] + ci)->aq_fib_addr) / AAC_FIB_SIZE;
3327 		break;
3328 
3329 	default:
3330 		cmn_err(CE_NOTE, "!Invalid queue in aac_fib_dequeue()");
3331 		return (AACERR);
3332 	}
3333 
3334 	/* Update consumer index */
3335 	ddi_put32(acc, &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX],
3336 	    ci + 1);
3337 	(void) ddi_dma_sync(dma,
3338 	    (uintptr_t)&softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX] - \
3339 	    (uintptr_t)softs->comm_space, sizeof (uint32_t),
3340 	    DDI_DMA_SYNC_FORDEV);
3341 
3342 	if (unfull && aac_qinfo[queue].notify != 0)
3343 		AAC_NOTIFY(softs, aac_qinfo[queue].notify);
3344 	return (AACOK);
3345 }
3346 
3347 static struct aac_mntinforesp *
aac_get_mntinfo(struct aac_softstate * softs,int cid)3348 aac_get_mntinfo(struct aac_softstate *softs, int cid)
3349 {
3350 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
3351 	struct aac_fib *fibp = softs->sync_ac.slotp->fibp;
3352 	struct aac_mntinfo *mi = (struct aac_mntinfo *)&fibp->data[0];
3353 	struct aac_mntinforesp *mir;
3354 
3355 	ddi_put32(acc, &mi->Command, /* Use 64-bit LBA if enabled */
3356 	    (softs->flags & AAC_FLAGS_LBA_64BIT) ?
3357 	    VM_NameServe64 : VM_NameServe);
3358 	ddi_put32(acc, &mi->MntType, FT_FILESYS);
3359 	ddi_put32(acc, &mi->MntCount, cid);
3360 
3361 	if (aac_sync_fib(softs, ContainerCommand,
3362 	    AAC_FIB_SIZEOF(struct aac_mntinfo)) == AACERR) {
3363 		AACDB_PRINT(softs, CE_WARN, "Error probe container %d", cid);
3364 		return (NULL);
3365 	}
3366 
3367 	mir = (struct aac_mntinforesp *)&fibp->data[0];
3368 	if (ddi_get32(acc, &mir->Status) == ST_OK)
3369 		return (mir);
3370 	return (NULL);
3371 }
3372 
3373 static int
aac_get_container_count(struct aac_softstate * softs,int * count)3374 aac_get_container_count(struct aac_softstate *softs, int *count)
3375 {
3376 	ddi_acc_handle_t acc;
3377 	struct aac_mntinforesp *mir;
3378 	int rval;
3379 
3380 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
3381 	acc = softs->sync_ac.slotp->fib_acc_handle;
3382 
3383 	if ((mir = aac_get_mntinfo(softs, 0)) == NULL) {
3384 		rval = AACERR;
3385 		goto finish;
3386 	}
3387 	*count = ddi_get32(acc, &mir->MntRespCount);
3388 	if (*count > AAC_MAX_LD) {
3389 		AACDB_PRINT(softs, CE_CONT,
3390 		    "container count(%d) > AAC_MAX_LD", *count);
3391 		rval = AACERR;
3392 		goto finish;
3393 	}
3394 	rval = AACOK;
3395 
3396 finish:
3397 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
3398 	return (rval);
3399 }
3400 
3401 static int
aac_get_container_uid(struct aac_softstate * softs,uint32_t cid,uint32_t * uid)3402 aac_get_container_uid(struct aac_softstate *softs, uint32_t cid, uint32_t *uid)
3403 {
3404 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
3405 	struct aac_Container *ct = (struct aac_Container *) \
3406 	    &softs->sync_ac.slotp->fibp->data[0];
3407 
3408 	bzero(ct, sizeof (*ct) - CT_PACKET_SIZE);
3409 	ddi_put32(acc, &ct->Command, VM_ContainerConfig);
3410 	ddi_put32(acc, &ct->CTCommand.command, CT_CID_TO_32BITS_UID);
3411 	ddi_put32(acc, &ct->CTCommand.param[0], cid);
3412 
3413 	if (aac_sync_fib(softs, ContainerCommand,
3414 	    AAC_FIB_SIZEOF(struct aac_Container)) == AACERR)
3415 		return (AACERR);
3416 	if (ddi_get32(acc, &ct->CTCommand.param[0]) != CT_OK)
3417 		return (AACERR);
3418 
3419 	*uid = ddi_get32(acc, &ct->CTCommand.param[1]);
3420 	return (AACOK);
3421 }
3422 
3423 /*
3424  * Request information of the container cid
3425  */
3426 static struct aac_mntinforesp *
aac_get_container_info(struct aac_softstate * softs,int cid)3427 aac_get_container_info(struct aac_softstate *softs, int cid)
3428 {
3429 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
3430 	struct aac_mntinforesp *mir;
3431 	int rval_uid;
3432 	uint32_t uid;
3433 
3434 	/* Get container UID first so that it will not overwrite mntinfo */
3435 	rval_uid = aac_get_container_uid(softs, cid, &uid);
3436 
3437 	/* Get container basic info */
3438 	if ((mir = aac_get_mntinfo(softs, cid)) == NULL) {
3439 		AACDB_PRINT(softs, CE_CONT,
3440 		    "query container %d info failed", cid);
3441 		return (NULL);
3442 	}
3443 	if (ddi_get32(acc, &mir->MntObj.VolType) == CT_NONE)
3444 		return (mir);
3445 	if (rval_uid != AACOK) {
3446 		AACDB_PRINT(softs, CE_CONT,
3447 		    "query container %d uid failed", cid);
3448 		return (NULL);
3449 	}
3450 
3451 	ddi_put32(acc, &mir->Status, uid);
3452 	return (mir);
3453 }
3454 
3455 static enum aac_cfg_event
aac_probe_container(struct aac_softstate * softs,uint32_t cid)3456 aac_probe_container(struct aac_softstate *softs, uint32_t cid)
3457 {
3458 	enum aac_cfg_event event = AAC_CFG_NULL_NOEXIST;
3459 	struct aac_container *dvp = &softs->containers[cid];
3460 	struct aac_mntinforesp *mir;
3461 	ddi_acc_handle_t acc;
3462 
3463 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
3464 	acc = softs->sync_ac.slotp->fib_acc_handle;
3465 
3466 	/* Get container basic info */
3467 	if ((mir = aac_get_container_info(softs, cid)) == NULL) {
3468 		/* AAC_CFG_NULL_NOEXIST */
3469 		goto finish;
3470 	}
3471 
3472 	if (ddi_get32(acc, &mir->MntObj.VolType) == CT_NONE) {
3473 		if (AAC_DEV_IS_VALID(&dvp->dev)) {
3474 			AACDB_PRINT(softs, CE_NOTE,
3475 			    ">>> Container %d deleted", cid);
3476 			dvp->dev.flags &= ~AAC_DFLAG_VALID;
3477 			event = AAC_CFG_DELETE;
3478 		}
3479 		/* AAC_CFG_NULL_NOEXIST */
3480 	} else {
3481 		uint64_t size;
3482 		uint32_t uid;
3483 
3484 		event = AAC_CFG_NULL_EXIST;
3485 
3486 		size = AAC_MIR_SIZE(softs, acc, mir);
3487 		uid = ddi_get32(acc, &mir->Status);
3488 		if (AAC_DEV_IS_VALID(&dvp->dev)) {
3489 			if (dvp->uid != uid) {
3490 				AACDB_PRINT(softs, CE_WARN,
3491 				    ">>> Container %u uid changed to %d",
3492 				    cid, uid);
3493 				dvp->uid = uid;
3494 				event = AAC_CFG_CHANGE;
3495 			}
3496 			if (dvp->size != size) {
3497 				AACDB_PRINT(softs, CE_NOTE,
3498 				    ">>> Container %u size changed to %"PRIu64,
3499 				    cid, size);
3500 				dvp->size = size;
3501 				event = AAC_CFG_CHANGE;
3502 			}
3503 		} else { /* Init new container */
3504 			AACDB_PRINT(softs, CE_NOTE,
3505 			    ">>> Container %d added: " \
3506 			    "size=0x%x.%08x, type=%d, name=%s",
3507 			    cid,
3508 			    ddi_get32(acc, &mir->MntObj.CapacityHigh),
3509 			    ddi_get32(acc, &mir->MntObj.Capacity),
3510 			    ddi_get32(acc, &mir->MntObj.VolType),
3511 			    mir->MntObj.FileSystemName);
3512 			dvp->dev.flags |= AAC_DFLAG_VALID;
3513 			dvp->dev.type = AAC_DEV_LD;
3514 
3515 			dvp->cid = cid;
3516 			dvp->uid = uid;
3517 			dvp->size = size;
3518 			dvp->locked = 0;
3519 			dvp->deleted = 0;
3520 
3521 			event = AAC_CFG_ADD;
3522 		}
3523 	}
3524 
3525 finish:
3526 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
3527 	return (event);
3528 }
3529 
3530 /*
3531  * Do a rescan of all the possible containers and update the container list
3532  * with newly online/offline containers, and prepare for autoconfiguration.
3533  */
3534 static int
aac_probe_containers(struct aac_softstate * softs)3535 aac_probe_containers(struct aac_softstate *softs)
3536 {
3537 	int i, count, total;
3538 
3539 	/* Loop over possible containers */
3540 	count = softs->container_count;
3541 	if (aac_get_container_count(softs, &count) == AACERR)
3542 		return (AACERR);
3543 
3544 	for (i = total = 0; i < count; i++) {
3545 		enum aac_cfg_event event = aac_probe_container(softs, i);
3546 		if ((event != AAC_CFG_NULL_NOEXIST) &&
3547 		    (event != AAC_CFG_NULL_EXIST)) {
3548 			(void) aac_handle_dr(softs, i, -1, event);
3549 			total++;
3550 		}
3551 	}
3552 
3553 	if (count < softs->container_count) {
3554 		struct aac_container *dvp;
3555 
3556 		for (dvp = &softs->containers[count];
3557 		    dvp < &softs->containers[softs->container_count]; dvp++) {
3558 			if (!AAC_DEV_IS_VALID(&dvp->dev))
3559 				continue;
3560 			AACDB_PRINT(softs, CE_NOTE, ">>> Container %d deleted",
3561 			    dvp->cid);
3562 			dvp->dev.flags &= ~AAC_DFLAG_VALID;
3563 			(void) aac_handle_dr(softs, dvp->cid, -1,
3564 			    AAC_CFG_DELETE);
3565 		}
3566 	}
3567 
3568 	softs->container_count = count;
3569 	AACDB_PRINT(softs, CE_CONT, "?Total %d container(s) found", total);
3570 	return (AACOK);
3571 }
3572 
3573 static int
aac_probe_jbod(struct aac_softstate * softs,int tgt,int event)3574 aac_probe_jbod(struct aac_softstate *softs, int tgt, int event)
3575 {
3576 	ASSERT(AAC_MAX_LD <= tgt);
3577 	ASSERT(tgt < AAC_MAX_DEV(softs));
3578 	struct aac_device *dvp;
3579 	dvp = AAC_DEV(softs, tgt);
3580 
3581 	switch (event) {
3582 	case AAC_CFG_ADD:
3583 		AACDB_PRINT(softs, CE_NOTE,
3584 		    ">>> Jbod %d added", tgt - AAC_MAX_LD);
3585 		dvp->flags |= AAC_DFLAG_VALID;
3586 		dvp->type = AAC_DEV_PD;
3587 		break;
3588 	case AAC_CFG_DELETE:
3589 		AACDB_PRINT(softs, CE_NOTE,
3590 		    ">>> Jbod %d deleted", tgt - AAC_MAX_LD);
3591 		dvp->flags &= ~AAC_DFLAG_VALID;
3592 		break;
3593 	default:
3594 		return (AACERR);
3595 	}
3596 	(void) aac_handle_dr(softs, tgt, 0, event);
3597 	return (AACOK);
3598 }
3599 
3600 static int
aac_alloc_comm_space(struct aac_softstate * softs)3601 aac_alloc_comm_space(struct aac_softstate *softs)
3602 {
3603 	size_t rlen;
3604 	ddi_dma_cookie_t cookie;
3605 	uint_t cookien;
3606 
3607 	/* Allocate DMA for comm. space */
3608 	if (ddi_dma_alloc_handle(
3609 	    softs->devinfo_p,
3610 	    &softs->addr_dma_attr,
3611 	    DDI_DMA_SLEEP,
3612 	    NULL,
3613 	    &softs->comm_space_dma_handle) != DDI_SUCCESS) {
3614 		AACDB_PRINT(softs, CE_WARN,
3615 		    "Cannot alloc dma handle for communication area");
3616 		goto error;
3617 	}
3618 	if (ddi_dma_mem_alloc(
3619 	    softs->comm_space_dma_handle,
3620 	    sizeof (struct aac_comm_space),
3621 	    &softs->acc_attr,
3622 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
3623 	    DDI_DMA_SLEEP,
3624 	    NULL,
3625 	    (caddr_t *)&softs->comm_space,
3626 	    &rlen,
3627 	    &softs->comm_space_acc_handle) != DDI_SUCCESS) {
3628 		AACDB_PRINT(softs, CE_WARN,
3629 		    "Cannot alloc mem for communication area");
3630 		goto error;
3631 	}
3632 	if (ddi_dma_addr_bind_handle(
3633 	    softs->comm_space_dma_handle,
3634 	    NULL,
3635 	    (caddr_t)softs->comm_space,
3636 	    sizeof (struct aac_comm_space),
3637 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
3638 	    DDI_DMA_SLEEP,
3639 	    NULL,
3640 	    &cookie,
3641 	    &cookien) != DDI_DMA_MAPPED) {
3642 		AACDB_PRINT(softs, CE_WARN,
3643 		    "DMA bind failed for communication area");
3644 		goto error;
3645 	}
3646 	softs->comm_space_phyaddr = cookie.dmac_address;
3647 
3648 	return (AACOK);
3649 error:
3650 	if (softs->comm_space_acc_handle) {
3651 		ddi_dma_mem_free(&softs->comm_space_acc_handle);
3652 		softs->comm_space_acc_handle = NULL;
3653 	}
3654 	if (softs->comm_space_dma_handle) {
3655 		ddi_dma_free_handle(&softs->comm_space_dma_handle);
3656 		softs->comm_space_dma_handle = NULL;
3657 	}
3658 	return (AACERR);
3659 }
3660 
3661 static void
aac_free_comm_space(struct aac_softstate * softs)3662 aac_free_comm_space(struct aac_softstate *softs)
3663 {
3664 
3665 	(void) ddi_dma_unbind_handle(softs->comm_space_dma_handle);
3666 	ddi_dma_mem_free(&softs->comm_space_acc_handle);
3667 	softs->comm_space_acc_handle = NULL;
3668 	ddi_dma_free_handle(&softs->comm_space_dma_handle);
3669 	softs->comm_space_dma_handle = NULL;
3670 	softs->comm_space_phyaddr = 0;
3671 }
3672 
3673 /*
3674  * Initialize the data structures that are required for the communication
3675  * interface to operate
3676  */
3677 static int
aac_setup_comm_space(struct aac_softstate * softs)3678 aac_setup_comm_space(struct aac_softstate *softs)
3679 {
3680 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
3681 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
3682 	uint32_t comm_space_phyaddr;
3683 	struct aac_adapter_init *initp;
3684 	int qoffset;
3685 
3686 	comm_space_phyaddr = softs->comm_space_phyaddr;
3687 
3688 	/* Setup adapter init struct */
3689 	initp = &softs->comm_space->init_data;
3690 	bzero(initp, sizeof (struct aac_adapter_init));
3691 
3692 	ddi_put32(acc, &initp->InitStructRevision, AAC_INIT_STRUCT_REVISION);
3693 	ddi_put32(acc, &initp->HostElapsedSeconds, ddi_get_time());
3694 
3695 	/* Setup new/old comm. specific data */
3696 	if (softs->flags & AAC_FLAGS_RAW_IO) {
3697 		uint32_t init_flags = 0;
3698 
3699 		if (softs->flags & AAC_FLAGS_NEW_COMM)
3700 			init_flags |= AAC_INIT_FLAGS_NEW_COMM_SUPPORTED;
3701 		/* AAC_SUPPORTED_POWER_MANAGEMENT */
3702 		init_flags |= AAC_INIT_FLAGS_DRIVER_SUPPORTS_PM;
3703 		init_flags |= AAC_INIT_FLAGS_DRIVER_USES_UTC_TIME;
3704 
3705 		ddi_put32(acc, &initp->InitStructRevision,
3706 		    AAC_INIT_STRUCT_REVISION_4);
3707 		ddi_put32(acc, &initp->InitFlags, init_flags);
3708 		/* Setup the preferred settings */
3709 		ddi_put32(acc, &initp->MaxIoCommands, softs->aac_max_fibs);
3710 		ddi_put32(acc, &initp->MaxIoSize,
3711 		    (softs->aac_max_sectors << 9));
3712 		ddi_put32(acc, &initp->MaxFibSize, softs->aac_max_fib_size);
3713 	} else {
3714 		/*
3715 		 * Tells the adapter about the physical location of various
3716 		 * important shared data structures
3717 		 */
3718 		ddi_put32(acc, &initp->AdapterFibsPhysicalAddress,
3719 		    comm_space_phyaddr + \
3720 		    offsetof(struct aac_comm_space, adapter_fibs));
3721 		ddi_put32(acc, &initp->AdapterFibsVirtualAddress, 0);
3722 		ddi_put32(acc, &initp->AdapterFibAlign, AAC_FIB_SIZE);
3723 		ddi_put32(acc, &initp->AdapterFibsSize,
3724 		    AAC_ADAPTER_FIBS * AAC_FIB_SIZE);
3725 		ddi_put32(acc, &initp->PrintfBufferAddress,
3726 		    comm_space_phyaddr + \
3727 		    offsetof(struct aac_comm_space, adapter_print_buf));
3728 		ddi_put32(acc, &initp->PrintfBufferSize,
3729 		    AAC_ADAPTER_PRINT_BUFSIZE);
3730 		ddi_put32(acc, &initp->MiniPortRevision,
3731 		    AAC_INIT_STRUCT_MINIPORT_REVISION);
3732 		ddi_put32(acc, &initp->HostPhysMemPages, AAC_MAX_PFN);
3733 
3734 		qoffset = (comm_space_phyaddr + \
3735 		    offsetof(struct aac_comm_space, qtable)) % \
3736 		    AAC_QUEUE_ALIGN;
3737 		if (qoffset)
3738 			qoffset = AAC_QUEUE_ALIGN - qoffset;
3739 		softs->qtablep = (struct aac_queue_table *) \
3740 		    ((char *)&softs->comm_space->qtable + qoffset);
3741 		ddi_put32(acc, &initp->CommHeaderAddress, comm_space_phyaddr + \
3742 		    offsetof(struct aac_comm_space, qtable) + qoffset);
3743 
3744 		/* Init queue table */
3745 		ddi_put32(acc, &softs->qtablep-> \
3746 		    qt_qindex[AAC_HOST_NORM_CMD_Q][AAC_PRODUCER_INDEX],
3747 		    AAC_HOST_NORM_CMD_ENTRIES);
3748 		ddi_put32(acc, &softs->qtablep-> \
3749 		    qt_qindex[AAC_HOST_NORM_CMD_Q][AAC_CONSUMER_INDEX],
3750 		    AAC_HOST_NORM_CMD_ENTRIES);
3751 		ddi_put32(acc, &softs->qtablep-> \
3752 		    qt_qindex[AAC_HOST_HIGH_CMD_Q][AAC_PRODUCER_INDEX],
3753 		    AAC_HOST_HIGH_CMD_ENTRIES);
3754 		ddi_put32(acc, &softs->qtablep-> \
3755 		    qt_qindex[AAC_HOST_HIGH_CMD_Q][AAC_CONSUMER_INDEX],
3756 		    AAC_HOST_HIGH_CMD_ENTRIES);
3757 		ddi_put32(acc, &softs->qtablep-> \
3758 		    qt_qindex[AAC_ADAP_NORM_CMD_Q][AAC_PRODUCER_INDEX],
3759 		    AAC_ADAP_NORM_CMD_ENTRIES);
3760 		ddi_put32(acc, &softs->qtablep-> \
3761 		    qt_qindex[AAC_ADAP_NORM_CMD_Q][AAC_CONSUMER_INDEX],
3762 		    AAC_ADAP_NORM_CMD_ENTRIES);
3763 		ddi_put32(acc, &softs->qtablep-> \
3764 		    qt_qindex[AAC_ADAP_HIGH_CMD_Q][AAC_PRODUCER_INDEX],
3765 		    AAC_ADAP_HIGH_CMD_ENTRIES);
3766 		ddi_put32(acc, &softs->qtablep-> \
3767 		    qt_qindex[AAC_ADAP_HIGH_CMD_Q][AAC_CONSUMER_INDEX],
3768 		    AAC_ADAP_HIGH_CMD_ENTRIES);
3769 		ddi_put32(acc, &softs->qtablep-> \
3770 		    qt_qindex[AAC_HOST_NORM_RESP_Q][AAC_PRODUCER_INDEX],
3771 		    AAC_HOST_NORM_RESP_ENTRIES);
3772 		ddi_put32(acc, &softs->qtablep-> \
3773 		    qt_qindex[AAC_HOST_NORM_RESP_Q][AAC_CONSUMER_INDEX],
3774 		    AAC_HOST_NORM_RESP_ENTRIES);
3775 		ddi_put32(acc, &softs->qtablep-> \
3776 		    qt_qindex[AAC_HOST_HIGH_RESP_Q][AAC_PRODUCER_INDEX],
3777 		    AAC_HOST_HIGH_RESP_ENTRIES);
3778 		ddi_put32(acc, &softs->qtablep-> \
3779 		    qt_qindex[AAC_HOST_HIGH_RESP_Q][AAC_CONSUMER_INDEX],
3780 		    AAC_HOST_HIGH_RESP_ENTRIES);
3781 		ddi_put32(acc, &softs->qtablep-> \
3782 		    qt_qindex[AAC_ADAP_NORM_RESP_Q][AAC_PRODUCER_INDEX],
3783 		    AAC_ADAP_NORM_RESP_ENTRIES);
3784 		ddi_put32(acc, &softs->qtablep-> \
3785 		    qt_qindex[AAC_ADAP_NORM_RESP_Q][AAC_CONSUMER_INDEX],
3786 		    AAC_ADAP_NORM_RESP_ENTRIES);
3787 		ddi_put32(acc, &softs->qtablep-> \
3788 		    qt_qindex[AAC_ADAP_HIGH_RESP_Q][AAC_PRODUCER_INDEX],
3789 		    AAC_ADAP_HIGH_RESP_ENTRIES);
3790 		ddi_put32(acc, &softs->qtablep-> \
3791 		    qt_qindex[AAC_ADAP_HIGH_RESP_Q][AAC_CONSUMER_INDEX],
3792 		    AAC_ADAP_HIGH_RESP_ENTRIES);
3793 
3794 		/* Init queue entries */
3795 		softs->qentries[AAC_HOST_NORM_CMD_Q] =
3796 		    &softs->qtablep->qt_HostNormCmdQueue[0];
3797 		softs->qentries[AAC_HOST_HIGH_CMD_Q] =
3798 		    &softs->qtablep->qt_HostHighCmdQueue[0];
3799 		softs->qentries[AAC_ADAP_NORM_CMD_Q] =
3800 		    &softs->qtablep->qt_AdapNormCmdQueue[0];
3801 		softs->qentries[AAC_ADAP_HIGH_CMD_Q] =
3802 		    &softs->qtablep->qt_AdapHighCmdQueue[0];
3803 		softs->qentries[AAC_HOST_NORM_RESP_Q] =
3804 		    &softs->qtablep->qt_HostNormRespQueue[0];
3805 		softs->qentries[AAC_HOST_HIGH_RESP_Q] =
3806 		    &softs->qtablep->qt_HostHighRespQueue[0];
3807 		softs->qentries[AAC_ADAP_NORM_RESP_Q] =
3808 		    &softs->qtablep->qt_AdapNormRespQueue[0];
3809 		softs->qentries[AAC_ADAP_HIGH_RESP_Q] =
3810 		    &softs->qtablep->qt_AdapHighRespQueue[0];
3811 	}
3812 	(void) ddi_dma_sync(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
3813 
3814 	/* Send init structure to the card */
3815 	if (aac_sync_mbcommand(softs, AAC_MONKER_INITSTRUCT,
3816 	    comm_space_phyaddr + \
3817 	    offsetof(struct aac_comm_space, init_data),
3818 	    0, 0, 0, NULL) == AACERR) {
3819 		AACDB_PRINT(softs, CE_WARN,
3820 		    "Cannot send init structure to adapter");
3821 		return (AACERR);
3822 	}
3823 
3824 	return (AACOK);
3825 }
3826 
3827 static uchar_t *
aac_vendor_id(struct aac_softstate * softs,uchar_t * buf)3828 aac_vendor_id(struct aac_softstate *softs, uchar_t *buf)
3829 {
3830 	(void) memset(buf, ' ', AAC_VENDOR_LEN);
3831 	bcopy(softs->vendor_name, buf, strlen(softs->vendor_name));
3832 	return (buf + AAC_VENDOR_LEN);
3833 }
3834 
3835 static uchar_t *
aac_product_id(struct aac_softstate * softs,uchar_t * buf)3836 aac_product_id(struct aac_softstate *softs, uchar_t *buf)
3837 {
3838 	(void) memset(buf, ' ', AAC_PRODUCT_LEN);
3839 	bcopy(softs->product_name, buf, strlen(softs->product_name));
3840 	return (buf + AAC_PRODUCT_LEN);
3841 }
3842 
3843 /*
3844  * Construct unit serial number from container uid
3845  */
3846 static uchar_t *
aac_lun_serialno(struct aac_softstate * softs,int tgt,uchar_t * buf)3847 aac_lun_serialno(struct aac_softstate *softs, int tgt, uchar_t *buf)
3848 {
3849 	int i, d;
3850 	uint32_t uid;
3851 
3852 	ASSERT(tgt >= 0 && tgt < AAC_MAX_LD);
3853 
3854 	uid = softs->containers[tgt].uid;
3855 	for (i = 7; i >= 0; i--) {
3856 		d = uid & 0xf;
3857 		buf[i] = d > 9 ? 'A' + (d - 0xa) : '0' + d;
3858 		uid >>= 4;
3859 	}
3860 	return (buf + 8);
3861 }
3862 
3863 /*
3864  * SPC-3 7.5 INQUIRY command implementation
3865  */
3866 static void
aac_inquiry(struct aac_softstate * softs,struct scsi_pkt * pkt,union scsi_cdb * cdbp,struct buf * bp)3867 aac_inquiry(struct aac_softstate *softs, struct scsi_pkt *pkt,
3868     union scsi_cdb *cdbp, struct buf *bp)
3869 {
3870 	int tgt = pkt->pkt_address.a_target;
3871 	char *b_addr = NULL;
3872 	uchar_t page = cdbp->cdb_opaque[2];
3873 
3874 	if (cdbp->cdb_opaque[1] & AAC_CDB_INQUIRY_CMDDT) {
3875 		/* Command Support Data is not supported */
3876 		aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST, 0x24, 0x00, 0);
3877 		return;
3878 	}
3879 
3880 	if (bp && bp->b_un.b_addr && bp->b_bcount) {
3881 		if (bp->b_flags & (B_PHYS | B_PAGEIO))
3882 			bp_mapin(bp);
3883 		b_addr = bp->b_un.b_addr;
3884 	}
3885 
3886 	if (cdbp->cdb_opaque[1] & AAC_CDB_INQUIRY_EVPD) {
3887 		uchar_t *vpdp = (uchar_t *)b_addr;
3888 		uchar_t *idp, *sp;
3889 
3890 		/* SPC-3 8.4 Vital product data parameters */
3891 		switch (page) {
3892 		case 0x00:
3893 			/* Supported VPD pages */
3894 			if (vpdp == NULL ||
3895 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 3))
3896 				return;
3897 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
3898 			vpdp[AAC_VPD_PAGE_CODE] = 0x00;
3899 			vpdp[AAC_VPD_PAGE_LENGTH] = 3;
3900 
3901 			vpdp[AAC_VPD_PAGE_DATA] = 0x00;
3902 			vpdp[AAC_VPD_PAGE_DATA + 1] = 0x80;
3903 			vpdp[AAC_VPD_PAGE_DATA + 2] = 0x83;
3904 
3905 			pkt->pkt_state |= STATE_XFERRED_DATA;
3906 			break;
3907 
3908 		case 0x80:
3909 			/* Unit serial number page */
3910 			if (vpdp == NULL ||
3911 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 8))
3912 				return;
3913 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
3914 			vpdp[AAC_VPD_PAGE_CODE] = 0x80;
3915 			vpdp[AAC_VPD_PAGE_LENGTH] = 8;
3916 
3917 			sp = &vpdp[AAC_VPD_PAGE_DATA];
3918 			(void) aac_lun_serialno(softs, tgt, sp);
3919 
3920 			pkt->pkt_state |= STATE_XFERRED_DATA;
3921 			break;
3922 
3923 		case 0x83:
3924 			/* Device identification page */
3925 			if (vpdp == NULL ||
3926 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 32))
3927 				return;
3928 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
3929 			vpdp[AAC_VPD_PAGE_CODE] = 0x83;
3930 
3931 			idp = &vpdp[AAC_VPD_PAGE_DATA];
3932 			bzero(idp, AAC_VPD_ID_LENGTH);
3933 			idp[AAC_VPD_ID_CODESET] = 0x02;
3934 			idp[AAC_VPD_ID_TYPE] = 0x01;
3935 
3936 			/*
3937 			 * SPC-3 Table 111 - Identifier type
3938 			 * One recommanded method of constructing the remainder
3939 			 * of identifier field is to concatenate the product
3940 			 * identification field from the standard INQUIRY data
3941 			 * field and the product serial number field from the
3942 			 * unit serial number page.
3943 			 */
3944 			sp = &idp[AAC_VPD_ID_DATA];
3945 			sp = aac_vendor_id(softs, sp);
3946 			sp = aac_product_id(softs, sp);
3947 			sp = aac_lun_serialno(softs, tgt, sp);
3948 			idp[AAC_VPD_ID_LENGTH] = (uintptr_t)sp - \
3949 			    (uintptr_t)&idp[AAC_VPD_ID_DATA];
3950 
3951 			vpdp[AAC_VPD_PAGE_LENGTH] = (uintptr_t)sp - \
3952 			    (uintptr_t)&vpdp[AAC_VPD_PAGE_DATA];
3953 			pkt->pkt_state |= STATE_XFERRED_DATA;
3954 			break;
3955 
3956 		default:
3957 			aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST,
3958 			    0x24, 0x00, 0);
3959 			break;
3960 		}
3961 	} else {
3962 		struct scsi_inquiry *inqp = (struct scsi_inquiry *)b_addr;
3963 		size_t len = sizeof (struct scsi_inquiry);
3964 
3965 		if (page != 0) {
3966 			aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST,
3967 			    0x24, 0x00, 0);
3968 			return;
3969 		}
3970 		if (inqp == NULL || bp->b_bcount < len)
3971 			return;
3972 
3973 		bzero(inqp, len);
3974 		inqp->inq_len = AAC_ADDITIONAL_LEN;
3975 		inqp->inq_ansi = AAC_ANSI_VER;
3976 		inqp->inq_rdf = AAC_RESP_DATA_FORMAT;
3977 		(void) aac_vendor_id(softs, (uchar_t *)inqp->inq_vid);
3978 		(void) aac_product_id(softs, (uchar_t *)inqp->inq_pid);
3979 		bcopy("V1.0", inqp->inq_revision, 4);
3980 		inqp->inq_cmdque = 1; /* enable tagged-queuing */
3981 		/*
3982 		 * For "sd-max-xfer-size" property which may impact performance
3983 		 * when IO threads increase.
3984 		 */
3985 		inqp->inq_wbus32 = 1;
3986 
3987 		pkt->pkt_state |= STATE_XFERRED_DATA;
3988 	}
3989 }
3990 
3991 /*
3992  * SPC-3 7.10 MODE SENSE command implementation
3993  */
3994 static void
aac_mode_sense(struct aac_softstate * softs,struct scsi_pkt * pkt,union scsi_cdb * cdbp,struct buf * bp,int capacity)3995 aac_mode_sense(struct aac_softstate *softs, struct scsi_pkt *pkt,
3996     union scsi_cdb *cdbp, struct buf *bp, int capacity)
3997 {
3998 	uchar_t pagecode;
3999 	struct mode_header *headerp;
4000 	struct mode_header_g1 *g1_headerp;
4001 	unsigned int ncyl;
4002 	caddr_t sense_data;
4003 	caddr_t next_page;
4004 	size_t sdata_size;
4005 	size_t pages_size;
4006 	int unsupport_page = 0;
4007 
4008 	ASSERT(cdbp->scc_cmd == SCMD_MODE_SENSE ||
4009 	    cdbp->scc_cmd == SCMD_MODE_SENSE_G1);
4010 
4011 	if (!(bp && bp->b_un.b_addr && bp->b_bcount))
4012 		return;
4013 
4014 	if (bp->b_flags & (B_PHYS | B_PAGEIO))
4015 		bp_mapin(bp);
4016 	pkt->pkt_state |= STATE_XFERRED_DATA;
4017 	pagecode = cdbp->cdb_un.sg.scsi[0] & 0x3F;
4018 
4019 	/* calculate the size of needed buffer */
4020 	if (cdbp->scc_cmd == SCMD_MODE_SENSE)
4021 		sdata_size = MODE_HEADER_LENGTH;
4022 	else /* must be SCMD_MODE_SENSE_G1 */
4023 		sdata_size = MODE_HEADER_LENGTH_G1;
4024 
4025 	pages_size = 0;
4026 	switch (pagecode) {
4027 	case SD_MODE_SENSE_PAGE3_CODE:
4028 		pages_size += sizeof (struct mode_format);
4029 		break;
4030 
4031 	case SD_MODE_SENSE_PAGE4_CODE:
4032 		pages_size += sizeof (struct mode_geometry);
4033 		break;
4034 
4035 	case MODEPAGE_CTRL_MODE:
4036 		if (softs->flags & AAC_FLAGS_LBA_64BIT) {
4037 			pages_size += sizeof (struct mode_control_scsi3);
4038 		} else {
4039 			unsupport_page = 1;
4040 		}
4041 		break;
4042 
4043 	case MODEPAGE_ALLPAGES:
4044 		if (softs->flags & AAC_FLAGS_LBA_64BIT) {
4045 			pages_size += sizeof (struct mode_format) +
4046 			    sizeof (struct mode_geometry) +
4047 			    sizeof (struct mode_control_scsi3);
4048 		} else {
4049 			pages_size += sizeof (struct mode_format) +
4050 			    sizeof (struct mode_geometry);
4051 		}
4052 		break;
4053 
4054 	default:
4055 		/* unsupported pages */
4056 		unsupport_page = 1;
4057 	}
4058 
4059 	/* allocate buffer to fill the send data */
4060 	sdata_size += pages_size;
4061 	sense_data = kmem_zalloc(sdata_size, KM_SLEEP);
4062 
4063 	if (cdbp->scc_cmd == SCMD_MODE_SENSE) {
4064 		headerp = (struct mode_header *)sense_data;
4065 		headerp->length = MODE_HEADER_LENGTH + pages_size -
4066 		    sizeof (headerp->length);
4067 		headerp->bdesc_length = 0;
4068 		next_page = sense_data + sizeof (struct mode_header);
4069 	} else {
4070 		g1_headerp = (void *)sense_data;
4071 		g1_headerp->length = BE_16(MODE_HEADER_LENGTH_G1 + pages_size -
4072 		    sizeof (g1_headerp->length));
4073 		g1_headerp->bdesc_length = 0;
4074 		next_page = sense_data + sizeof (struct mode_header_g1);
4075 	}
4076 
4077 	if (unsupport_page)
4078 		goto finish;
4079 
4080 	if (pagecode == SD_MODE_SENSE_PAGE3_CODE ||
4081 	    pagecode == MODEPAGE_ALLPAGES) {
4082 		/* SBC-3 7.1.3.3 Format device page */
4083 		struct mode_format *page3p;
4084 
4085 		page3p = (void *)next_page;
4086 		page3p->mode_page.code = SD_MODE_SENSE_PAGE3_CODE;
4087 		page3p->mode_page.length = sizeof (struct mode_format);
4088 		page3p->data_bytes_sect = BE_16(AAC_SECTOR_SIZE);
4089 		page3p->sect_track = BE_16(AAC_SECTORS_PER_TRACK);
4090 
4091 		next_page += sizeof (struct mode_format);
4092 	}
4093 
4094 	if (pagecode == SD_MODE_SENSE_PAGE4_CODE ||
4095 	    pagecode == MODEPAGE_ALLPAGES) {
4096 		/* SBC-3 7.1.3.8 Rigid disk device geometry page */
4097 		struct mode_geometry *page4p;
4098 
4099 		page4p = (void *)next_page;
4100 		page4p->mode_page.code = SD_MODE_SENSE_PAGE4_CODE;
4101 		page4p->mode_page.length = sizeof (struct mode_geometry);
4102 		page4p->heads = AAC_NUMBER_OF_HEADS;
4103 		page4p->rpm = BE_16(AAC_ROTATION_SPEED);
4104 		ncyl = capacity / (AAC_NUMBER_OF_HEADS * AAC_SECTORS_PER_TRACK);
4105 		page4p->cyl_lb = ncyl & 0xff;
4106 		page4p->cyl_mb = (ncyl >> 8) & 0xff;
4107 		page4p->cyl_ub = (ncyl >> 16) & 0xff;
4108 
4109 		next_page += sizeof (struct mode_geometry);
4110 	}
4111 
4112 	if ((pagecode == MODEPAGE_CTRL_MODE || pagecode == MODEPAGE_ALLPAGES) &&
4113 	    softs->flags & AAC_FLAGS_LBA_64BIT) {
4114 		/* 64-bit LBA need large sense data */
4115 		struct mode_control_scsi3 *mctl;
4116 
4117 		mctl = (void *)next_page;
4118 		mctl->mode_page.code = MODEPAGE_CTRL_MODE;
4119 		mctl->mode_page.length =
4120 		    sizeof (struct mode_control_scsi3) -
4121 		    sizeof (struct mode_page);
4122 		mctl->d_sense = 1;
4123 	}
4124 
4125 finish:
4126 	/* copyout the valid data. */
4127 	bcopy(sense_data, bp->b_un.b_addr, min(sdata_size, bp->b_bcount));
4128 	kmem_free(sense_data, sdata_size);
4129 }
4130 
4131 static int
aac_name_node(dev_info_t * dip,char * name,int len)4132 aac_name_node(dev_info_t *dip, char *name, int len)
4133 {
4134 	int tgt, lun;
4135 
4136 	tgt = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
4137 	    DDI_PROP_DONTPASS, "target", -1);
4138 	if (tgt == -1)
4139 		return (DDI_FAILURE);
4140 	lun = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
4141 	    DDI_PROP_DONTPASS, "lun", -1);
4142 	if (lun == -1)
4143 		return (DDI_FAILURE);
4144 
4145 	(void) snprintf(name, len, "%x,%x", tgt, lun);
4146 	return (DDI_SUCCESS);
4147 }
4148 
4149 /*ARGSUSED*/
4150 static int
aac_tran_tgt_init(dev_info_t * hba_dip,dev_info_t * tgt_dip,scsi_hba_tran_t * tran,struct scsi_device * sd)4151 aac_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
4152     scsi_hba_tran_t *tran, struct scsi_device *sd)
4153 {
4154 	struct aac_softstate *softs = AAC_TRAN2SOFTS(tran);
4155 #if defined(DEBUG) || defined(__lock_lint)
4156 	int ctl = ddi_get_instance(softs->devinfo_p);
4157 #endif
4158 	uint16_t tgt = sd->sd_address.a_target;
4159 	uint8_t lun = sd->sd_address.a_lun;
4160 	struct aac_device *dvp;
4161 
4162 	DBCALLED(softs, 2);
4163 
4164 	if (ndi_dev_is_persistent_node(tgt_dip) == 0) {
4165 		/*
4166 		 * If no persistent node exist, we don't allow .conf node
4167 		 * to be created.
4168 		 */
4169 		if (aac_find_child(softs, tgt, lun) != NULL) {
4170 			if (ndi_merge_node(tgt_dip, aac_name_node) !=
4171 			    DDI_SUCCESS)
4172 				/* Create this .conf node */
4173 				return (DDI_SUCCESS);
4174 		}
4175 		return (DDI_FAILURE);
4176 	}
4177 
4178 	/*
4179 	 * Only support container/phys. device that has been
4180 	 * detected and valid
4181 	 */
4182 	mutex_enter(&softs->io_lock);
4183 	if (tgt >= AAC_MAX_DEV(softs)) {
4184 		AACDB_PRINT_TRAN(softs,
4185 		    "aac_tran_tgt_init: c%dt%dL%d out", ctl, tgt, lun);
4186 		mutex_exit(&softs->io_lock);
4187 		return (DDI_FAILURE);
4188 	}
4189 
4190 	if (tgt < AAC_MAX_LD) {
4191 		dvp = (struct aac_device *)&softs->containers[tgt];
4192 		if (lun != 0 || !AAC_DEV_IS_VALID(dvp)) {
4193 			AACDB_PRINT_TRAN(softs, "aac_tran_tgt_init: c%dt%dL%d",
4194 			    ctl, tgt, lun);
4195 			mutex_exit(&softs->io_lock);
4196 			return (DDI_FAILURE);
4197 		}
4198 		/*
4199 		 * Save the tgt_dip for the given target if one doesn't exist
4200 		 * already. Dip's for non-existance tgt's will be cleared in
4201 		 * tgt_free.
4202 		 */
4203 		if (softs->containers[tgt].dev.dip == NULL &&
4204 		    strcmp(ddi_driver_name(sd->sd_dev), "sd") == 0)
4205 			softs->containers[tgt].dev.dip = tgt_dip;
4206 	} else {
4207 		dvp = (struct aac_device *)&softs->nondasds[AAC_PD(tgt)];
4208 		/*
4209 		 * Save the tgt_dip for the given target if one doesn't exist
4210 		 * already. Dip's for non-existance tgt's will be cleared in
4211 		 * tgt_free.
4212 		 */
4213 
4214 		if (softs->nondasds[AAC_PD(tgt)].dev.dip  == NULL &&
4215 		    strcmp(ddi_driver_name(sd->sd_dev), "sd") == 0)
4216 			softs->nondasds[AAC_PD(tgt)].dev.dip  = tgt_dip;
4217 	}
4218 
4219 	if (softs->flags & AAC_FLAGS_BRKUP) {
4220 		if (ndi_prop_update_int(DDI_DEV_T_NONE, tgt_dip,
4221 		    "buf_break", 1) != DDI_PROP_SUCCESS) {
4222 			cmn_err(CE_CONT, "unable to create "
4223 			    "property for t%dL%d (buf_break)", tgt, lun);
4224 		}
4225 	}
4226 
4227 	AACDB_PRINT(softs, CE_NOTE,
4228 	    "aac_tran_tgt_init: c%dt%dL%d ok (%s)", ctl, tgt, lun,
4229 	    (dvp->type == AAC_DEV_PD) ? "pd" : "ld");
4230 	mutex_exit(&softs->io_lock);
4231 	return (DDI_SUCCESS);
4232 }
4233 
4234 static void
aac_tran_tgt_free(dev_info_t * hba_dip,dev_info_t * tgt_dip,scsi_hba_tran_t * hba_tran,struct scsi_device * sd)4235 aac_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
4236     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
4237 {
4238 #ifndef __lock_lint
4239 	_NOTE(ARGUNUSED(hba_dip, tgt_dip, hba_tran))
4240 #endif
4241 
4242 	struct aac_softstate *softs = SD2AAC(sd);
4243 	int tgt = sd->sd_address.a_target;
4244 
4245 	mutex_enter(&softs->io_lock);
4246 	if (tgt < AAC_MAX_LD) {
4247 		if (softs->containers[tgt].dev.dip == tgt_dip)
4248 			softs->containers[tgt].dev.dip = NULL;
4249 	} else {
4250 		if (softs->nondasds[AAC_PD(tgt)].dev.dip == tgt_dip)
4251 			softs->nondasds[AAC_PD(tgt)].dev.dip = NULL;
4252 		softs->nondasds[AAC_PD(tgt)].dev.flags &= ~AAC_DFLAG_VALID;
4253 	}
4254 	mutex_exit(&softs->io_lock);
4255 }
4256 
4257 /*
4258  * Check if the firmware is Up And Running. If it is in the Kernel Panic
4259  * state, (BlinkLED code + 1) is returned.
4260  *    0 -- firmware up and running
4261  *   -1 -- firmware dead
4262  *   >0 -- firmware kernel panic
4263  */
4264 static int
aac_check_adapter_health(struct aac_softstate * softs)4265 aac_check_adapter_health(struct aac_softstate *softs)
4266 {
4267 	int rval;
4268 
4269 	rval = PCI_MEM_GET32(softs, AAC_OMR0);
4270 
4271 	if (rval & AAC_KERNEL_UP_AND_RUNNING) {
4272 		rval = 0;
4273 	} else if (rval & AAC_KERNEL_PANIC) {
4274 		cmn_err(CE_WARN, "firmware panic");
4275 		rval = ((rval >> 16) & 0xff) + 1; /* avoid 0 as return value */
4276 	} else {
4277 		cmn_err(CE_WARN, "firmware dead");
4278 		rval = -1;
4279 	}
4280 	return (rval);
4281 }
4282 
4283 static void
aac_abort_iocmd(struct aac_softstate * softs,struct aac_cmd * acp,uchar_t reason)4284 aac_abort_iocmd(struct aac_softstate *softs, struct aac_cmd *acp,
4285     uchar_t reason)
4286 {
4287 	acp->flags |= AAC_CMD_ABORT;
4288 
4289 	if (acp->pkt) {
4290 		if (acp->slotp) { /* outstanding cmd */
4291 			acp->pkt->pkt_state |= STATE_GOT_STATUS;
4292 		}
4293 
4294 		switch (reason) {
4295 		case CMD_TIMEOUT:
4296 			AACDB_PRINT(softs, CE_NOTE, "CMD_TIMEOUT: acp=0x%p",
4297 			    acp);
4298 			aac_set_pkt_reason(softs, acp, CMD_TIMEOUT,
4299 			    STAT_TIMEOUT | STAT_BUS_RESET);
4300 			break;
4301 		case CMD_RESET:
4302 			/* aac support only RESET_ALL */
4303 			AACDB_PRINT(softs, CE_NOTE, "CMD_RESET: acp=0x%p", acp);
4304 			aac_set_pkt_reason(softs, acp, CMD_RESET,
4305 			    STAT_BUS_RESET);
4306 			break;
4307 		case CMD_ABORTED:
4308 			AACDB_PRINT(softs, CE_NOTE, "CMD_ABORTED: acp=0x%p",
4309 			    acp);
4310 			aac_set_pkt_reason(softs, acp, CMD_ABORTED,
4311 			    STAT_ABORTED);
4312 			break;
4313 		}
4314 	}
4315 	aac_end_io(softs, acp);
4316 }
4317 
4318 /*
4319  * Abort all the pending commands of type iocmd or just the command pkt
4320  * corresponding to pkt
4321  */
4322 static void
aac_abort_iocmds(struct aac_softstate * softs,int iocmd,struct scsi_pkt * pkt,int reason)4323 aac_abort_iocmds(struct aac_softstate *softs, int iocmd, struct scsi_pkt *pkt,
4324     int reason)
4325 {
4326 	struct aac_cmd *ac_arg, *acp;
4327 	int i;
4328 
4329 	if (pkt == NULL) {
4330 		ac_arg = NULL;
4331 	} else {
4332 		ac_arg = PKT2AC(pkt);
4333 		iocmd = (ac_arg->flags & AAC_CMD_SYNC) ?
4334 		    AAC_IOCMD_SYNC : AAC_IOCMD_ASYNC;
4335 	}
4336 
4337 	/*
4338 	 * a) outstanding commands on the controller
4339 	 * Note: should abort outstanding commands only after one
4340 	 * IOP reset has been done.
4341 	 */
4342 	if (iocmd & AAC_IOCMD_OUTSTANDING) {
4343 		struct aac_cmd *acp;
4344 
4345 		for (i = 0; i < AAC_MAX_LD; i++) {
4346 			if (AAC_DEV_IS_VALID(&softs->containers[i].dev))
4347 				softs->containers[i].reset = 1;
4348 		}
4349 		while ((acp = softs->q_busy.q_head) != NULL)
4350 			aac_abort_iocmd(softs, acp, reason);
4351 	}
4352 
4353 	/* b) commands in the waiting queues */
4354 	for (i = 0; i < AAC_CMDQ_NUM; i++) {
4355 		if (iocmd & (1 << i)) {
4356 			if (ac_arg) {
4357 				aac_abort_iocmd(softs, ac_arg, reason);
4358 			} else {
4359 				while ((acp = softs->q_wait[i].q_head) != NULL)
4360 					aac_abort_iocmd(softs, acp, reason);
4361 			}
4362 		}
4363 	}
4364 }
4365 
4366 /*
4367  * The draining thread is shared among quiesce threads. It terminates
4368  * when the adapter is quiesced or stopped by aac_stop_drain().
4369  */
4370 static void
aac_check_drain(void * arg)4371 aac_check_drain(void *arg)
4372 {
4373 	struct aac_softstate *softs = arg;
4374 
4375 	mutex_enter(&softs->io_lock);
4376 	if (softs->ndrains) {
4377 		softs->drain_timeid = 0;
4378 		/*
4379 		 * If both ASYNC and SYNC bus throttle are held,
4380 		 * wake up threads only when both are drained out.
4381 		 */
4382 		if ((softs->bus_throttle[AAC_CMDQ_ASYNC] > 0 ||
4383 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] == 0) &&
4384 		    (softs->bus_throttle[AAC_CMDQ_SYNC] > 0 ||
4385 		    softs->bus_ncmds[AAC_CMDQ_SYNC] == 0))
4386 			cv_broadcast(&softs->drain_cv);
4387 		else
4388 			softs->drain_timeid = timeout(aac_check_drain, softs,
4389 			    AAC_QUIESCE_TICK * drv_usectohz(1000000));
4390 	}
4391 	mutex_exit(&softs->io_lock);
4392 }
4393 
4394 /*
4395  * If not draining the outstanding cmds, drain them. Otherwise,
4396  * only update ndrains.
4397  */
4398 static void
aac_start_drain(struct aac_softstate * softs)4399 aac_start_drain(struct aac_softstate *softs)
4400 {
4401 	if (softs->ndrains == 0) {
4402 		ASSERT(softs->drain_timeid == 0);
4403 		softs->drain_timeid = timeout(aac_check_drain, softs,
4404 		    AAC_QUIESCE_TICK * drv_usectohz(1000000));
4405 	}
4406 	softs->ndrains++;
4407 }
4408 
4409 /*
4410  * Stop the draining thread when no other threads use it any longer.
4411  * Side effect: io_lock may be released in the middle.
4412  */
4413 static void
aac_stop_drain(struct aac_softstate * softs)4414 aac_stop_drain(struct aac_softstate *softs)
4415 {
4416 	softs->ndrains--;
4417 	if (softs->ndrains == 0) {
4418 		if (softs->drain_timeid != 0) {
4419 			timeout_id_t tid = softs->drain_timeid;
4420 
4421 			softs->drain_timeid = 0;
4422 			mutex_exit(&softs->io_lock);
4423 			(void) untimeout(tid);
4424 			mutex_enter(&softs->io_lock);
4425 		}
4426 	}
4427 }
4428 
4429 /*
4430  * The following function comes from Adaptec:
4431  *
4432  * Once do an IOP reset, basically the driver have to re-initialize the card
4433  * as if up from a cold boot, and the driver is responsible for any IO that
4434  * is outstanding to the adapter at the time of the IOP RESET. And prepare
4435  * for IOP RESET by making the init code modular with the ability to call it
4436  * from multiple places.
4437  */
4438 static int
aac_reset_adapter(struct aac_softstate * softs)4439 aac_reset_adapter(struct aac_softstate *softs)
4440 {
4441 	int health;
4442 	uint32_t status;
4443 	int rval = AAC_IOP_RESET_FAILED;
4444 
4445 	DBCALLED(softs, 1);
4446 
4447 	ASSERT(softs->state & AAC_STATE_RESET);
4448 
4449 	ddi_fm_acc_err_clear(softs->pci_mem_handle, DDI_FME_VER0);
4450 	/* Disable interrupt */
4451 	AAC_DISABLE_INTR(softs);
4452 
4453 	health = aac_check_adapter_health(softs);
4454 	if (health == -1) {
4455 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
4456 		goto finish;
4457 	}
4458 	if (health == 0) /* flush drives if possible */
4459 		(void) aac_shutdown(softs);
4460 
4461 	/* Execute IOP reset */
4462 	if ((aac_sync_mbcommand(softs, AAC_IOP_RESET, 0, 0, 0, 0,
4463 	    &status)) != AACOK) {
4464 		ddi_acc_handle_t acc;
4465 		struct aac_fib *fibp;
4466 		struct aac_pause_command *pc;
4467 
4468 		if ((status & 0xf) == 0xf) {
4469 			uint32_t wait_count;
4470 
4471 			/*
4472 			 * Sunrise Lake has dual cores and we must drag the
4473 			 * other core with us to reset simultaneously. There
4474 			 * are 2 bits in the Inbound Reset Control and Status
4475 			 * Register (offset 0x38) of the Sunrise Lake to reset
4476 			 * the chip without clearing out the PCI configuration
4477 			 * info (COMMAND & BARS).
4478 			 */
4479 			PCI_MEM_PUT32(softs, AAC_IRCSR, AAC_IRCSR_CORES_RST);
4480 
4481 			/*
4482 			 * We need to wait for 5 seconds before accessing the MU
4483 			 * again 10000 * 100us = 1000,000us = 1000ms = 1s
4484 			 */
4485 			wait_count = 5 * 10000;
4486 			while (wait_count) {
4487 				drv_usecwait(100); /* delay 100 microseconds */
4488 				wait_count--;
4489 			}
4490 		} else {
4491 			if (status == SRB_STATUS_INVALID_REQUEST)
4492 				cmn_err(CE_WARN, "!IOP_RESET not supported");
4493 			else /* probably timeout */
4494 				cmn_err(CE_WARN, "!IOP_RESET failed");
4495 
4496 			/* Unwind aac_shutdown() */
4497 			(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
4498 			acc = softs->sync_ac.slotp->fib_acc_handle;
4499 
4500 			fibp = softs->sync_ac.slotp->fibp;
4501 			pc = (struct aac_pause_command *)&fibp->data[0];
4502 
4503 			bzero(pc, sizeof (*pc));
4504 			ddi_put32(acc, &pc->Command, VM_ContainerConfig);
4505 			ddi_put32(acc, &pc->Type, CT_PAUSE_IO);
4506 			ddi_put32(acc, &pc->Timeout, 1);
4507 			ddi_put32(acc, &pc->Min, 1);
4508 			ddi_put32(acc, &pc->NoRescan, 1);
4509 
4510 			(void) aac_sync_fib(softs, ContainerCommand,
4511 			    AAC_FIB_SIZEOF(struct aac_pause_command));
4512 			aac_sync_fib_slot_release(softs, &softs->sync_ac);
4513 
4514 			if (aac_check_adapter_health(softs) != 0)
4515 				ddi_fm_service_impact(softs->devinfo_p,
4516 				    DDI_SERVICE_LOST);
4517 			else
4518 				/*
4519 				 * IOP reset not supported or IOP not reseted
4520 				 */
4521 				rval = AAC_IOP_RESET_ABNORMAL;
4522 			goto finish;
4523 		}
4524 	}
4525 
4526 	/*
4527 	 * Re-read and renegotiate the FIB parameters, as one of the actions
4528 	 * that can result from an IOP reset is the running of a new firmware
4529 	 * image.
4530 	 */
4531 	if (aac_common_attach(softs) != AACOK)
4532 		goto finish;
4533 
4534 	rval = AAC_IOP_RESET_SUCCEED;
4535 
4536 finish:
4537 	AAC_ENABLE_INTR(softs);
4538 	return (rval);
4539 }
4540 
4541 static void
aac_set_throttle(struct aac_softstate * softs,struct aac_device * dvp,int q,int throttle)4542 aac_set_throttle(struct aac_softstate *softs, struct aac_device *dvp, int q,
4543     int throttle)
4544 {
4545 	/*
4546 	 * If the bus is draining/quiesced, no changes to the throttles
4547 	 * are allowed. All throttles should have been set to 0.
4548 	 */
4549 	if ((softs->state & AAC_STATE_QUIESCED) || softs->ndrains)
4550 		return;
4551 	dvp->throttle[q] = throttle;
4552 }
4553 
4554 static void
aac_hold_bus(struct aac_softstate * softs,int iocmds)4555 aac_hold_bus(struct aac_softstate *softs, int iocmds)
4556 {
4557 	int i, q;
4558 
4559 	/* Hold bus by holding every device on the bus */
4560 	for (q = 0; q < AAC_CMDQ_NUM; q++) {
4561 		if (iocmds & (1 << q)) {
4562 			softs->bus_throttle[q] = 0;
4563 			for (i = 0; i < AAC_MAX_LD; i++)
4564 				aac_set_throttle(softs,
4565 				    &softs->containers[i].dev, q, 0);
4566 			for (i = 0; i < AAC_MAX_PD(softs); i++)
4567 				aac_set_throttle(softs,
4568 				    &softs->nondasds[i].dev, q, 0);
4569 		}
4570 	}
4571 }
4572 
4573 static void
aac_unhold_bus(struct aac_softstate * softs,int iocmds)4574 aac_unhold_bus(struct aac_softstate *softs, int iocmds)
4575 {
4576 	int i, q, max_throttle;
4577 
4578 	for (q = 0; q < AAC_CMDQ_NUM; q++) {
4579 		if (iocmds & (1 << q)) {
4580 			/*
4581 			 * Should not unhold AAC_IOCMD_ASYNC bus, if it has been
4582 			 * quiesced or being drained by possibly some quiesce
4583 			 * threads.
4584 			 */
4585 			if (q == AAC_CMDQ_ASYNC && ((softs->state &
4586 			    AAC_STATE_QUIESCED) || softs->ndrains))
4587 				continue;
4588 			if (q == AAC_CMDQ_ASYNC)
4589 				max_throttle = softs->total_slots -
4590 				    AAC_MGT_SLOT_NUM;
4591 			else
4592 				max_throttle = softs->total_slots - 1;
4593 			softs->bus_throttle[q] = max_throttle;
4594 			for (i = 0; i < AAC_MAX_LD; i++)
4595 				aac_set_throttle(softs,
4596 				    &softs->containers[i].dev,
4597 				    q, max_throttle);
4598 			for (i = 0; i < AAC_MAX_PD(softs); i++)
4599 				aac_set_throttle(softs, &softs->nondasds[i].dev,
4600 				    q, max_throttle);
4601 		}
4602 	}
4603 }
4604 
4605 static int
aac_do_reset(struct aac_softstate * softs)4606 aac_do_reset(struct aac_softstate *softs)
4607 {
4608 	int health;
4609 	int rval;
4610 
4611 	softs->state |= AAC_STATE_RESET;
4612 	health = aac_check_adapter_health(softs);
4613 
4614 	/*
4615 	 * Hold off new io commands and wait all outstanding io
4616 	 * commands to complete.
4617 	 */
4618 	if (health == 0) {
4619 		int sync_cmds = softs->bus_ncmds[AAC_CMDQ_SYNC];
4620 		int async_cmds = softs->bus_ncmds[AAC_CMDQ_ASYNC];
4621 
4622 		if (sync_cmds == 0 && async_cmds == 0) {
4623 			rval = AAC_IOP_RESET_SUCCEED;
4624 			goto finish;
4625 		}
4626 		/*
4627 		 * Give the adapter up to AAC_QUIESCE_TIMEOUT more seconds
4628 		 * to complete the outstanding io commands
4629 		 */
4630 		int timeout = AAC_QUIESCE_TIMEOUT * 1000 * 10;
4631 		int (*intr_handler)(struct aac_softstate *);
4632 
4633 		aac_hold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
4634 		/*
4635 		 * Poll the adapter by ourselves in case interrupt is disabled
4636 		 * and to avoid releasing the io_lock.
4637 		 */
4638 		intr_handler = (softs->flags & AAC_FLAGS_NEW_COMM) ?
4639 		    aac_process_intr_new : aac_process_intr_old;
4640 		while ((softs->bus_ncmds[AAC_CMDQ_SYNC] ||
4641 		    softs->bus_ncmds[AAC_CMDQ_ASYNC]) && timeout) {
4642 			drv_usecwait(100);
4643 			(void) intr_handler(softs);
4644 			timeout--;
4645 		}
4646 		aac_unhold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
4647 
4648 		if (softs->bus_ncmds[AAC_CMDQ_SYNC] == 0 &&
4649 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] == 0) {
4650 			/* Cmds drained out */
4651 			rval = AAC_IOP_RESET_SUCCEED;
4652 			goto finish;
4653 		} else if (softs->bus_ncmds[AAC_CMDQ_SYNC] < sync_cmds ||
4654 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] < async_cmds) {
4655 			/* Cmds not drained out, adapter overloaded */
4656 			rval = AAC_IOP_RESET_ABNORMAL;
4657 			goto finish;
4658 		}
4659 	}
4660 
4661 	/*
4662 	 * If a longer waiting time still can't drain any outstanding io
4663 	 * commands, do IOP reset.
4664 	 */
4665 	if ((rval = aac_reset_adapter(softs)) == AAC_IOP_RESET_FAILED)
4666 		softs->state |= AAC_STATE_DEAD;
4667 
4668 finish:
4669 	softs->state &= ~AAC_STATE_RESET;
4670 	return (rval);
4671 }
4672 
4673 static int
aac_tran_reset(struct scsi_address * ap,int level)4674 aac_tran_reset(struct scsi_address *ap, int level)
4675 {
4676 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
4677 	int rval;
4678 
4679 	DBCALLED(softs, 1);
4680 
4681 	if (level != RESET_ALL) {
4682 		cmn_err(CE_NOTE, "!reset target/lun not supported");
4683 		return (0);
4684 	}
4685 
4686 	mutex_enter(&softs->io_lock);
4687 	switch (rval = aac_do_reset(softs)) {
4688 	case AAC_IOP_RESET_SUCCEED:
4689 		aac_abort_iocmds(softs, AAC_IOCMD_OUTSTANDING | AAC_IOCMD_ASYNC,
4690 		    NULL, CMD_RESET);
4691 		aac_start_waiting_io(softs);
4692 		break;
4693 	case AAC_IOP_RESET_FAILED:
4694 		/* Abort IOCTL cmds when adapter is dead */
4695 		aac_abort_iocmds(softs, AAC_IOCMD_ALL, NULL, CMD_RESET);
4696 		break;
4697 	case AAC_IOP_RESET_ABNORMAL:
4698 		aac_start_waiting_io(softs);
4699 	}
4700 	mutex_exit(&softs->io_lock);
4701 
4702 	aac_drain_comp_q(softs);
4703 	return (rval == 0);
4704 }
4705 
4706 static int
aac_tran_abort(struct scsi_address * ap,struct scsi_pkt * pkt)4707 aac_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
4708 {
4709 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
4710 
4711 	DBCALLED(softs, 1);
4712 
4713 	mutex_enter(&softs->io_lock);
4714 	aac_abort_iocmds(softs, 0, pkt, CMD_ABORTED);
4715 	mutex_exit(&softs->io_lock);
4716 
4717 	aac_drain_comp_q(softs);
4718 	return (1);
4719 }
4720 
4721 void
aac_free_dmamap(struct aac_cmd * acp)4722 aac_free_dmamap(struct aac_cmd *acp)
4723 {
4724 	/* Free dma mapping */
4725 	if (acp->flags & AAC_CMD_DMA_VALID) {
4726 		ASSERT(acp->buf_dma_handle);
4727 		(void) ddi_dma_unbind_handle(acp->buf_dma_handle);
4728 		acp->flags &= ~AAC_CMD_DMA_VALID;
4729 	}
4730 
4731 	if (acp->abp != NULL) { /* free non-aligned buf DMA */
4732 		ASSERT(acp->buf_dma_handle);
4733 		if ((acp->flags & AAC_CMD_BUF_WRITE) == 0 && acp->bp)
4734 			ddi_rep_get8(acp->abh, (uint8_t *)acp->bp->b_un.b_addr,
4735 			    (uint8_t *)acp->abp, acp->bp->b_bcount,
4736 			    DDI_DEV_AUTOINCR);
4737 		ddi_dma_mem_free(&acp->abh);
4738 		acp->abp = NULL;
4739 	}
4740 
4741 	if (acp->buf_dma_handle) {
4742 		ddi_dma_free_handle(&acp->buf_dma_handle);
4743 		acp->buf_dma_handle = NULL;
4744 	}
4745 }
4746 
4747 static void
aac_unknown_scmd(struct aac_softstate * softs,struct aac_cmd * acp)4748 aac_unknown_scmd(struct aac_softstate *softs, struct aac_cmd *acp)
4749 {
4750 	AACDB_PRINT(softs, CE_CONT, "SCMD 0x%x not supported",
4751 	    ((union scsi_cdb *)(void *)acp->pkt->pkt_cdbp)->scc_cmd);
4752 	aac_free_dmamap(acp);
4753 	aac_set_arq_data(acp->pkt, KEY_ILLEGAL_REQUEST, 0x20, 0x00, 0);
4754 	aac_soft_callback(softs, acp);
4755 }
4756 
4757 /*
4758  * Handle command to logical device
4759  */
4760 static int
aac_tran_start_ld(struct aac_softstate * softs,struct aac_cmd * acp)4761 aac_tran_start_ld(struct aac_softstate *softs, struct aac_cmd *acp)
4762 {
4763 	struct aac_container *dvp;
4764 	struct scsi_pkt *pkt;
4765 	union scsi_cdb *cdbp;
4766 	struct buf *bp;
4767 	int rval;
4768 
4769 	dvp = (struct aac_container *)acp->dvp;
4770 	pkt = acp->pkt;
4771 	cdbp = (void *)pkt->pkt_cdbp;
4772 	bp = acp->bp;
4773 
4774 	switch (cdbp->scc_cmd) {
4775 	case SCMD_INQUIRY: /* inquiry */
4776 		aac_free_dmamap(acp);
4777 		aac_inquiry(softs, pkt, cdbp, bp);
4778 		aac_soft_callback(softs, acp);
4779 		rval = TRAN_ACCEPT;
4780 		break;
4781 
4782 	case SCMD_READ_CAPACITY: /* read capacity */
4783 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
4784 			struct scsi_capacity cap;
4785 			uint64_t last_lba;
4786 
4787 			/* check 64-bit LBA */
4788 			last_lba = dvp->size - 1;
4789 			if (last_lba > 0xffffffffull) {
4790 				cap.capacity = 0xfffffffful;
4791 			} else {
4792 				cap.capacity = BE_32(last_lba);
4793 			}
4794 			cap.lbasize = BE_32(AAC_SECTOR_SIZE);
4795 
4796 			aac_free_dmamap(acp);
4797 			if (bp->b_flags & (B_PHYS|B_PAGEIO))
4798 				bp_mapin(bp);
4799 			bcopy(&cap, bp->b_un.b_addr, min(bp->b_bcount, 8));
4800 			pkt->pkt_state |= STATE_XFERRED_DATA;
4801 		}
4802 		aac_soft_callback(softs, acp);
4803 		rval = TRAN_ACCEPT;
4804 		break;
4805 
4806 	case SCMD_SVC_ACTION_IN_G4: /* read capacity 16 */
4807 		/* Check if containers need 64-bit LBA support */
4808 		if (cdbp->cdb_opaque[1] == SSVC_ACTION_READ_CAPACITY_G4) {
4809 			if (bp && bp->b_un.b_addr && bp->b_bcount) {
4810 				struct scsi_capacity_16 cap16;
4811 				int cap_len = sizeof (struct scsi_capacity_16);
4812 
4813 				bzero(&cap16, cap_len);
4814 				cap16.sc_capacity = BE_64(dvp->size - 1);
4815 				cap16.sc_lbasize = BE_32(AAC_SECTOR_SIZE);
4816 
4817 				aac_free_dmamap(acp);
4818 				if (bp->b_flags & (B_PHYS | B_PAGEIO))
4819 					bp_mapin(bp);
4820 				bcopy(&cap16, bp->b_un.b_addr,
4821 				    min(bp->b_bcount, cap_len));
4822 				pkt->pkt_state |= STATE_XFERRED_DATA;
4823 			}
4824 			aac_soft_callback(softs, acp);
4825 		} else {
4826 			aac_unknown_scmd(softs, acp);
4827 		}
4828 		rval = TRAN_ACCEPT;
4829 		break;
4830 
4831 	case SCMD_READ_G4: /* read_16 */
4832 	case SCMD_WRITE_G4: /* write_16 */
4833 		if (softs->flags & AAC_FLAGS_RAW_IO) {
4834 			/* NOTE: GETG4ADDRTL(cdbp) is int32_t */
4835 			acp->blkno = ((uint64_t) \
4836 			    GETG4ADDR(cdbp) << 32) | \
4837 			    (uint32_t)GETG4ADDRTL(cdbp);
4838 			goto do_io;
4839 		}
4840 		AACDB_PRINT(softs, CE_WARN, "64-bit LBA not supported");
4841 		aac_unknown_scmd(softs, acp);
4842 		rval = TRAN_ACCEPT;
4843 		break;
4844 
4845 	case SCMD_READ: /* read_6 */
4846 	case SCMD_WRITE: /* write_6 */
4847 		acp->blkno = GETG0ADDR(cdbp);
4848 		goto do_io;
4849 
4850 	case SCMD_READ_G5: /* read_12 */
4851 	case SCMD_WRITE_G5: /* write_12 */
4852 		acp->blkno = GETG5ADDR(cdbp);
4853 		goto do_io;
4854 
4855 	case SCMD_READ_G1: /* read_10 */
4856 	case SCMD_WRITE_G1: /* write_10 */
4857 		acp->blkno = (uint32_t)GETG1ADDR(cdbp);
4858 do_io:
4859 		if (acp->flags & AAC_CMD_DMA_VALID) {
4860 			uint64_t cnt_size = dvp->size;
4861 
4862 			/*
4863 			 * If LBA > array size AND rawio, the
4864 			 * adapter may hang. So check it before
4865 			 * sending.
4866 			 * NOTE: (blkno + blkcnt) may overflow
4867 			 */
4868 			if ((acp->blkno < cnt_size) &&
4869 			    ((acp->blkno + acp->bcount /
4870 			    AAC_BLK_SIZE) <= cnt_size)) {
4871 				rval = aac_do_io(softs, acp);
4872 			} else {
4873 			/*
4874 			 * Request exceeds the capacity of disk,
4875 			 * set error block number to last LBA
4876 			 * + 1.
4877 			 */
4878 				aac_set_arq_data(pkt,
4879 				    KEY_ILLEGAL_REQUEST, 0x21,
4880 				    0x00, cnt_size);
4881 				aac_soft_callback(softs, acp);
4882 				rval = TRAN_ACCEPT;
4883 			}
4884 		} else if (acp->bcount == 0) {
4885 			/* For 0 length IO, just return ok */
4886 			aac_soft_callback(softs, acp);
4887 			rval = TRAN_ACCEPT;
4888 		} else {
4889 			rval = TRAN_BADPKT;
4890 		}
4891 		break;
4892 
4893 	case SCMD_MODE_SENSE: /* mode_sense_6 */
4894 	case SCMD_MODE_SENSE_G1: { /* mode_sense_10 */
4895 		int capacity;
4896 
4897 		aac_free_dmamap(acp);
4898 		if (dvp->size > 0xffffffffull)
4899 			capacity = 0xfffffffful; /* 64-bit LBA */
4900 		else
4901 			capacity = dvp->size;
4902 		aac_mode_sense(softs, pkt, cdbp, bp, capacity);
4903 		aac_soft_callback(softs, acp);
4904 		rval = TRAN_ACCEPT;
4905 		break;
4906 	}
4907 
4908 	case SCMD_START_STOP:
4909 		if (softs->support_opt2 & AAC_SUPPORTED_POWER_MANAGEMENT) {
4910 			acp->aac_cmd_fib = aac_cmd_fib_startstop;
4911 			acp->ac_comp = aac_startstop_complete;
4912 			rval = aac_do_io(softs, acp);
4913 			break;
4914 		}
4915 	/* FALLTHRU */
4916 	case SCMD_TEST_UNIT_READY:
4917 	case SCMD_REQUEST_SENSE:
4918 	case SCMD_FORMAT:
4919 		aac_free_dmamap(acp);
4920 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
4921 			if (acp->flags & AAC_CMD_BUF_READ) {
4922 				if (bp->b_flags & (B_PHYS|B_PAGEIO))
4923 					bp_mapin(bp);
4924 				bzero(bp->b_un.b_addr, bp->b_bcount);
4925 			}
4926 			pkt->pkt_state |= STATE_XFERRED_DATA;
4927 		}
4928 		aac_soft_callback(softs, acp);
4929 		rval = TRAN_ACCEPT;
4930 		break;
4931 
4932 	case SCMD_SYNCHRONIZE_CACHE:
4933 		acp->flags |= AAC_CMD_NTAG;
4934 		acp->aac_cmd_fib = aac_cmd_fib_sync;
4935 		acp->ac_comp = aac_synccache_complete;
4936 		rval = aac_do_io(softs, acp);
4937 		break;
4938 
4939 	case SCMD_DOORLOCK:
4940 		aac_free_dmamap(acp);
4941 		dvp->locked = (pkt->pkt_cdbp[4] & 0x01) ? 1 : 0;
4942 		aac_soft_callback(softs, acp);
4943 		rval = TRAN_ACCEPT;
4944 		break;
4945 
4946 	default: /* unknown command */
4947 		aac_unknown_scmd(softs, acp);
4948 		rval = TRAN_ACCEPT;
4949 		break;
4950 	}
4951 
4952 	return (rval);
4953 }
4954 
4955 static int
aac_tran_start(struct scsi_address * ap,struct scsi_pkt * pkt)4956 aac_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
4957 {
4958 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
4959 	struct aac_cmd *acp = PKT2AC(pkt);
4960 	struct aac_device *dvp = acp->dvp;
4961 	int rval;
4962 
4963 	DBCALLED(softs, 2);
4964 
4965 	/*
4966 	 * Reinitialize some fields of ac and pkt; the packet may
4967 	 * have been resubmitted
4968 	 */
4969 	acp->flags &= AAC_CMD_CONSISTENT | AAC_CMD_DMA_PARTIAL | \
4970 	    AAC_CMD_BUF_READ | AAC_CMD_BUF_WRITE | AAC_CMD_DMA_VALID;
4971 	acp->timeout = acp->pkt->pkt_time;
4972 	if (pkt->pkt_flags & FLAG_NOINTR)
4973 		acp->flags |= AAC_CMD_NO_INTR;
4974 #ifdef DEBUG
4975 	acp->fib_flags = AACDB_FLAGS_FIB_SCMD;
4976 #endif
4977 	pkt->pkt_reason = CMD_CMPLT;
4978 	pkt->pkt_state = 0;
4979 	pkt->pkt_statistics = 0;
4980 	*pkt->pkt_scbp = STATUS_GOOD; /* clear arq scsi_status */
4981 
4982 	if (acp->flags & AAC_CMD_DMA_VALID) {
4983 		pkt->pkt_resid = acp->bcount;
4984 		/* Consistent packets need to be sync'ed first */
4985 		if ((acp->flags & AAC_CMD_CONSISTENT) &&
4986 		    (acp->flags & AAC_CMD_BUF_WRITE))
4987 			if (aac_dma_sync_ac(acp) != AACOK) {
4988 				ddi_fm_service_impact(softs->devinfo_p,
4989 				    DDI_SERVICE_UNAFFECTED);
4990 				return (TRAN_BADPKT);
4991 			}
4992 	} else {
4993 		pkt->pkt_resid = 0;
4994 	}
4995 
4996 	mutex_enter(&softs->io_lock);
4997 	AACDB_PRINT_SCMD(softs, acp);
4998 	if ((dvp->flags & (AAC_DFLAG_VALID | AAC_DFLAG_CONFIGURING)) &&
4999 	    !(softs->state & AAC_STATE_DEAD)) {
5000 		if (dvp->type == AAC_DEV_LD) {
5001 			if (ap->a_lun == 0)
5002 				rval = aac_tran_start_ld(softs, acp);
5003 			else
5004 				goto error;
5005 		} else {
5006 			rval = aac_do_io(softs, acp);
5007 		}
5008 	} else {
5009 error:
5010 #ifdef DEBUG
5011 		if (!(softs->state & AAC_STATE_DEAD)) {
5012 			AACDB_PRINT_TRAN(softs,
5013 			    "Cannot send cmd to target t%dL%d: %s",
5014 			    ap->a_target, ap->a_lun,
5015 			    "target invalid");
5016 		} else {
5017 			AACDB_PRINT(softs, CE_WARN,
5018 			    "Cannot send cmd to target t%dL%d: %s",
5019 			    ap->a_target, ap->a_lun,
5020 			    "adapter dead");
5021 		}
5022 #endif
5023 		rval = TRAN_FATAL_ERROR;
5024 	}
5025 	mutex_exit(&softs->io_lock);
5026 	return (rval);
5027 }
5028 
5029 static int
aac_tran_getcap(struct scsi_address * ap,char * cap,int whom)5030 aac_tran_getcap(struct scsi_address *ap, char *cap, int whom)
5031 {
5032 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
5033 	struct aac_device *dvp;
5034 	int rval;
5035 
5036 	DBCALLED(softs, 2);
5037 
5038 	/* We don't allow inquiring about capabilities for other targets */
5039 	if (cap == NULL || whom == 0) {
5040 		AACDB_PRINT(softs, CE_WARN,
5041 		    "GetCap> %s not supported: whom=%d", cap, whom);
5042 		return (-1);
5043 	}
5044 
5045 	mutex_enter(&softs->io_lock);
5046 	dvp = AAC_DEV(softs, ap->a_target);
5047 	if (dvp == NULL || !AAC_DEV_IS_VALID(dvp)) {
5048 		mutex_exit(&softs->io_lock);
5049 		AACDB_PRINT_TRAN(softs, "Bad target t%dL%d to getcap",
5050 		    ap->a_target, ap->a_lun);
5051 		return (-1);
5052 	}
5053 
5054 	switch (scsi_hba_lookup_capstr(cap)) {
5055 	case SCSI_CAP_ARQ: /* auto request sense */
5056 		rval = 1;
5057 		break;
5058 	case SCSI_CAP_UNTAGGED_QING:
5059 	case SCSI_CAP_TAGGED_QING:
5060 		rval = 1;
5061 		break;
5062 	case SCSI_CAP_DMA_MAX:
5063 		rval = softs->dma_max;
5064 		break;
5065 	default:
5066 		rval = -1;
5067 		break;
5068 	}
5069 	mutex_exit(&softs->io_lock);
5070 
5071 	AACDB_PRINT_TRAN(softs, "GetCap> %s t%dL%d: rval=%d",
5072 	    cap, ap->a_target, ap->a_lun, rval);
5073 	return (rval);
5074 }
5075 
5076 /*ARGSUSED*/
5077 static int
aac_tran_setcap(struct scsi_address * ap,char * cap,int value,int whom)5078 aac_tran_setcap(struct scsi_address *ap, char *cap, int value, int whom)
5079 {
5080 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
5081 	struct aac_device *dvp;
5082 	int rval;
5083 
5084 	DBCALLED(softs, 2);
5085 
5086 	/* We don't allow inquiring about capabilities for other targets */
5087 	if (cap == NULL || whom == 0) {
5088 		AACDB_PRINT(softs, CE_WARN,
5089 		    "SetCap> %s not supported: whom=%d", cap, whom);
5090 		return (-1);
5091 	}
5092 
5093 	mutex_enter(&softs->io_lock);
5094 	dvp = AAC_DEV(softs, ap->a_target);
5095 	if (dvp == NULL || !AAC_DEV_IS_VALID(dvp)) {
5096 		mutex_exit(&softs->io_lock);
5097 		AACDB_PRINT_TRAN(softs, "Bad target t%dL%d to setcap",
5098 		    ap->a_target, ap->a_lun);
5099 		return (-1);
5100 	}
5101 
5102 	switch (scsi_hba_lookup_capstr(cap)) {
5103 	case SCSI_CAP_ARQ:
5104 		/* Force auto request sense */
5105 		rval = (value == 1) ? 1 : 0;
5106 		break;
5107 	case SCSI_CAP_UNTAGGED_QING:
5108 	case SCSI_CAP_TAGGED_QING:
5109 		rval = (value == 1) ? 1 : 0;
5110 		break;
5111 	default:
5112 		rval = -1;
5113 		break;
5114 	}
5115 	mutex_exit(&softs->io_lock);
5116 
5117 	AACDB_PRINT_TRAN(softs, "SetCap> %s t%dL%d val=%d: rval=%d",
5118 	    cap, ap->a_target, ap->a_lun, value, rval);
5119 	return (rval);
5120 }
5121 
5122 static void
aac_tran_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)5123 aac_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
5124 {
5125 	struct aac_cmd *acp = PKT2AC(pkt);
5126 
5127 	DBCALLED(NULL, 2);
5128 
5129 	if (acp->sgt) {
5130 		kmem_free(acp->sgt, sizeof (struct aac_sge) * \
5131 		    acp->left_cookien);
5132 	}
5133 	aac_free_dmamap(acp);
5134 	ASSERT(acp->slotp == NULL);
5135 	scsi_hba_pkt_free(ap, pkt);
5136 }
5137 
5138 int
aac_cmd_dma_alloc(struct aac_softstate * softs,struct aac_cmd * acp,struct buf * bp,int flags,int (* cb)(),caddr_t arg)5139 aac_cmd_dma_alloc(struct aac_softstate *softs, struct aac_cmd *acp,
5140     struct buf *bp, int flags, int (*cb)(), caddr_t arg)
5141 {
5142 	int kf = (cb == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP;
5143 	uint_t oldcookiec;
5144 	int bioerr = 0;
5145 	int rval;
5146 
5147 	oldcookiec = acp->left_cookien;
5148 
5149 	/* Move window to build s/g map */
5150 	if (acp->total_nwin > 0) {
5151 		if (++acp->cur_win < acp->total_nwin) {
5152 			off_t off;
5153 			size_t len;
5154 
5155 			rval = ddi_dma_getwin(acp->buf_dma_handle, acp->cur_win,
5156 			    &off, &len, &acp->cookie, &acp->left_cookien);
5157 			if (rval == DDI_SUCCESS)
5158 				goto get_dma_cookies;
5159 			AACDB_PRINT(softs, CE_WARN,
5160 			    "ddi_dma_getwin() fail %d", rval);
5161 			return (AACERR);
5162 		}
5163 		AACDB_PRINT(softs, CE_WARN, "Nothing to transfer");
5164 		return (AACERR);
5165 	}
5166 
5167 	/* We need to transfer data, so we alloc DMA resources for this pkt */
5168 	if (bp && bp->b_bcount != 0 && !(acp->flags & AAC_CMD_DMA_VALID)) {
5169 		uint_t dma_flags = 0;
5170 		struct aac_sge *sge;
5171 
5172 		/*
5173 		 * We will still use this point to fake some
5174 		 * infomation in tran_start
5175 		 */
5176 		acp->bp = bp;
5177 
5178 		/* Set dma flags */
5179 		if (BUF_IS_READ(bp)) {
5180 			dma_flags |= DDI_DMA_READ;
5181 			acp->flags |= AAC_CMD_BUF_READ;
5182 		} else {
5183 			dma_flags |= DDI_DMA_WRITE;
5184 			acp->flags |= AAC_CMD_BUF_WRITE;
5185 		}
5186 		if (flags & PKT_CONSISTENT)
5187 			dma_flags |= DDI_DMA_CONSISTENT;
5188 		if (flags & PKT_DMA_PARTIAL)
5189 			dma_flags |= DDI_DMA_PARTIAL;
5190 
5191 		/* Alloc buf dma handle */
5192 		if (!acp->buf_dma_handle) {
5193 			rval = ddi_dma_alloc_handle(softs->devinfo_p,
5194 			    &softs->buf_dma_attr, cb, arg,
5195 			    &acp->buf_dma_handle);
5196 			if (rval != DDI_SUCCESS) {
5197 				AACDB_PRINT(softs, CE_WARN,
5198 				    "Can't allocate DMA handle, errno=%d",
5199 				    rval);
5200 				goto error_out;
5201 			}
5202 		}
5203 
5204 		/* Bind buf */
5205 		if (((uintptr_t)bp->b_un.b_addr & AAC_DMA_ALIGN_MASK) == 0) {
5206 			rval = ddi_dma_buf_bind_handle(acp->buf_dma_handle,
5207 			    bp, dma_flags, cb, arg, &acp->cookie,
5208 			    &acp->left_cookien);
5209 		} else {
5210 			size_t bufsz;
5211 
5212 			AACDB_PRINT_TRAN(softs,
5213 			    "non-aligned buffer: addr=0x%p, cnt=%lu",
5214 			    (void *)bp->b_un.b_addr, bp->b_bcount);
5215 			if (bp->b_flags & (B_PAGEIO|B_PHYS))
5216 				bp_mapin(bp);
5217 
5218 			rval = ddi_dma_mem_alloc(acp->buf_dma_handle,
5219 			    AAC_ROUNDUP(bp->b_bcount, AAC_DMA_ALIGN),
5220 			    &softs->acc_attr, DDI_DMA_STREAMING,
5221 			    cb, arg, &acp->abp, &bufsz, &acp->abh);
5222 
5223 			if (rval != DDI_SUCCESS) {
5224 				AACDB_PRINT(softs, CE_NOTE,
5225 				    "Cannot alloc DMA to non-aligned buf");
5226 				bioerr = 0;
5227 				goto error_out;
5228 			}
5229 
5230 			if (acp->flags & AAC_CMD_BUF_WRITE)
5231 				ddi_rep_put8(acp->abh,
5232 				    (uint8_t *)bp->b_un.b_addr,
5233 				    (uint8_t *)acp->abp, bp->b_bcount,
5234 				    DDI_DEV_AUTOINCR);
5235 
5236 			rval = ddi_dma_addr_bind_handle(acp->buf_dma_handle,
5237 			    NULL, acp->abp, bufsz, dma_flags, cb, arg,
5238 			    &acp->cookie, &acp->left_cookien);
5239 		}
5240 
5241 		switch (rval) {
5242 		case DDI_DMA_PARTIAL_MAP:
5243 			if (ddi_dma_numwin(acp->buf_dma_handle,
5244 			    &acp->total_nwin) == DDI_FAILURE) {
5245 				AACDB_PRINT(softs, CE_WARN,
5246 				    "Cannot get number of DMA windows");
5247 				bioerr = 0;
5248 				goto error_out;
5249 			}
5250 			AACDB_PRINT_TRAN(softs, "buf bind, %d seg(s)",
5251 			    acp->left_cookien);
5252 			acp->cur_win = 0;
5253 			break;
5254 
5255 		case DDI_DMA_MAPPED:
5256 			AACDB_PRINT_TRAN(softs, "buf bind, %d seg(s)",
5257 			    acp->left_cookien);
5258 			acp->cur_win = 0;
5259 			acp->total_nwin = 1;
5260 			break;
5261 
5262 		case DDI_DMA_NORESOURCES:
5263 			bioerr = 0;
5264 			AACDB_PRINT(softs, CE_WARN,
5265 			    "Cannot bind buf for DMA: DDI_DMA_NORESOURCES");
5266 			goto error_out;
5267 		case DDI_DMA_BADATTR:
5268 		case DDI_DMA_NOMAPPING:
5269 			bioerr = EFAULT;
5270 			AACDB_PRINT(softs, CE_WARN,
5271 			    "Cannot bind buf for DMA: DDI_DMA_NOMAPPING");
5272 			goto error_out;
5273 		case DDI_DMA_TOOBIG:
5274 			bioerr = EINVAL;
5275 			AACDB_PRINT(softs, CE_WARN,
5276 			    "Cannot bind buf for DMA: DDI_DMA_TOOBIG(%d)",
5277 			    bp->b_bcount);
5278 			goto error_out;
5279 		default:
5280 			bioerr = EINVAL;
5281 			AACDB_PRINT(softs, CE_WARN,
5282 			    "Cannot bind buf for DMA: %d", rval);
5283 			goto error_out;
5284 		}
5285 		acp->flags |= AAC_CMD_DMA_VALID;
5286 
5287 get_dma_cookies:
5288 		ASSERT(acp->left_cookien > 0);
5289 		if (acp->left_cookien > softs->aac_sg_tablesize) {
5290 			AACDB_PRINT(softs, CE_NOTE, "large cookiec received %d",
5291 			    acp->left_cookien);
5292 			bioerr = EINVAL;
5293 			goto error_out;
5294 		}
5295 		if (oldcookiec != acp->left_cookien && acp->sgt != NULL) {
5296 			kmem_free(acp->sgt, sizeof (struct aac_sge) * \
5297 			    oldcookiec);
5298 			acp->sgt = NULL;
5299 		}
5300 		if (acp->sgt == NULL) {
5301 			acp->sgt = kmem_alloc(sizeof (struct aac_sge) * \
5302 			    acp->left_cookien, kf);
5303 			if (acp->sgt == NULL) {
5304 				AACDB_PRINT(softs, CE_WARN,
5305 				    "sgt kmem_alloc fail");
5306 				bioerr = ENOMEM;
5307 				goto error_out;
5308 			}
5309 		}
5310 
5311 		sge = &acp->sgt[0];
5312 		sge->bcount = acp->cookie.dmac_size;
5313 		sge->addr.ad64.lo = AAC_LS32(acp->cookie.dmac_laddress);
5314 		sge->addr.ad64.hi = AAC_MS32(acp->cookie.dmac_laddress);
5315 		acp->bcount = acp->cookie.dmac_size;
5316 		for (sge++; sge < &acp->sgt[acp->left_cookien]; sge++) {
5317 			ddi_dma_nextcookie(acp->buf_dma_handle, &acp->cookie);
5318 			sge->bcount = acp->cookie.dmac_size;
5319 			sge->addr.ad64.lo = AAC_LS32(acp->cookie.dmac_laddress);
5320 			sge->addr.ad64.hi = AAC_MS32(acp->cookie.dmac_laddress);
5321 			acp->bcount += acp->cookie.dmac_size;
5322 		}
5323 
5324 		/*
5325 		 * Note: The old DMA engine do not correctly handle
5326 		 * dma_attr_maxxfer attribute. So we have to ensure
5327 		 * it by ourself.
5328 		 */
5329 		if (acp->bcount > softs->buf_dma_attr.dma_attr_maxxfer) {
5330 			AACDB_PRINT(softs, CE_NOTE,
5331 			    "large xfer size received %d\n", acp->bcount);
5332 			bioerr = EINVAL;
5333 			goto error_out;
5334 		}
5335 
5336 		acp->total_xfer += acp->bcount;
5337 
5338 		if (acp->pkt) {
5339 			/* Return remaining byte count */
5340 			if (acp->total_xfer <= bp->b_bcount) {
5341 				acp->pkt->pkt_resid = bp->b_bcount - \
5342 				    acp->total_xfer;
5343 			} else {
5344 				/*
5345 				 * Allocated DMA size is greater than the buf
5346 				 * size of bp. This is caused by devices like
5347 				 * tape. we have extra bytes allocated, but
5348 				 * the packet residual has to stay correct.
5349 				 */
5350 				acp->pkt->pkt_resid = 0;
5351 			}
5352 			AACDB_PRINT_TRAN(softs,
5353 			    "bp=0x%p, xfered=%d/%d, resid=%d",
5354 			    (void *)bp->b_un.b_addr, (int)acp->total_xfer,
5355 			    (int)bp->b_bcount, (int)acp->pkt->pkt_resid);
5356 		}
5357 	}
5358 	return (AACOK);
5359 
5360 error_out:
5361 	bioerror(bp, bioerr);
5362 	return (AACERR);
5363 }
5364 
5365 static struct scsi_pkt *
aac_tran_init_pkt(struct scsi_address * ap,struct scsi_pkt * pkt,struct buf * bp,int cmdlen,int statuslen,int tgtlen,int flags,int (* callback)(),caddr_t arg)5366 aac_tran_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
5367     struct buf *bp, int cmdlen, int statuslen, int tgtlen, int flags,
5368     int (*callback)(), caddr_t arg)
5369 {
5370 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
5371 	struct aac_cmd *acp, *new_acp;
5372 
5373 	DBCALLED(softs, 2);
5374 
5375 	/* Allocate pkt */
5376 	if (pkt == NULL) {
5377 		int slen;
5378 
5379 		/* Force auto request sense */
5380 		slen = (statuslen > softs->slen) ? statuslen : softs->slen;
5381 		pkt = scsi_hba_pkt_alloc(softs->devinfo_p, ap, cmdlen,
5382 		    slen, tgtlen, sizeof (struct aac_cmd), callback, arg);
5383 		if (pkt == NULL) {
5384 			AACDB_PRINT(softs, CE_WARN, "Alloc scsi pkt failed");
5385 			return (NULL);
5386 		}
5387 		acp = new_acp = PKT2AC(pkt);
5388 		acp->pkt = pkt;
5389 		acp->cmdlen = cmdlen;
5390 
5391 		if (ap->a_target < AAC_MAX_LD) {
5392 			acp->dvp = &softs->containers[ap->a_target].dev;
5393 			acp->aac_cmd_fib = softs->aac_cmd_fib;
5394 			acp->ac_comp = aac_ld_complete;
5395 		} else {
5396 			_NOTE(ASSUMING_PROTECTED(softs->nondasds))
5397 
5398 			acp->dvp = &softs->nondasds[AAC_PD(ap->a_target)].dev;
5399 			acp->aac_cmd_fib = softs->aac_cmd_fib_scsi;
5400 			acp->ac_comp = aac_pd_complete;
5401 		}
5402 	} else {
5403 		acp = PKT2AC(pkt);
5404 		new_acp = NULL;
5405 	}
5406 
5407 	if (aac_cmd_dma_alloc(softs, acp, bp, flags, callback, arg) == AACOK)
5408 		return (pkt);
5409 
5410 	if (new_acp)
5411 		aac_tran_destroy_pkt(ap, pkt);
5412 	return (NULL);
5413 }
5414 
5415 /*
5416  * tran_sync_pkt(9E) - explicit DMA synchronization
5417  */
5418 /*ARGSUSED*/
5419 static void
aac_tran_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)5420 aac_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
5421 {
5422 	struct aac_cmd *acp = PKT2AC(pkt);
5423 
5424 	DBCALLED(NULL, 2);
5425 
5426 	if (aac_dma_sync_ac(acp) != AACOK)
5427 		ddi_fm_service_impact(
5428 		    (AAC_TRAN2SOFTS(ap->a_hba_tran))->devinfo_p,
5429 		    DDI_SERVICE_UNAFFECTED);
5430 }
5431 
5432 /*
5433  * tran_dmafree(9E) - deallocate DMA resources allocated for command
5434  */
5435 /*ARGSUSED*/
5436 static void
aac_tran_dmafree(struct scsi_address * ap,struct scsi_pkt * pkt)5437 aac_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
5438 {
5439 	struct aac_cmd *acp = PKT2AC(pkt);
5440 
5441 	DBCALLED(NULL, 2);
5442 
5443 	aac_free_dmamap(acp);
5444 }
5445 
5446 static int
aac_do_quiesce(struct aac_softstate * softs)5447 aac_do_quiesce(struct aac_softstate *softs)
5448 {
5449 	aac_hold_bus(softs, AAC_IOCMD_ASYNC);
5450 	if (softs->bus_ncmds[AAC_CMDQ_ASYNC]) {
5451 		aac_start_drain(softs);
5452 		do {
5453 			if (cv_wait_sig(&softs->drain_cv,
5454 			    &softs->io_lock) == 0) {
5455 				/* Quiesce has been interrupted */
5456 				aac_stop_drain(softs);
5457 				aac_unhold_bus(softs, AAC_IOCMD_ASYNC);
5458 				aac_start_waiting_io(softs);
5459 				return (AACERR);
5460 			}
5461 		} while (softs->bus_ncmds[AAC_CMDQ_ASYNC]);
5462 		aac_stop_drain(softs);
5463 	}
5464 
5465 	softs->state |= AAC_STATE_QUIESCED;
5466 	return (AACOK);
5467 }
5468 
5469 static int
aac_tran_quiesce(dev_info_t * dip)5470 aac_tran_quiesce(dev_info_t *dip)
5471 {
5472 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
5473 	int rval;
5474 
5475 	DBCALLED(softs, 1);
5476 
5477 	mutex_enter(&softs->io_lock);
5478 	if (aac_do_quiesce(softs) == AACOK)
5479 		rval = 0;
5480 	else
5481 		rval = 1;
5482 	mutex_exit(&softs->io_lock);
5483 	return (rval);
5484 }
5485 
5486 static int
aac_do_unquiesce(struct aac_softstate * softs)5487 aac_do_unquiesce(struct aac_softstate *softs)
5488 {
5489 	softs->state &= ~AAC_STATE_QUIESCED;
5490 	aac_unhold_bus(softs, AAC_IOCMD_ASYNC);
5491 
5492 	aac_start_waiting_io(softs);
5493 	return (AACOK);
5494 }
5495 
5496 static int
aac_tran_unquiesce(dev_info_t * dip)5497 aac_tran_unquiesce(dev_info_t *dip)
5498 {
5499 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
5500 	int rval;
5501 
5502 	DBCALLED(softs, 1);
5503 
5504 	mutex_enter(&softs->io_lock);
5505 	if (aac_do_unquiesce(softs) == AACOK)
5506 		rval = 0;
5507 	else
5508 		rval = 1;
5509 	mutex_exit(&softs->io_lock);
5510 	return (rval);
5511 }
5512 
5513 static int
aac_hba_setup(struct aac_softstate * softs)5514 aac_hba_setup(struct aac_softstate *softs)
5515 {
5516 	scsi_hba_tran_t *hba_tran;
5517 	int rval;
5518 
5519 	hba_tran = scsi_hba_tran_alloc(softs->devinfo_p, SCSI_HBA_CANSLEEP);
5520 	if (hba_tran == NULL)
5521 		return (AACERR);
5522 	hba_tran->tran_hba_private = softs;
5523 	hba_tran->tran_tgt_init = aac_tran_tgt_init;
5524 	hba_tran->tran_tgt_free = aac_tran_tgt_free;
5525 	hba_tran->tran_tgt_probe = scsi_hba_probe;
5526 	hba_tran->tran_start = aac_tran_start;
5527 	hba_tran->tran_getcap = aac_tran_getcap;
5528 	hba_tran->tran_setcap = aac_tran_setcap;
5529 	hba_tran->tran_init_pkt = aac_tran_init_pkt;
5530 	hba_tran->tran_destroy_pkt = aac_tran_destroy_pkt;
5531 	hba_tran->tran_reset = aac_tran_reset;
5532 	hba_tran->tran_abort = aac_tran_abort;
5533 	hba_tran->tran_sync_pkt = aac_tran_sync_pkt;
5534 	hba_tran->tran_dmafree = aac_tran_dmafree;
5535 	hba_tran->tran_quiesce = aac_tran_quiesce;
5536 	hba_tran->tran_unquiesce = aac_tran_unquiesce;
5537 	hba_tran->tran_bus_config = aac_tran_bus_config;
5538 	rval = scsi_hba_attach_setup(softs->devinfo_p, &softs->buf_dma_attr,
5539 	    hba_tran, 0);
5540 	if (rval != DDI_SUCCESS) {
5541 		scsi_hba_tran_free(hba_tran);
5542 		AACDB_PRINT(softs, CE_WARN, "aac_hba_setup failed");
5543 		return (AACERR);
5544 	}
5545 
5546 	softs->hba_tran = hba_tran;
5547 	return (AACOK);
5548 }
5549 
5550 /*
5551  * FIB setup operations
5552  */
5553 
5554 /*
5555  * Init FIB header
5556  */
5557 static void
aac_cmd_fib_header(struct aac_softstate * softs,struct aac_cmd * acp,uint16_t cmd)5558 aac_cmd_fib_header(struct aac_softstate *softs, struct aac_cmd *acp,
5559     uint16_t cmd)
5560 {
5561 	struct aac_slot *slotp = acp->slotp;
5562 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
5563 	struct aac_fib *fibp = slotp->fibp;
5564 	uint32_t xfer_state;
5565 
5566 	xfer_state =
5567 	    AAC_FIBSTATE_HOSTOWNED |
5568 	    AAC_FIBSTATE_INITIALISED |
5569 	    AAC_FIBSTATE_EMPTY |
5570 	    AAC_FIBSTATE_FAST_RESPONSE | /* enable fast io */
5571 	    AAC_FIBSTATE_FROMHOST |
5572 	    AAC_FIBSTATE_REXPECTED |
5573 	    AAC_FIBSTATE_NORM;
5574 
5575 	if (!(acp->flags & AAC_CMD_SYNC))
5576 		xfer_state |= AAC_FIBSTATE_ASYNC;
5577 
5578 	ddi_put32(acc, &fibp->Header.XferState, xfer_state);
5579 	ddi_put16(acc, &fibp->Header.Command, cmd);
5580 	ddi_put8(acc, &fibp->Header.StructType, AAC_FIBTYPE_TFIB);
5581 	ddi_put8(acc, &fibp->Header.Flags, 0); /* don't care */
5582 	ddi_put16(acc, &fibp->Header.Size, acp->fib_size);
5583 	ddi_put16(acc, &fibp->Header.SenderSize, softs->aac_max_fib_size);
5584 	ddi_put32(acc, &fibp->Header.SenderFibAddress, (slotp->index << 2));
5585 	ddi_put32(acc, &fibp->Header.ReceiverFibAddress, slotp->fib_phyaddr);
5586 	ddi_put32(acc, &fibp->Header.SenderData, 0); /* don't care */
5587 }
5588 
5589 /*
5590  * Init FIB for raw IO command
5591  */
5592 static void
aac_cmd_fib_rawio(struct aac_softstate * softs,struct aac_cmd * acp)5593 aac_cmd_fib_rawio(struct aac_softstate *softs, struct aac_cmd *acp)
5594 {
5595 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5596 	struct aac_raw_io *io = (struct aac_raw_io *)&acp->slotp->fibp->data[0];
5597 	struct aac_sg_entryraw *sgp;
5598 	struct aac_sge *sge;
5599 
5600 	/* Calculate FIB size */
5601 	acp->fib_size = sizeof (struct aac_fib_header) + \
5602 	    sizeof (struct aac_raw_io) + (acp->left_cookien - 1) * \
5603 	    sizeof (struct aac_sg_entryraw);
5604 
5605 	aac_cmd_fib_header(softs, acp, RawIo);
5606 
5607 	ddi_put16(acc, &io->Flags, (acp->flags & AAC_CMD_BUF_READ) ? 1 : 0);
5608 	ddi_put16(acc, &io->BpTotal, 0);
5609 	ddi_put16(acc, &io->BpComplete, 0);
5610 
5611 	ddi_put32(acc, AAC_LO32(&io->BlockNumber), AAC_LS32(acp->blkno));
5612 	ddi_put32(acc, AAC_HI32(&io->BlockNumber), AAC_MS32(acp->blkno));
5613 	ddi_put16(acc, &io->ContainerId,
5614 	    ((struct aac_container *)acp->dvp)->cid);
5615 
5616 	/* Fill SG table */
5617 	ddi_put32(acc, &io->SgMapRaw.SgCount, acp->left_cookien);
5618 	ddi_put32(acc, &io->ByteCount, acp->bcount);
5619 
5620 	for (sge = &acp->sgt[0], sgp = &io->SgMapRaw.SgEntryRaw[0];
5621 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5622 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
5623 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
5624 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5625 		sgp->Next = 0;
5626 		sgp->Prev = 0;
5627 		sgp->Flags = 0;
5628 	}
5629 }
5630 
5631 /* Init FIB for 64-bit block IO command */
5632 static void
aac_cmd_fib_brw64(struct aac_softstate * softs,struct aac_cmd * acp)5633 aac_cmd_fib_brw64(struct aac_softstate *softs, struct aac_cmd *acp)
5634 {
5635 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5636 	struct aac_blockread64 *br = (struct aac_blockread64 *) \
5637 	    &acp->slotp->fibp->data[0];
5638 	struct aac_sg_entry64 *sgp;
5639 	struct aac_sge *sge;
5640 
5641 	acp->fib_size = sizeof (struct aac_fib_header) + \
5642 	    sizeof (struct aac_blockread64) + (acp->left_cookien - 1) * \
5643 	    sizeof (struct aac_sg_entry64);
5644 
5645 	aac_cmd_fib_header(softs, acp, ContainerCommand64);
5646 
5647 	/*
5648 	 * The definitions for aac_blockread64 and aac_blockwrite64
5649 	 * are the same.
5650 	 */
5651 	ddi_put32(acc, &br->BlockNumber, (uint32_t)acp->blkno);
5652 	ddi_put16(acc, &br->ContainerId,
5653 	    ((struct aac_container *)acp->dvp)->cid);
5654 	ddi_put32(acc, &br->Command, (acp->flags & AAC_CMD_BUF_READ) ?
5655 	    VM_CtHostRead64 : VM_CtHostWrite64);
5656 	ddi_put16(acc, &br->Pad, 0);
5657 	ddi_put16(acc, &br->Flags, 0);
5658 
5659 	/* Fill SG table */
5660 	ddi_put32(acc, &br->SgMap64.SgCount, acp->left_cookien);
5661 	ddi_put16(acc, &br->SectorCount, acp->bcount / AAC_BLK_SIZE);
5662 
5663 	for (sge = &acp->sgt[0], sgp = &br->SgMap64.SgEntry64[0];
5664 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5665 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
5666 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
5667 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5668 	}
5669 }
5670 
5671 /* Init FIB for block IO command */
5672 static void
aac_cmd_fib_brw(struct aac_softstate * softs,struct aac_cmd * acp)5673 aac_cmd_fib_brw(struct aac_softstate *softs, struct aac_cmd *acp)
5674 {
5675 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5676 	struct aac_blockread *br = (struct aac_blockread *) \
5677 	    &acp->slotp->fibp->data[0];
5678 	struct aac_sg_entry *sgp;
5679 	struct aac_sge *sge = &acp->sgt[0];
5680 
5681 	if (acp->flags & AAC_CMD_BUF_READ) {
5682 		acp->fib_size = sizeof (struct aac_fib_header) + \
5683 		    sizeof (struct aac_blockread) + (acp->left_cookien - 1) * \
5684 		    sizeof (struct aac_sg_entry);
5685 
5686 		ddi_put32(acc, &br->Command, VM_CtBlockRead);
5687 		ddi_put32(acc, &br->SgMap.SgCount, acp->left_cookien);
5688 		sgp = &br->SgMap.SgEntry[0];
5689 	} else {
5690 		struct aac_blockwrite *bw = (struct aac_blockwrite *)br;
5691 
5692 		acp->fib_size = sizeof (struct aac_fib_header) + \
5693 		    sizeof (struct aac_blockwrite) + (acp->left_cookien - 1) * \
5694 		    sizeof (struct aac_sg_entry);
5695 
5696 		ddi_put32(acc, &bw->Command, VM_CtBlockWrite);
5697 		ddi_put32(acc, &bw->Stable, CUNSTABLE);
5698 		ddi_put32(acc, &bw->SgMap.SgCount, acp->left_cookien);
5699 		sgp = &bw->SgMap.SgEntry[0];
5700 	}
5701 	aac_cmd_fib_header(softs, acp, ContainerCommand);
5702 
5703 	/*
5704 	 * aac_blockread and aac_blockwrite have the similar
5705 	 * structure head, so use br for bw here
5706 	 */
5707 	ddi_put32(acc, &br->BlockNumber, (uint32_t)acp->blkno);
5708 	ddi_put32(acc, &br->ContainerId,
5709 	    ((struct aac_container *)acp->dvp)->cid);
5710 	ddi_put32(acc, &br->ByteCount, acp->bcount);
5711 
5712 	/* Fill SG table */
5713 	for (sge = &acp->sgt[0];
5714 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5715 		ddi_put32(acc, &sgp->SgAddress, sge->addr.ad32);
5716 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5717 	}
5718 }
5719 
5720 /*ARGSUSED*/
5721 void
aac_cmd_fib_copy(struct aac_softstate * softs,struct aac_cmd * acp)5722 aac_cmd_fib_copy(struct aac_softstate *softs, struct aac_cmd *acp)
5723 {
5724 	struct aac_slot *slotp = acp->slotp;
5725 	struct aac_fib *fibp = slotp->fibp;
5726 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
5727 
5728 	ddi_rep_put8(acc, (uint8_t *)acp->fibp, (uint8_t *)fibp,
5729 	    acp->fib_size,   /* only copy data of needed length */
5730 	    DDI_DEV_AUTOINCR);
5731 	ddi_put32(acc, &fibp->Header.ReceiverFibAddress, slotp->fib_phyaddr);
5732 	ddi_put32(acc, &fibp->Header.SenderFibAddress, slotp->index << 2);
5733 }
5734 
5735 static void
aac_cmd_fib_sync(struct aac_softstate * softs,struct aac_cmd * acp)5736 aac_cmd_fib_sync(struct aac_softstate *softs, struct aac_cmd *acp)
5737 {
5738 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5739 	struct aac_synchronize_command *sync =
5740 	    (struct aac_synchronize_command *)&acp->slotp->fibp->data[0];
5741 
5742 	acp->fib_size = AAC_FIB_SIZEOF(struct aac_synchronize_command);
5743 
5744 	aac_cmd_fib_header(softs, acp, ContainerCommand);
5745 	ddi_put32(acc, &sync->Command, VM_ContainerConfig);
5746 	ddi_put32(acc, &sync->Type, (uint32_t)CT_FLUSH_CACHE);
5747 	ddi_put32(acc, &sync->Cid, ((struct aac_container *)acp->dvp)->cid);
5748 	ddi_put32(acc, &sync->Count,
5749 	    sizeof (((struct aac_synchronize_reply *)0)->Data));
5750 }
5751 
5752 /*
5753  * Start/Stop unit (Power Management)
5754  */
5755 static void
aac_cmd_fib_startstop(struct aac_softstate * softs,struct aac_cmd * acp)5756 aac_cmd_fib_startstop(struct aac_softstate *softs, struct aac_cmd *acp)
5757 {
5758 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5759 	struct aac_Container *cmd =
5760 	    (struct aac_Container *)&acp->slotp->fibp->data[0];
5761 	union scsi_cdb *cdbp = (void *)acp->pkt->pkt_cdbp;
5762 
5763 	acp->fib_size = AAC_FIB_SIZEOF(struct aac_Container);
5764 
5765 	aac_cmd_fib_header(softs, acp, ContainerCommand);
5766 	bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
5767 	ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
5768 	ddi_put32(acc, &cmd->CTCommand.command, CT_PM_DRIVER_SUPPORT);
5769 	ddi_put32(acc, &cmd->CTCommand.param[0], cdbp->cdb_opaque[4] & 1 ? \
5770 	    AAC_PM_DRIVERSUP_START_UNIT : AAC_PM_DRIVERSUP_STOP_UNIT);
5771 	ddi_put32(acc, &cmd->CTCommand.param[1],
5772 	    ((struct aac_container *)acp->dvp)->cid);
5773 	ddi_put32(acc, &cmd->CTCommand.param[2], cdbp->cdb_opaque[1] & 1);
5774 }
5775 
5776 /*
5777  * Init FIB for pass-through SCMD
5778  */
5779 static void
aac_cmd_fib_srb(struct aac_cmd * acp)5780 aac_cmd_fib_srb(struct aac_cmd *acp)
5781 {
5782 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5783 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
5784 	uint8_t *cdb;
5785 
5786 	ddi_put32(acc, &srb->function, SRBF_ExecuteScsi);
5787 	ddi_put32(acc, &srb->retry_limit, 0);
5788 	ddi_put32(acc, &srb->cdb_size, acp->cmdlen);
5789 	ddi_put32(acc, &srb->timeout, 0); /* use driver timeout */
5790 	if (acp->fibp == NULL) {
5791 		if (acp->flags & AAC_CMD_BUF_READ)
5792 			ddi_put32(acc, &srb->flags, SRB_DataIn);
5793 		else if (acp->flags & AAC_CMD_BUF_WRITE)
5794 			ddi_put32(acc, &srb->flags, SRB_DataOut);
5795 		ddi_put32(acc, &srb->channel,
5796 		    ((struct aac_nondasd *)acp->dvp)->bus);
5797 		ddi_put32(acc, &srb->id, ((struct aac_nondasd *)acp->dvp)->tid);
5798 		ddi_put32(acc, &srb->lun, 0);
5799 		cdb = acp->pkt->pkt_cdbp;
5800 	} else {
5801 		struct aac_srb *srb0 = (struct aac_srb *)&acp->fibp->data[0];
5802 
5803 		ddi_put32(acc, &srb->flags, srb0->flags);
5804 		ddi_put32(acc, &srb->channel, srb0->channel);
5805 		ddi_put32(acc, &srb->id, srb0->id);
5806 		ddi_put32(acc, &srb->lun, srb0->lun);
5807 		cdb = srb0->cdb;
5808 	}
5809 	ddi_rep_put8(acc, cdb, srb->cdb, acp->cmdlen, DDI_DEV_AUTOINCR);
5810 }
5811 
5812 static void
aac_cmd_fib_scsi32(struct aac_softstate * softs,struct aac_cmd * acp)5813 aac_cmd_fib_scsi32(struct aac_softstate *softs, struct aac_cmd *acp)
5814 {
5815 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5816 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
5817 	struct aac_sg_entry *sgp;
5818 	struct aac_sge *sge;
5819 
5820 	acp->fib_size = sizeof (struct aac_fib_header) + \
5821 	    sizeof (struct aac_srb) - sizeof (struct aac_sg_entry) + \
5822 	    acp->left_cookien * sizeof (struct aac_sg_entry);
5823 
5824 	/* Fill FIB and SRB headers, and copy cdb */
5825 	aac_cmd_fib_header(softs, acp, ScsiPortCommand);
5826 	aac_cmd_fib_srb(acp);
5827 
5828 	/* Fill SG table */
5829 	ddi_put32(acc, &srb->sg.SgCount, acp->left_cookien);
5830 	ddi_put32(acc, &srb->count, acp->bcount);
5831 
5832 	for (sge = &acp->sgt[0], sgp = &srb->sg.SgEntry[0];
5833 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5834 		ddi_put32(acc, &sgp->SgAddress, sge->addr.ad32);
5835 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5836 	}
5837 }
5838 
5839 static void
aac_cmd_fib_scsi64(struct aac_softstate * softs,struct aac_cmd * acp)5840 aac_cmd_fib_scsi64(struct aac_softstate *softs, struct aac_cmd *acp)
5841 {
5842 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5843 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
5844 	struct aac_sg_entry64 *sgp;
5845 	struct aac_sge *sge;
5846 
5847 	acp->fib_size = sizeof (struct aac_fib_header) + \
5848 	    sizeof (struct aac_srb) - sizeof (struct aac_sg_entry) + \
5849 	    acp->left_cookien * sizeof (struct aac_sg_entry64);
5850 
5851 	/* Fill FIB and SRB headers, and copy cdb */
5852 	aac_cmd_fib_header(softs, acp, ScsiPortCommandU64);
5853 	aac_cmd_fib_srb(acp);
5854 
5855 	/* Fill SG table */
5856 	ddi_put32(acc, &srb->sg.SgCount, acp->left_cookien);
5857 	ddi_put32(acc, &srb->count, acp->bcount);
5858 
5859 	for (sge = &acp->sgt[0],
5860 	    sgp = &((struct aac_sg_table64 *)&srb->sg)->SgEntry64[0];
5861 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5862 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
5863 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
5864 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5865 	}
5866 }
5867 
5868 static int
aac_cmd_slot_bind(struct aac_softstate * softs,struct aac_cmd * acp)5869 aac_cmd_slot_bind(struct aac_softstate *softs, struct aac_cmd *acp)
5870 {
5871 	struct aac_slot *slotp;
5872 
5873 	if (slotp = aac_get_slot(softs)) {
5874 		acp->slotp = slotp;
5875 		slotp->acp = acp;
5876 		acp->aac_cmd_fib(softs, acp);
5877 		(void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0,
5878 		    DDI_DMA_SYNC_FORDEV);
5879 		return (AACOK);
5880 	}
5881 	return (AACERR);
5882 }
5883 
5884 static int
aac_bind_io(struct aac_softstate * softs,struct aac_cmd * acp)5885 aac_bind_io(struct aac_softstate *softs, struct aac_cmd *acp)
5886 {
5887 	struct aac_device *dvp = acp->dvp;
5888 	int q = AAC_CMDQ(acp);
5889 
5890 	if (softs->bus_ncmds[q] < softs->bus_throttle[q]) {
5891 		if (dvp) {
5892 			if (dvp->ncmds[q] < dvp->throttle[q]) {
5893 				if (!(acp->flags & AAC_CMD_NTAG) ||
5894 				    dvp->ncmds[q] == 0) {
5895 					return (aac_cmd_slot_bind(softs, acp));
5896 				}
5897 				ASSERT(q == AAC_CMDQ_ASYNC);
5898 				aac_set_throttle(softs, dvp, AAC_CMDQ_ASYNC,
5899 				    AAC_THROTTLE_DRAIN);
5900 			}
5901 		} else {
5902 			return (aac_cmd_slot_bind(softs, acp));
5903 		}
5904 	}
5905 	return (AACERR);
5906 }
5907 
5908 static int
aac_sync_fib_slot_bind(struct aac_softstate * softs,struct aac_cmd * acp)5909 aac_sync_fib_slot_bind(struct aac_softstate *softs, struct aac_cmd *acp)
5910 {
5911 	struct aac_slot *slotp;
5912 
5913 	while (softs->sync_ac.slotp)
5914 		cv_wait(&softs->sync_fib_cv, &softs->io_lock);
5915 
5916 	if (slotp = aac_get_slot(softs)) {
5917 		ASSERT(acp->slotp == NULL);
5918 
5919 		acp->slotp = slotp;
5920 		slotp->acp = acp;
5921 		return (AACOK);
5922 	}
5923 	return (AACERR);
5924 }
5925 
5926 static void
aac_sync_fib_slot_release(struct aac_softstate * softs,struct aac_cmd * acp)5927 aac_sync_fib_slot_release(struct aac_softstate *softs, struct aac_cmd *acp)
5928 {
5929 	ASSERT(acp->slotp);
5930 
5931 	aac_release_slot(softs, acp->slotp);
5932 	acp->slotp->acp = NULL;
5933 	acp->slotp = NULL;
5934 
5935 	cv_signal(&softs->sync_fib_cv);
5936 }
5937 
5938 static void
aac_start_io(struct aac_softstate * softs,struct aac_cmd * acp)5939 aac_start_io(struct aac_softstate *softs, struct aac_cmd *acp)
5940 {
5941 	struct aac_slot *slotp = acp->slotp;
5942 	int q = AAC_CMDQ(acp);
5943 	int rval;
5944 
5945 	/* Set ac and pkt */
5946 	if (acp->pkt) { /* ac from ioctl has no pkt */
5947 		acp->pkt->pkt_state |=
5948 		    STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD;
5949 	}
5950 	if (acp->timeout) /* 0 indicates no timeout */
5951 		acp->timeout += aac_timebase + aac_tick;
5952 
5953 	if (acp->dvp)
5954 		acp->dvp->ncmds[q]++;
5955 	softs->bus_ncmds[q]++;
5956 	aac_cmd_enqueue(&softs->q_busy, acp);
5957 
5958 	AACDB_PRINT_FIB(softs, slotp);
5959 
5960 	if (softs->flags & AAC_FLAGS_NEW_COMM) {
5961 		rval = aac_send_command(softs, slotp);
5962 	} else {
5963 		/*
5964 		 * If fib can not be enqueued, the adapter is in an abnormal
5965 		 * state, there will be no interrupt to us.
5966 		 */
5967 		rval = aac_fib_enqueue(softs, AAC_ADAP_NORM_CMD_Q,
5968 		    slotp->fib_phyaddr, acp->fib_size);
5969 	}
5970 
5971 	if (aac_check_dma_handle(slotp->fib_dma_handle) != DDI_SUCCESS)
5972 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
5973 
5974 	/*
5975 	 * NOTE: We send command only when slots availabe, so should never
5976 	 * reach here.
5977 	 */
5978 	if (rval != AACOK) {
5979 		AACDB_PRINT(softs, CE_NOTE, "SCMD send failed");
5980 		if (acp->pkt) {
5981 			acp->pkt->pkt_state &= ~STATE_SENT_CMD;
5982 			aac_set_pkt_reason(softs, acp, CMD_INCOMPLETE, 0);
5983 		}
5984 		aac_end_io(softs, acp);
5985 		if (!(acp->flags & (AAC_CMD_NO_INTR | AAC_CMD_NO_CB)))
5986 			ddi_trigger_softintr(softs->softint_id);
5987 	}
5988 }
5989 
5990 static void
aac_start_waitq(struct aac_softstate * softs,struct aac_cmd_queue * q)5991 aac_start_waitq(struct aac_softstate *softs, struct aac_cmd_queue *q)
5992 {
5993 	struct aac_cmd *acp, *next_acp;
5994 
5995 	/* Serve as many waiting io's as possible */
5996 	for (acp = q->q_head; acp; acp = next_acp) {
5997 		next_acp = acp->next;
5998 		if (aac_bind_io(softs, acp) == AACOK) {
5999 			aac_cmd_delete(q, acp);
6000 			aac_start_io(softs, acp);
6001 		}
6002 		if (softs->free_io_slot_head == NULL)
6003 			break;
6004 	}
6005 }
6006 
6007 static void
aac_start_waiting_io(struct aac_softstate * softs)6008 aac_start_waiting_io(struct aac_softstate *softs)
6009 {
6010 	/*
6011 	 * Sync FIB io is served before async FIB io so that io requests
6012 	 * sent by interactive userland commands get responded asap.
6013 	 */
6014 	if (softs->q_wait[AAC_CMDQ_SYNC].q_head)
6015 		aac_start_waitq(softs, &softs->q_wait[AAC_CMDQ_SYNC]);
6016 	if (softs->q_wait[AAC_CMDQ_ASYNC].q_head)
6017 		aac_start_waitq(softs, &softs->q_wait[AAC_CMDQ_ASYNC]);
6018 }
6019 
6020 static void
aac_drain_comp_q(struct aac_softstate * softs)6021 aac_drain_comp_q(struct aac_softstate *softs)
6022 {
6023 	struct aac_cmd *acp;
6024 	struct scsi_pkt *pkt;
6025 
6026 	/*CONSTCOND*/
6027 	while (1) {
6028 		mutex_enter(&softs->q_comp_mutex);
6029 		acp = aac_cmd_dequeue(&softs->q_comp);
6030 		mutex_exit(&softs->q_comp_mutex);
6031 		if (acp != NULL) {
6032 			ASSERT(acp->pkt != NULL);
6033 			pkt = acp->pkt;
6034 
6035 			if (pkt->pkt_reason == CMD_CMPLT) {
6036 				/*
6037 				 * Consistent packets need to be sync'ed first
6038 				 */
6039 				if ((acp->flags & AAC_CMD_CONSISTENT) &&
6040 				    (acp->flags & AAC_CMD_BUF_READ)) {
6041 					if (aac_dma_sync_ac(acp) != AACOK) {
6042 						ddi_fm_service_impact(
6043 						    softs->devinfo_p,
6044 						    DDI_SERVICE_UNAFFECTED);
6045 						pkt->pkt_reason = CMD_TRAN_ERR;
6046 						pkt->pkt_statistics = 0;
6047 					}
6048 				}
6049 				if ((aac_check_acc_handle(softs-> \
6050 				    comm_space_acc_handle) != DDI_SUCCESS) ||
6051 				    (aac_check_acc_handle(softs-> \
6052 				    pci_mem_handle) != DDI_SUCCESS)) {
6053 					ddi_fm_service_impact(softs->devinfo_p,
6054 					    DDI_SERVICE_UNAFFECTED);
6055 					ddi_fm_acc_err_clear(softs-> \
6056 					    pci_mem_handle, DDI_FME_VER0);
6057 					pkt->pkt_reason = CMD_TRAN_ERR;
6058 					pkt->pkt_statistics = 0;
6059 				}
6060 				if (aac_check_dma_handle(softs-> \
6061 				    comm_space_dma_handle) != DDI_SUCCESS) {
6062 					ddi_fm_service_impact(softs->devinfo_p,
6063 					    DDI_SERVICE_UNAFFECTED);
6064 					pkt->pkt_reason = CMD_TRAN_ERR;
6065 					pkt->pkt_statistics = 0;
6066 				}
6067 			}
6068 			scsi_hba_pkt_comp(pkt);
6069 		} else {
6070 			break;
6071 		}
6072 	}
6073 }
6074 
6075 static int
aac_alloc_fib(struct aac_softstate * softs,struct aac_slot * slotp)6076 aac_alloc_fib(struct aac_softstate *softs, struct aac_slot *slotp)
6077 {
6078 	size_t rlen;
6079 	ddi_dma_cookie_t cookie;
6080 	uint_t cookien;
6081 
6082 	/* Allocate FIB dma resource */
6083 	if (ddi_dma_alloc_handle(
6084 	    softs->devinfo_p,
6085 	    &softs->addr_dma_attr,
6086 	    DDI_DMA_SLEEP,
6087 	    NULL,
6088 	    &slotp->fib_dma_handle) != DDI_SUCCESS) {
6089 		AACDB_PRINT(softs, CE_WARN,
6090 		    "Cannot alloc dma handle for slot fib area");
6091 		goto error;
6092 	}
6093 	if (ddi_dma_mem_alloc(
6094 	    slotp->fib_dma_handle,
6095 	    softs->aac_max_fib_size,
6096 	    &softs->acc_attr,
6097 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6098 	    DDI_DMA_SLEEP,
6099 	    NULL,
6100 	    (caddr_t *)&slotp->fibp,
6101 	    &rlen,
6102 	    &slotp->fib_acc_handle) != DDI_SUCCESS) {
6103 		AACDB_PRINT(softs, CE_WARN,
6104 		    "Cannot alloc mem for slot fib area");
6105 		goto error;
6106 	}
6107 	if (ddi_dma_addr_bind_handle(
6108 	    slotp->fib_dma_handle,
6109 	    NULL,
6110 	    (caddr_t)slotp->fibp,
6111 	    softs->aac_max_fib_size,
6112 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6113 	    DDI_DMA_SLEEP,
6114 	    NULL,
6115 	    &cookie,
6116 	    &cookien) != DDI_DMA_MAPPED) {
6117 		AACDB_PRINT(softs, CE_WARN,
6118 		    "dma bind failed for slot fib area");
6119 		goto error;
6120 	}
6121 
6122 	/* Check dma handles allocated in fib attach */
6123 	if (aac_check_dma_handle(slotp->fib_dma_handle) != DDI_SUCCESS) {
6124 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
6125 		goto error;
6126 	}
6127 
6128 	/* Check acc handles allocated in fib attach */
6129 	if (aac_check_acc_handle(slotp->fib_acc_handle) != DDI_SUCCESS) {
6130 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
6131 		goto error;
6132 	}
6133 
6134 	slotp->fib_phyaddr = cookie.dmac_laddress;
6135 	return (AACOK);
6136 
6137 error:
6138 	if (slotp->fib_acc_handle) {
6139 		ddi_dma_mem_free(&slotp->fib_acc_handle);
6140 		slotp->fib_acc_handle = NULL;
6141 	}
6142 	if (slotp->fib_dma_handle) {
6143 		ddi_dma_free_handle(&slotp->fib_dma_handle);
6144 		slotp->fib_dma_handle = NULL;
6145 	}
6146 	return (AACERR);
6147 }
6148 
6149 static void
aac_free_fib(struct aac_slot * slotp)6150 aac_free_fib(struct aac_slot *slotp)
6151 {
6152 	(void) ddi_dma_unbind_handle(slotp->fib_dma_handle);
6153 	ddi_dma_mem_free(&slotp->fib_acc_handle);
6154 	slotp->fib_acc_handle = NULL;
6155 	ddi_dma_free_handle(&slotp->fib_dma_handle);
6156 	slotp->fib_dma_handle = NULL;
6157 	slotp->fib_phyaddr = 0;
6158 }
6159 
6160 static void
aac_alloc_fibs(struct aac_softstate * softs)6161 aac_alloc_fibs(struct aac_softstate *softs)
6162 {
6163 	int i;
6164 	struct aac_slot *slotp;
6165 
6166 	for (i = 0; i < softs->total_slots &&
6167 	    softs->total_fibs < softs->total_slots; i++) {
6168 		slotp = &(softs->io_slot[i]);
6169 		if (slotp->fib_phyaddr)
6170 			continue;
6171 		if (aac_alloc_fib(softs, slotp) != AACOK)
6172 			break;
6173 
6174 		/* Insert the slot to the free slot list */
6175 		aac_release_slot(softs, slotp);
6176 		softs->total_fibs++;
6177 	}
6178 }
6179 
6180 static void
aac_destroy_fibs(struct aac_softstate * softs)6181 aac_destroy_fibs(struct aac_softstate *softs)
6182 {
6183 	struct aac_slot *slotp;
6184 
6185 	while ((slotp = softs->free_io_slot_head) != NULL) {
6186 		ASSERT(slotp->fib_phyaddr);
6187 		softs->free_io_slot_head = slotp->next;
6188 		aac_free_fib(slotp);
6189 		ASSERT(slotp->index == (slotp - softs->io_slot));
6190 		softs->total_fibs--;
6191 	}
6192 	ASSERT(softs->total_fibs == 0);
6193 }
6194 
6195 static int
aac_create_slots(struct aac_softstate * softs)6196 aac_create_slots(struct aac_softstate *softs)
6197 {
6198 	int i;
6199 
6200 	softs->total_slots = softs->aac_max_fibs;
6201 	softs->io_slot = kmem_zalloc(sizeof (struct aac_slot) * \
6202 	    softs->total_slots, KM_SLEEP);
6203 	if (softs->io_slot == NULL) {
6204 		AACDB_PRINT(softs, CE_WARN, "Cannot allocate slot");
6205 		return (AACERR);
6206 	}
6207 	for (i = 0; i < softs->total_slots; i++)
6208 		softs->io_slot[i].index = i;
6209 	softs->free_io_slot_head = NULL;
6210 	softs->total_fibs = 0;
6211 	return (AACOK);
6212 }
6213 
6214 static void
aac_destroy_slots(struct aac_softstate * softs)6215 aac_destroy_slots(struct aac_softstate *softs)
6216 {
6217 	ASSERT(softs->free_io_slot_head == NULL);
6218 
6219 	kmem_free(softs->io_slot, sizeof (struct aac_slot) * \
6220 	    softs->total_slots);
6221 	softs->io_slot = NULL;
6222 	softs->total_slots = 0;
6223 }
6224 
6225 struct aac_slot *
aac_get_slot(struct aac_softstate * softs)6226 aac_get_slot(struct aac_softstate *softs)
6227 {
6228 	struct aac_slot *slotp;
6229 
6230 	if ((slotp = softs->free_io_slot_head) != NULL) {
6231 		softs->free_io_slot_head = slotp->next;
6232 		slotp->next = NULL;
6233 	}
6234 	return (slotp);
6235 }
6236 
6237 static void
aac_release_slot(struct aac_softstate * softs,struct aac_slot * slotp)6238 aac_release_slot(struct aac_softstate *softs, struct aac_slot *slotp)
6239 {
6240 	ASSERT((slotp->index >= 0) && (slotp->index < softs->total_slots));
6241 	ASSERT(slotp == &softs->io_slot[slotp->index]);
6242 
6243 	slotp->acp = NULL;
6244 	slotp->next = softs->free_io_slot_head;
6245 	softs->free_io_slot_head = slotp;
6246 }
6247 
6248 int
aac_do_io(struct aac_softstate * softs,struct aac_cmd * acp)6249 aac_do_io(struct aac_softstate *softs, struct aac_cmd *acp)
6250 {
6251 	if (aac_bind_io(softs, acp) == AACOK)
6252 		aac_start_io(softs, acp);
6253 	else
6254 		aac_cmd_enqueue(&softs->q_wait[AAC_CMDQ(acp)], acp);
6255 
6256 	if (!(acp->flags & (AAC_CMD_NO_CB | AAC_CMD_NO_INTR)))
6257 		return (TRAN_ACCEPT);
6258 	/*
6259 	 * Because sync FIB is always 512 bytes and used for critical
6260 	 * functions, async FIB is used for poll IO.
6261 	 */
6262 	if (acp->flags & AAC_CMD_NO_INTR) {
6263 		if (aac_do_poll_io(softs, acp) == AACOK)
6264 			return (TRAN_ACCEPT);
6265 	} else {
6266 		if (aac_do_sync_io(softs, acp) == AACOK)
6267 			return (TRAN_ACCEPT);
6268 	}
6269 	return (TRAN_BADPKT);
6270 }
6271 
6272 static int
aac_do_poll_io(struct aac_softstate * softs,struct aac_cmd * acp)6273 aac_do_poll_io(struct aac_softstate *softs, struct aac_cmd *acp)
6274 {
6275 	int (*intr_handler)(struct aac_softstate *);
6276 
6277 	/*
6278 	 * Interrupt is disabled, we have to poll the adapter by ourselves.
6279 	 */
6280 	intr_handler = (softs->flags & AAC_FLAGS_NEW_COMM) ?
6281 	    aac_process_intr_new : aac_process_intr_old;
6282 	while (!(acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT))) {
6283 		int i = AAC_POLL_TIME * 1000;
6284 
6285 		AAC_BUSYWAIT((intr_handler(softs) != AAC_DB_RESPONSE_READY), i);
6286 		if (i == 0)
6287 			aac_cmd_timeout(softs, acp);
6288 	}
6289 
6290 	ddi_trigger_softintr(softs->softint_id);
6291 
6292 	if ((acp->flags & AAC_CMD_CMPLT) && !(acp->flags & AAC_CMD_ERR))
6293 		return (AACOK);
6294 	return (AACERR);
6295 }
6296 
6297 static int
aac_do_sync_io(struct aac_softstate * softs,struct aac_cmd * acp)6298 aac_do_sync_io(struct aac_softstate *softs, struct aac_cmd *acp)
6299 {
6300 	ASSERT(softs && acp);
6301 
6302 	while (!(acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT)))
6303 		cv_wait(&softs->event, &softs->io_lock);
6304 
6305 	if (acp->flags & AAC_CMD_CMPLT)
6306 		return (AACOK);
6307 	return (AACERR);
6308 }
6309 
6310 static int
aac_dma_sync_ac(struct aac_cmd * acp)6311 aac_dma_sync_ac(struct aac_cmd *acp)
6312 {
6313 	if (acp->buf_dma_handle) {
6314 		if (acp->flags & AAC_CMD_BUF_WRITE) {
6315 			if (acp->abp != NULL)
6316 				ddi_rep_put8(acp->abh,
6317 				    (uint8_t *)acp->bp->b_un.b_addr,
6318 				    (uint8_t *)acp->abp, acp->bp->b_bcount,
6319 				    DDI_DEV_AUTOINCR);
6320 			(void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
6321 			    DDI_DMA_SYNC_FORDEV);
6322 		} else {
6323 			(void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
6324 			    DDI_DMA_SYNC_FORCPU);
6325 			if (aac_check_dma_handle(acp->buf_dma_handle) !=
6326 			    DDI_SUCCESS)
6327 				return (AACERR);
6328 			if (acp->abp != NULL)
6329 				ddi_rep_get8(acp->abh,
6330 				    (uint8_t *)acp->bp->b_un.b_addr,
6331 				    (uint8_t *)acp->abp, acp->bp->b_bcount,
6332 				    DDI_DEV_AUTOINCR);
6333 		}
6334 	}
6335 	return (AACOK);
6336 }
6337 
6338 /*
6339  * Copy AIF from adapter to the empty AIF slot and inform AIF threads
6340  */
6341 static void
aac_save_aif(struct aac_softstate * softs,ddi_acc_handle_t acc,struct aac_fib * fibp0,int fib_size0)6342 aac_save_aif(struct aac_softstate *softs, ddi_acc_handle_t acc,
6343     struct aac_fib *fibp0, int fib_size0)
6344 {
6345 	struct aac_fib *fibp;	/* FIB in AIF queue */
6346 	int fib_size;
6347 	uint16_t fib_command;
6348 	int current, next;
6349 
6350 	/* Ignore non AIF messages */
6351 	fib_command = ddi_get16(acc, &fibp0->Header.Command);
6352 	if (fib_command != AifRequest) {
6353 		cmn_err(CE_WARN, "!Unknown command from controller");
6354 		return;
6355 	}
6356 
6357 	mutex_enter(&softs->aifq_mutex);
6358 
6359 	/* Save AIF */
6360 	fibp = &softs->aifq[softs->aifq_idx].d;
6361 	fib_size = (fib_size0 > AAC_FIB_SIZE) ? AAC_FIB_SIZE : fib_size0;
6362 	ddi_rep_get8(acc, (uint8_t *)fibp, (uint8_t *)fibp0, fib_size,
6363 	    DDI_DEV_AUTOINCR);
6364 
6365 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
6366 		ddi_fm_service_impact(softs->devinfo_p,
6367 		    DDI_SERVICE_UNAFFECTED);
6368 		mutex_exit(&softs->aifq_mutex);
6369 		return;
6370 	}
6371 
6372 	AACDB_PRINT_AIF(softs, (struct aac_aif_command *)&fibp->data[0]);
6373 
6374 	/* Modify AIF contexts */
6375 	current = softs->aifq_idx;
6376 	next = (current + 1) % AAC_AIFQ_LENGTH;
6377 	if (next == 0) {
6378 		struct aac_fib_context *ctx_p;
6379 
6380 		softs->aifq_wrap = 1;
6381 		for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) {
6382 			if (next == ctx_p->ctx_idx) {
6383 				ctx_p->ctx_flags |= AAC_CTXFLAG_FILLED;
6384 			} else if (current == ctx_p->ctx_idx &&
6385 			    (ctx_p->ctx_flags & AAC_CTXFLAG_FILLED)) {
6386 				ctx_p->ctx_idx = next;
6387 				ctx_p->ctx_overrun++;
6388 			}
6389 		}
6390 	}
6391 	softs->aifq_idx = next;
6392 
6393 	/* Wakeup AIF threads */
6394 	cv_broadcast(&softs->aifq_cv);
6395 	mutex_exit(&softs->aifq_mutex);
6396 
6397 	/* Wakeup event thread to handle aif */
6398 	aac_event_disp(softs, AAC_EVENT_AIF);
6399 }
6400 
6401 static int
aac_return_aif_common(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)6402 aac_return_aif_common(struct aac_softstate *softs, struct aac_fib_context *ctx,
6403     struct aac_fib **fibpp)
6404 {
6405 	int current;
6406 
6407 	current = ctx->ctx_idx;
6408 	if (current == softs->aifq_idx &&
6409 	    !(ctx->ctx_flags & AAC_CTXFLAG_FILLED))
6410 		return (EAGAIN); /* Empty */
6411 
6412 	*fibpp = &softs->aifq[current].d;
6413 
6414 	ctx->ctx_flags &= ~AAC_CTXFLAG_FILLED;
6415 	ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
6416 	return (0);
6417 }
6418 
6419 int
aac_return_aif(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)6420 aac_return_aif(struct aac_softstate *softs, struct aac_fib_context *ctx,
6421     struct aac_fib **fibpp)
6422 {
6423 	int rval;
6424 
6425 	mutex_enter(&softs->aifq_mutex);
6426 	rval = aac_return_aif_common(softs, ctx, fibpp);
6427 	mutex_exit(&softs->aifq_mutex);
6428 	return (rval);
6429 }
6430 
6431 int
aac_return_aif_wait(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)6432 aac_return_aif_wait(struct aac_softstate *softs, struct aac_fib_context *ctx,
6433     struct aac_fib **fibpp)
6434 {
6435 	int rval;
6436 
6437 	mutex_enter(&softs->aifq_mutex);
6438 	rval = aac_return_aif_common(softs, ctx, fibpp);
6439 	if (rval == EAGAIN) {
6440 		AACDB_PRINT(softs, CE_NOTE, "Waiting for AIF");
6441 		rval = cv_wait_sig(&softs->aifq_cv, &softs->aifq_mutex);
6442 	}
6443 	mutex_exit(&softs->aifq_mutex);
6444 	return ((rval > 0) ? 0 : EINTR);
6445 }
6446 
6447 /*
6448  * The following function comes from Adaptec:
6449  *
6450  * When driver sees a particular event that means containers are changed, it
6451  * will rescan containers. However a change may not be complete until some
6452  * other event is received. For example, creating or deleting an array will
6453  * incur as many as six AifEnConfigChange events which would generate six
6454  * container rescans. To diminish rescans, driver set a flag to wait for
6455  * another particular event. When sees that events come in, it will do rescan.
6456  */
6457 static int
aac_handle_aif(struct aac_softstate * softs,struct aac_aif_command * aif)6458 aac_handle_aif(struct aac_softstate *softs, struct aac_aif_command *aif)
6459 {
6460 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
6461 	int en_type;
6462 	int devcfg_needed;
6463 	int cid;
6464 	uint32_t bus_id, tgt_id;
6465 	enum aac_cfg_event event = AAC_CFG_NULL_EXIST;
6466 
6467 	devcfg_needed = 0;
6468 	en_type = LE_32((uint32_t)aif->data.EN.type);
6469 
6470 	switch (LE_32((uint32_t)aif->command)) {
6471 	case AifCmdDriverNotify: {
6472 		cid = LE_32(aif->data.EN.data.ECC.container[0]);
6473 
6474 		switch (en_type) {
6475 		case AifDenMorphComplete:
6476 		case AifDenVolumeExtendComplete:
6477 			if (AAC_DEV_IS_VALID(&softs->containers[cid].dev))
6478 				softs->devcfg_wait_on = AifEnConfigChange;
6479 			break;
6480 		}
6481 		if (softs->devcfg_wait_on == en_type)
6482 			devcfg_needed = 1;
6483 		break;
6484 	}
6485 
6486 	case AifCmdEventNotify:
6487 		cid = LE_32(aif->data.EN.data.ECC.container[0]);
6488 		switch (en_type) {
6489 		case AifEnAddContainer:
6490 		case AifEnDeleteContainer:
6491 			softs->devcfg_wait_on = AifEnConfigChange;
6492 			break;
6493 		case AifEnContainerChange:
6494 			if (!softs->devcfg_wait_on)
6495 				softs->devcfg_wait_on = AifEnConfigChange;
6496 			break;
6497 		case AifEnContainerEvent:
6498 			if (ddi_get32(acc, &aif-> \
6499 			    data.EN.data.ECE.eventType) == CT_PUP_MISSING_DRIVE)
6500 				devcfg_needed = 1;
6501 			break;
6502 		case AifEnAddJBOD:
6503 			if (!(softs->flags & AAC_FLAGS_JBOD))
6504 				return (AACERR);
6505 			event = AAC_CFG_ADD;
6506 			bus_id = (cid >> 24) & 0xf;
6507 			tgt_id = cid & 0xffff;
6508 			break;
6509 		case AifEnDeleteJBOD:
6510 			if (!(softs->flags & AAC_FLAGS_JBOD))
6511 				return (AACERR);
6512 			event = AAC_CFG_DELETE;
6513 			bus_id = (cid >> 24) & 0xf;
6514 			tgt_id = cid & 0xffff;
6515 			break;
6516 		}
6517 		if (softs->devcfg_wait_on == en_type)
6518 			devcfg_needed = 1;
6519 		break;
6520 
6521 	case AifCmdJobProgress:
6522 		if (LE_32((uint32_t)aif->data.PR[0].jd.type) == AifJobCtrZero) {
6523 			int pr_status;
6524 			uint32_t pr_ftick, pr_ctick;
6525 
6526 			pr_status = LE_32((uint32_t)aif->data.PR[0].status);
6527 			pr_ctick = LE_32(aif->data.PR[0].currentTick);
6528 			pr_ftick = LE_32(aif->data.PR[0].finalTick);
6529 
6530 			if ((pr_ctick == pr_ftick) ||
6531 			    (pr_status == AifJobStsSuccess))
6532 				softs->devcfg_wait_on = AifEnContainerChange;
6533 			else if ((pr_ctick == 0) &&
6534 			    (pr_status == AifJobStsRunning))
6535 				softs->devcfg_wait_on = AifEnContainerChange;
6536 		}
6537 		break;
6538 	}
6539 
6540 	if (devcfg_needed) {
6541 		softs->devcfg_wait_on = 0;
6542 		(void) aac_probe_containers(softs);
6543 	}
6544 
6545 	if (event != AAC_CFG_NULL_EXIST) {
6546 		ASSERT(en_type == AifEnAddJBOD || en_type == AifEnDeleteJBOD);
6547 		(void) aac_probe_jbod(softs,
6548 		    AAC_P2VTGT(softs, bus_id, tgt_id), event);
6549 	}
6550 	return (AACOK);
6551 }
6552 
6553 
6554 /*
6555  * Check and handle AIF events
6556  */
6557 static void
aac_aif_event(struct aac_softstate * softs)6558 aac_aif_event(struct aac_softstate *softs)
6559 {
6560 	struct aac_fib *fibp;
6561 
6562 	/*CONSTCOND*/
6563 	while (1) {
6564 		if (aac_return_aif(softs, &softs->aifctx, &fibp) != 0)
6565 			break; /* No more AIFs to handle, end loop */
6566 
6567 		/* AIF overrun, array create/delete may missed. */
6568 		if (softs->aifctx.ctx_overrun) {
6569 			softs->aifctx.ctx_overrun = 0;
6570 		}
6571 
6572 		/* AIF received, handle it */
6573 		struct aac_aif_command *aifp =
6574 		    (struct aac_aif_command *)&fibp->data[0];
6575 		uint32_t aif_command = LE_32((uint32_t)aifp->command);
6576 
6577 		if (aif_command == AifCmdDriverNotify ||
6578 		    aif_command == AifCmdEventNotify ||
6579 		    aif_command == AifCmdJobProgress)
6580 			(void) aac_handle_aif(softs, aifp);
6581 	}
6582 }
6583 
6584 /*
6585  * Timeout recovery
6586  */
6587 /*ARGSUSED*/
6588 static void
aac_cmd_timeout(struct aac_softstate * softs,struct aac_cmd * acp)6589 aac_cmd_timeout(struct aac_softstate *softs, struct aac_cmd *acp)
6590 {
6591 #ifdef DEBUG
6592 	acp->fib_flags |= AACDB_FLAGS_FIB_TIMEOUT;
6593 	AACDB_PRINT(softs, CE_WARN, "acp %p timed out", acp);
6594 	AACDB_PRINT_FIB(softs, acp->slotp);
6595 #endif
6596 
6597 	/*
6598 	 * Besides the firmware in unhealthy state, an overloaded
6599 	 * adapter may also incur pkt timeout.
6600 	 * There is a chance for an adapter with a slower IOP to take
6601 	 * longer than 60 seconds to process the commands, such as when
6602 	 * to perform IOs. So the adapter is doing a build on a RAID-5
6603 	 * while being required longer completion times should be
6604 	 * tolerated.
6605 	 */
6606 	switch (aac_do_reset(softs)) {
6607 	case AAC_IOP_RESET_SUCCEED:
6608 		aac_abort_iocmds(softs, AAC_IOCMD_OUTSTANDING, NULL, CMD_RESET);
6609 		aac_start_waiting_io(softs);
6610 		break;
6611 	case AAC_IOP_RESET_FAILED:
6612 		/* Abort all waiting cmds when adapter is dead */
6613 		aac_abort_iocmds(softs, AAC_IOCMD_ALL, NULL, CMD_TIMEOUT);
6614 		break;
6615 	case AAC_IOP_RESET_ABNORMAL:
6616 		aac_start_waiting_io(softs);
6617 	}
6618 }
6619 
6620 /*
6621  * The following function comes from Adaptec:
6622  *
6623  * Time sync. command added to synchronize time with firmware every 30
6624  * minutes (required for correct AIF timestamps etc.)
6625  */
6626 static void
aac_sync_tick(struct aac_softstate * softs)6627 aac_sync_tick(struct aac_softstate *softs)
6628 {
6629 	ddi_acc_handle_t acc;
6630 	int rval;
6631 
6632 	mutex_enter(&softs->time_mutex);
6633 	ASSERT(softs->time_sync <= softs->timebase);
6634 	softs->time_sync = 0;
6635 	mutex_exit(&softs->time_mutex);
6636 
6637 	/* Time sync. with firmware every AAC_SYNC_TICK */
6638 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
6639 	acc = softs->sync_ac.slotp->fib_acc_handle;
6640 
6641 	ddi_put32(acc, (void *)&softs->sync_ac.slotp->fibp->data[0],
6642 	    ddi_get_time());
6643 	rval = aac_sync_fib(softs, SendHostTime, AAC_FIB_SIZEOF(uint32_t));
6644 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
6645 
6646 	mutex_enter(&softs->time_mutex);
6647 	softs->time_sync = softs->timebase;
6648 	if (rval != AACOK)
6649 		/* retry shortly */
6650 		softs->time_sync += aac_tick << 1;
6651 	else
6652 		softs->time_sync += AAC_SYNC_TICK;
6653 	mutex_exit(&softs->time_mutex);
6654 }
6655 
6656 /*
6657  * Timeout checking and handling
6658  */
6659 static void
aac_daemon(struct aac_softstate * softs)6660 aac_daemon(struct aac_softstate *softs)
6661 {
6662 	int time_out; /* set if timeout happened */
6663 	int time_adjust;
6664 	uint32_t softs_timebase;
6665 
6666 	mutex_enter(&softs->time_mutex);
6667 	ASSERT(softs->time_out <= softs->timebase);
6668 	softs->time_out = 0;
6669 	softs_timebase = softs->timebase;
6670 	mutex_exit(&softs->time_mutex);
6671 
6672 	/* Check slots for timeout pkts */
6673 	time_adjust = 0;
6674 	do {
6675 		struct aac_cmd *acp;
6676 
6677 		time_out = 0;
6678 		for (acp = softs->q_busy.q_head; acp; acp = acp->next) {
6679 			if (acp->timeout == 0)
6680 				continue;
6681 
6682 			/*
6683 			 * If timeout happened, update outstanding cmds
6684 			 * to be checked later again.
6685 			 */
6686 			if (time_adjust) {
6687 				acp->timeout += time_adjust;
6688 				continue;
6689 			}
6690 
6691 			if (acp->timeout <= softs_timebase) {
6692 				aac_cmd_timeout(softs, acp);
6693 				time_out = 1;
6694 				time_adjust = aac_tick * drv_usectohz(1000000);
6695 				break; /* timeout happened */
6696 			} else {
6697 				break; /* no timeout */
6698 			}
6699 		}
6700 	} while (time_out);
6701 
6702 	mutex_enter(&softs->time_mutex);
6703 	softs->time_out = softs->timebase + aac_tick;
6704 	mutex_exit(&softs->time_mutex);
6705 }
6706 
6707 /*
6708  * The event thread handles various tasks serially for the other parts of
6709  * the driver, so that they can run fast.
6710  */
6711 static void
aac_event_thread(struct aac_softstate * softs)6712 aac_event_thread(struct aac_softstate *softs)
6713 {
6714 	int run = 1;
6715 
6716 	DBCALLED(softs, 1);
6717 
6718 	mutex_enter(&softs->ev_lock);
6719 	while (run) {
6720 		int events;
6721 
6722 		if ((events = softs->events) == 0) {
6723 			cv_wait(&softs->event_disp_cv, &softs->ev_lock);
6724 			events = softs->events;
6725 		}
6726 		softs->events = 0;
6727 		mutex_exit(&softs->ev_lock);
6728 
6729 		mutex_enter(&softs->io_lock);
6730 		if ((softs->state & AAC_STATE_RUN) &&
6731 		    (softs->state & AAC_STATE_DEAD) == 0) {
6732 			if (events & AAC_EVENT_TIMEOUT)
6733 				aac_daemon(softs);
6734 			if (events & AAC_EVENT_SYNCTICK)
6735 				aac_sync_tick(softs);
6736 			if (events & AAC_EVENT_AIF)
6737 				aac_aif_event(softs);
6738 		} else {
6739 			run = 0;
6740 		}
6741 		mutex_exit(&softs->io_lock);
6742 
6743 		mutex_enter(&softs->ev_lock);
6744 	}
6745 
6746 	cv_signal(&softs->event_wait_cv);
6747 	mutex_exit(&softs->ev_lock);
6748 }
6749 
6750 /*
6751  * Internal timer. It is only responsbile for time counting and report time
6752  * related events. Events handling is done by aac_event_thread(), so that
6753  * the timer itself could be as precise as possible.
6754  */
6755 static void
aac_timer(void * arg)6756 aac_timer(void *arg)
6757 {
6758 	struct aac_softstate *softs = arg;
6759 	int events = 0;
6760 
6761 	mutex_enter(&softs->time_mutex);
6762 
6763 	/* If timer is being stopped, exit */
6764 	if (softs->timeout_id) {
6765 		softs->timeout_id = timeout(aac_timer, (void *)softs,
6766 		    (aac_tick * drv_usectohz(1000000)));
6767 	} else {
6768 		mutex_exit(&softs->time_mutex);
6769 		return;
6770 	}
6771 
6772 	/* Time counting */
6773 	softs->timebase += aac_tick;
6774 
6775 	/* Check time related events */
6776 	if (softs->time_out && softs->time_out <= softs->timebase)
6777 		events |= AAC_EVENT_TIMEOUT;
6778 	if (softs->time_sync && softs->time_sync <= softs->timebase)
6779 		events |= AAC_EVENT_SYNCTICK;
6780 
6781 	mutex_exit(&softs->time_mutex);
6782 
6783 	if (events)
6784 		aac_event_disp(softs, events);
6785 }
6786 
6787 /*
6788  * Dispatch events to daemon thread for handling
6789  */
6790 static void
aac_event_disp(struct aac_softstate * softs,int events)6791 aac_event_disp(struct aac_softstate *softs, int events)
6792 {
6793 	mutex_enter(&softs->ev_lock);
6794 	softs->events |= events;
6795 	cv_broadcast(&softs->event_disp_cv);
6796 	mutex_exit(&softs->ev_lock);
6797 }
6798 
6799 /*
6800  * Architecture dependent functions
6801  */
6802 static int
aac_rx_get_fwstatus(struct aac_softstate * softs)6803 aac_rx_get_fwstatus(struct aac_softstate *softs)
6804 {
6805 	return (PCI_MEM_GET32(softs, AAC_OMR0));
6806 }
6807 
6808 static int
aac_rx_get_mailbox(struct aac_softstate * softs,int mb)6809 aac_rx_get_mailbox(struct aac_softstate *softs, int mb)
6810 {
6811 	return (PCI_MEM_GET32(softs, AAC_RX_MAILBOX + mb * 4));
6812 }
6813 
6814 static void
aac_rx_set_mailbox(struct aac_softstate * softs,uint32_t cmd,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3)6815 aac_rx_set_mailbox(struct aac_softstate *softs, uint32_t cmd,
6816     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3)
6817 {
6818 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX, cmd);
6819 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 4, arg0);
6820 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 8, arg1);
6821 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 12, arg2);
6822 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 16, arg3);
6823 }
6824 
6825 static int
aac_rkt_get_fwstatus(struct aac_softstate * softs)6826 aac_rkt_get_fwstatus(struct aac_softstate *softs)
6827 {
6828 	return (PCI_MEM_GET32(softs, AAC_OMR0));
6829 }
6830 
6831 static int
aac_rkt_get_mailbox(struct aac_softstate * softs,int mb)6832 aac_rkt_get_mailbox(struct aac_softstate *softs, int mb)
6833 {
6834 	return (PCI_MEM_GET32(softs, AAC_RKT_MAILBOX + mb *4));
6835 }
6836 
6837 static void
aac_rkt_set_mailbox(struct aac_softstate * softs,uint32_t cmd,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3)6838 aac_rkt_set_mailbox(struct aac_softstate *softs, uint32_t cmd,
6839     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3)
6840 {
6841 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX, cmd);
6842 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 4, arg0);
6843 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 8, arg1);
6844 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 12, arg2);
6845 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 16, arg3);
6846 }
6847 
6848 /*
6849  * cb_ops functions
6850  */
6851 static int
aac_open(dev_t * devp,int flag,int otyp,cred_t * cred)6852 aac_open(dev_t *devp, int flag, int otyp, cred_t *cred)
6853 {
6854 	struct aac_softstate *softs;
6855 	int minor0, minor;
6856 	int instance;
6857 
6858 	DBCALLED(NULL, 2);
6859 
6860 	if (otyp != OTYP_BLK && otyp != OTYP_CHR)
6861 		return (EINVAL);
6862 
6863 	minor0 = getminor(*devp);
6864 	minor = AAC_SCSA_MINOR(minor0);
6865 
6866 	if (AAC_IS_SCSA_NODE(minor))
6867 		return (scsi_hba_open(devp, flag, otyp, cred));
6868 
6869 	instance = MINOR2INST(minor0);
6870 	if (instance >= AAC_MAX_ADAPTERS)
6871 		return (ENXIO);
6872 
6873 	softs = ddi_get_soft_state(aac_softstatep, instance);
6874 	if (softs == NULL)
6875 		return (ENXIO);
6876 
6877 	return (0);
6878 }
6879 
6880 /*ARGSUSED*/
6881 static int
aac_close(dev_t dev,int flag,int otyp,cred_t * cred)6882 aac_close(dev_t dev, int flag, int otyp, cred_t *cred)
6883 {
6884 	int minor0, minor;
6885 	int instance;
6886 
6887 	DBCALLED(NULL, 2);
6888 
6889 	if (otyp != OTYP_BLK && otyp != OTYP_CHR)
6890 		return (EINVAL);
6891 
6892 	minor0 = getminor(dev);
6893 	minor = AAC_SCSA_MINOR(minor0);
6894 
6895 	if (AAC_IS_SCSA_NODE(minor))
6896 		return (scsi_hba_close(dev, flag, otyp, cred));
6897 
6898 	instance = MINOR2INST(minor0);
6899 	if (instance >= AAC_MAX_ADAPTERS)
6900 		return (ENXIO);
6901 
6902 	return (0);
6903 }
6904 
6905 static int
aac_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * cred_p,int * rval_p)6906 aac_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
6907     int *rval_p)
6908 {
6909 	struct aac_softstate *softs;
6910 	int minor0, minor;
6911 	int instance;
6912 
6913 	DBCALLED(NULL, 2);
6914 
6915 	if (drv_priv(cred_p) != 0)
6916 		return (EPERM);
6917 
6918 	minor0 = getminor(dev);
6919 	minor = AAC_SCSA_MINOR(minor0);
6920 
6921 	if (AAC_IS_SCSA_NODE(minor))
6922 		return (scsi_hba_ioctl(dev, cmd, arg, flag, cred_p, rval_p));
6923 
6924 	instance = MINOR2INST(minor0);
6925 	if (instance < AAC_MAX_ADAPTERS) {
6926 		softs = ddi_get_soft_state(aac_softstatep, instance);
6927 		return (aac_do_ioctl(softs, dev, cmd, arg, flag));
6928 	}
6929 	return (ENXIO);
6930 }
6931 
6932 /*
6933  * The IO fault service error handling callback function
6934  */
6935 /*ARGSUSED*/
6936 static int
aac_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)6937 aac_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
6938 {
6939 	/*
6940 	 * as the driver can always deal with an error in any dma or
6941 	 * access handle, we can just return the fme_status value.
6942 	 */
6943 	pci_ereport_post(dip, err, NULL);
6944 	return (err->fme_status);
6945 }
6946 
6947 /*
6948  * aac_fm_init - initialize fma capabilities and register with IO
6949  *               fault services.
6950  */
6951 static void
aac_fm_init(struct aac_softstate * softs)6952 aac_fm_init(struct aac_softstate *softs)
6953 {
6954 	/*
6955 	 * Need to change iblock to priority for new MSI intr
6956 	 */
6957 	ddi_iblock_cookie_t fm_ibc;
6958 
6959 	softs->fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, softs->devinfo_p,
6960 	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable",
6961 	    DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
6962 	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
6963 
6964 	/* Only register with IO Fault Services if we have some capability */
6965 	if (softs->fm_capabilities) {
6966 		/* Adjust access and dma attributes for FMA */
6967 		softs->reg_attr.devacc_attr_access = DDI_FLAGERR_ACC;
6968 		softs->addr_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
6969 		softs->buf_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
6970 
6971 		/*
6972 		 * Register capabilities with IO Fault Services.
6973 		 * fm_capabilities will be updated to indicate
6974 		 * capabilities actually supported (not requested.)
6975 		 */
6976 		ddi_fm_init(softs->devinfo_p, &softs->fm_capabilities, &fm_ibc);
6977 
6978 		/*
6979 		 * Initialize pci ereport capabilities if ereport
6980 		 * capable (should always be.)
6981 		 */
6982 		if (DDI_FM_EREPORT_CAP(softs->fm_capabilities) ||
6983 		    DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
6984 			pci_ereport_setup(softs->devinfo_p);
6985 		}
6986 
6987 		/*
6988 		 * Register error callback if error callback capable.
6989 		 */
6990 		if (DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
6991 			ddi_fm_handler_register(softs->devinfo_p,
6992 			    aac_fm_error_cb, (void *) softs);
6993 		}
6994 	}
6995 }
6996 
6997 /*
6998  * aac_fm_fini - Releases fma capabilities and un-registers with IO
6999  *               fault services.
7000  */
7001 static void
aac_fm_fini(struct aac_softstate * softs)7002 aac_fm_fini(struct aac_softstate *softs)
7003 {
7004 	/* Only unregister FMA capabilities if registered */
7005 	if (softs->fm_capabilities) {
7006 		/*
7007 		 * Un-register error callback if error callback capable.
7008 		 */
7009 		if (DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
7010 			ddi_fm_handler_unregister(softs->devinfo_p);
7011 		}
7012 
7013 		/*
7014 		 * Release any resources allocated by pci_ereport_setup()
7015 		 */
7016 		if (DDI_FM_EREPORT_CAP(softs->fm_capabilities) ||
7017 		    DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
7018 			pci_ereport_teardown(softs->devinfo_p);
7019 		}
7020 
7021 		/* Unregister from IO Fault Services */
7022 		ddi_fm_fini(softs->devinfo_p);
7023 
7024 		/* Adjust access and dma attributes for FMA */
7025 		softs->reg_attr.devacc_attr_access = DDI_DEFAULT_ACC;
7026 		softs->addr_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
7027 		softs->buf_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
7028 	}
7029 }
7030 
7031 int
aac_check_acc_handle(ddi_acc_handle_t handle)7032 aac_check_acc_handle(ddi_acc_handle_t handle)
7033 {
7034 	ddi_fm_error_t de;
7035 
7036 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
7037 	return (de.fme_status);
7038 }
7039 
7040 int
aac_check_dma_handle(ddi_dma_handle_t handle)7041 aac_check_dma_handle(ddi_dma_handle_t handle)
7042 {
7043 	ddi_fm_error_t de;
7044 
7045 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
7046 	return (de.fme_status);
7047 }
7048 
7049 void
aac_fm_ereport(struct aac_softstate * softs,char * detail)7050 aac_fm_ereport(struct aac_softstate *softs, char *detail)
7051 {
7052 	uint64_t ena;
7053 	char buf[FM_MAX_CLASS];
7054 
7055 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
7056 	ena = fm_ena_generate(0, FM_ENA_FMT1);
7057 	if (DDI_FM_EREPORT_CAP(softs->fm_capabilities)) {
7058 		ddi_fm_ereport_post(softs->devinfo_p, buf, ena, DDI_NOSLEEP,
7059 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERSION, NULL);
7060 	}
7061 }
7062 
7063 /*
7064  * Autoconfiguration support
7065  */
7066 static int
aac_parse_devname(char * devnm,int * tgt,int * lun)7067 aac_parse_devname(char *devnm, int *tgt, int *lun)
7068 {
7069 	char devbuf[SCSI_MAXNAMELEN];
7070 	char *addr;
7071 	char *p,  *tp, *lp;
7072 	long num;
7073 
7074 	/* Parse dev name and address */
7075 	(void) strcpy(devbuf, devnm);
7076 	addr = "";
7077 	for (p = devbuf; *p != '\0'; p++) {
7078 		if (*p == '@') {
7079 			addr = p + 1;
7080 			*p = '\0';
7081 		} else if (*p == ':') {
7082 			*p = '\0';
7083 			break;
7084 		}
7085 	}
7086 
7087 	/* Parse taget and lun */
7088 	for (p = tp = addr, lp = NULL; *p != '\0'; p++) {
7089 		if (*p == ',') {
7090 			lp = p + 1;
7091 			*p = '\0';
7092 			break;
7093 		}
7094 	}
7095 	if (tgt && tp) {
7096 		if (ddi_strtol(tp, NULL, 0x10, &num))
7097 			return (AACERR);
7098 		*tgt = (int)num;
7099 	}
7100 	if (lun && lp) {
7101 		if (ddi_strtol(lp, NULL, 0x10, &num))
7102 			return (AACERR);
7103 		*lun = (int)num;
7104 	}
7105 	return (AACOK);
7106 }
7107 
7108 static dev_info_t *
aac_find_child(struct aac_softstate * softs,uint16_t tgt,uint8_t lun)7109 aac_find_child(struct aac_softstate *softs, uint16_t tgt, uint8_t lun)
7110 {
7111 	dev_info_t *child = NULL;
7112 	char addr[SCSI_MAXNAMELEN];
7113 	char tmp[MAXNAMELEN];
7114 
7115 	if (tgt < AAC_MAX_LD) {
7116 		if (lun == 0) {
7117 			struct aac_device *dvp = &softs->containers[tgt].dev;
7118 
7119 			child = dvp->dip;
7120 		}
7121 	} else {
7122 		(void) sprintf(addr, "%x,%x", tgt, lun);
7123 		for (child = ddi_get_child(softs->devinfo_p);
7124 		    child; child = ddi_get_next_sibling(child)) {
7125 			/* We don't care about non-persistent node */
7126 			if (ndi_dev_is_persistent_node(child) == 0)
7127 				continue;
7128 
7129 			if (aac_name_node(child, tmp, MAXNAMELEN) !=
7130 			    DDI_SUCCESS)
7131 				continue;
7132 			if (strcmp(addr, tmp) == 0)
7133 				break;
7134 		}
7135 	}
7136 	return (child);
7137 }
7138 
7139 static int
aac_config_child(struct aac_softstate * softs,struct scsi_device * sd,dev_info_t ** dipp)7140 aac_config_child(struct aac_softstate *softs, struct scsi_device *sd,
7141     dev_info_t **dipp)
7142 {
7143 	char *nodename = NULL;
7144 	char **compatible = NULL;
7145 	int ncompatible = 0;
7146 	char *childname;
7147 	dev_info_t *ldip = NULL;
7148 	int tgt = sd->sd_address.a_target;
7149 	int lun = sd->sd_address.a_lun;
7150 	int dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
7151 	int rval;
7152 
7153 	DBCALLED(softs, 2);
7154 
7155 	scsi_hba_nodename_compatible_get(sd->sd_inq, NULL, dtype,
7156 	    NULL, &nodename, &compatible, &ncompatible);
7157 	if (nodename == NULL) {
7158 		AACDB_PRINT(softs, CE_WARN,
7159 		    "found no comptible driver for t%dL%d", tgt, lun);
7160 		rval = NDI_FAILURE;
7161 		goto finish;
7162 	}
7163 	childname = (softs->legacy && dtype == DTYPE_DIRECT) ? "sd" : nodename;
7164 
7165 	/* Create dev node */
7166 	rval = ndi_devi_alloc(softs->devinfo_p, childname, DEVI_SID_NODEID,
7167 	    &ldip);
7168 	if (rval == NDI_SUCCESS) {
7169 		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "target", tgt)
7170 		    != DDI_PROP_SUCCESS) {
7171 			AACDB_PRINT(softs, CE_WARN, "unable to create "
7172 			    "property for t%dL%d (target)", tgt, lun);
7173 			rval = NDI_FAILURE;
7174 			goto finish;
7175 		}
7176 		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "lun", lun)
7177 		    != DDI_PROP_SUCCESS) {
7178 			AACDB_PRINT(softs, CE_WARN, "unable to create "
7179 			    "property for t%dL%d (lun)", tgt, lun);
7180 			rval = NDI_FAILURE;
7181 			goto finish;
7182 		}
7183 		if (ndi_prop_update_string_array(DDI_DEV_T_NONE, ldip,
7184 		    "compatible", compatible, ncompatible)
7185 		    != DDI_PROP_SUCCESS) {
7186 			AACDB_PRINT(softs, CE_WARN, "unable to create "
7187 			    "property for t%dL%d (compatible)", tgt, lun);
7188 			rval = NDI_FAILURE;
7189 			goto finish;
7190 		}
7191 
7192 		rval = ndi_devi_online(ldip, NDI_ONLINE_ATTACH);
7193 		if (rval != NDI_SUCCESS) {
7194 			AACDB_PRINT(softs, CE_WARN, "unable to online t%dL%d",
7195 			    tgt, lun);
7196 			ndi_prop_remove_all(ldip);
7197 			(void) ndi_devi_free(ldip);
7198 		}
7199 	}
7200 finish:
7201 	if (dipp)
7202 		*dipp = ldip;
7203 
7204 	scsi_hba_nodename_compatible_free(nodename, compatible);
7205 	return (rval);
7206 }
7207 
7208 /*ARGSUSED*/
7209 static int
aac_probe_lun(struct aac_softstate * softs,struct scsi_device * sd)7210 aac_probe_lun(struct aac_softstate *softs, struct scsi_device *sd)
7211 {
7212 	int tgt = sd->sd_address.a_target;
7213 	int lun = sd->sd_address.a_lun;
7214 
7215 	DBCALLED(softs, 2);
7216 
7217 	if (tgt < AAC_MAX_LD) {
7218 		enum aac_cfg_event event;
7219 
7220 		if (lun == 0) {
7221 			mutex_enter(&softs->io_lock);
7222 			event = aac_probe_container(softs, tgt);
7223 			mutex_exit(&softs->io_lock);
7224 			if ((event != AAC_CFG_NULL_NOEXIST) &&
7225 			    (event != AAC_CFG_DELETE)) {
7226 				if (scsi_hba_probe(sd, NULL) ==
7227 				    SCSIPROBE_EXISTS)
7228 					return (NDI_SUCCESS);
7229 			}
7230 		}
7231 		return (NDI_FAILURE);
7232 	} else {
7233 		int dtype;
7234 		int qual; /* device qualifier */
7235 
7236 		if (scsi_hba_probe(sd, NULL) != SCSIPROBE_EXISTS)
7237 			return (NDI_FAILURE);
7238 
7239 		dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
7240 		qual = dtype >> 5;
7241 
7242 		AACDB_PRINT(softs, CE_NOTE,
7243 		    "Phys. device found: tgt %d dtype %d: %s",
7244 		    tgt, dtype, sd->sd_inq->inq_vid);
7245 
7246 		/* Only non-DASD and JBOD mode DASD are allowed exposed */
7247 		if (dtype == DTYPE_RODIRECT /* CDROM */ ||
7248 		    dtype == DTYPE_SEQUENTIAL /* TAPE */ ||
7249 		    dtype == DTYPE_ESI /* SES */) {
7250 			if (!(softs->flags & AAC_FLAGS_NONDASD))
7251 				return (NDI_FAILURE);
7252 			AACDB_PRINT(softs, CE_NOTE, "non-DASD %d found", tgt);
7253 
7254 		} else if (dtype == DTYPE_DIRECT) {
7255 			if (!(softs->flags & AAC_FLAGS_JBOD) || qual != 0)
7256 				return (NDI_FAILURE);
7257 			AACDB_PRINT(softs, CE_NOTE, "JBOD DASD %d found", tgt);
7258 		}
7259 
7260 		mutex_enter(&softs->io_lock);
7261 		softs->nondasds[AAC_PD(tgt)].dev.flags |= AAC_DFLAG_VALID;
7262 		mutex_exit(&softs->io_lock);
7263 		return (NDI_SUCCESS);
7264 	}
7265 }
7266 
7267 static int
aac_config_lun(struct aac_softstate * softs,uint16_t tgt,uint8_t lun,dev_info_t ** ldip)7268 aac_config_lun(struct aac_softstate *softs, uint16_t tgt, uint8_t lun,
7269     dev_info_t **ldip)
7270 {
7271 	struct scsi_device sd;
7272 	dev_info_t *child;
7273 	int rval;
7274 
7275 	DBCALLED(softs, 2);
7276 
7277 	if ((child = aac_find_child(softs, tgt, lun)) != NULL) {
7278 		if (ldip)
7279 			*ldip = child;
7280 		return (NDI_SUCCESS);
7281 	}
7282 
7283 	bzero(&sd, sizeof (struct scsi_device));
7284 	sd.sd_address.a_hba_tran = softs->hba_tran;
7285 	sd.sd_address.a_target = (uint16_t)tgt;
7286 	sd.sd_address.a_lun = (uint8_t)lun;
7287 	if ((rval = aac_probe_lun(softs, &sd)) == NDI_SUCCESS)
7288 		rval = aac_config_child(softs, &sd, ldip);
7289 	/* scsi_unprobe is blank now. Free buffer manually */
7290 	if (sd.sd_inq) {
7291 		kmem_free(sd.sd_inq, SUN_INQSIZE);
7292 		sd.sd_inq = (struct scsi_inquiry *)NULL;
7293 	}
7294 	return (rval);
7295 }
7296 
7297 static int
aac_config_tgt(struct aac_softstate * softs,int tgt)7298 aac_config_tgt(struct aac_softstate *softs, int tgt)
7299 {
7300 	struct scsi_address ap;
7301 	struct buf *bp = NULL;
7302 	int buf_len = AAC_SCSI_RPTLUNS_HEAD_SIZE + AAC_SCSI_RPTLUNS_ADDR_SIZE;
7303 	int list_len = 0;
7304 	int lun_total = 0;
7305 	dev_info_t *ldip;
7306 	int i;
7307 
7308 	ap.a_hba_tran = softs->hba_tran;
7309 	ap.a_target = (uint16_t)tgt;
7310 	ap.a_lun = 0;
7311 
7312 	for (i = 0; i < 2; i++) {
7313 		struct scsi_pkt *pkt;
7314 		uchar_t *cdb;
7315 		uchar_t *p;
7316 		uint32_t data;
7317 
7318 		if (bp == NULL) {
7319 			if ((bp = scsi_alloc_consistent_buf(&ap, NULL,
7320 			    buf_len, B_READ, NULL_FUNC, NULL)) == NULL)
7321 				return (AACERR);
7322 		}
7323 		if ((pkt = scsi_init_pkt(&ap, NULL, bp, CDB_GROUP5,
7324 		    sizeof (struct scsi_arq_status), 0, PKT_CONSISTENT,
7325 		    NULL, NULL)) == NULL) {
7326 			scsi_free_consistent_buf(bp);
7327 			return (AACERR);
7328 		}
7329 		cdb = pkt->pkt_cdbp;
7330 		bzero(cdb, CDB_GROUP5);
7331 		cdb[0] = SCMD_REPORT_LUNS;
7332 
7333 		/* Convert buffer len from local to LE_32 */
7334 		data = buf_len;
7335 		for (p = &cdb[9]; p > &cdb[5]; p--) {
7336 			*p = data & 0xff;
7337 			data >>= 8;
7338 		}
7339 
7340 		if (scsi_poll(pkt) < 0 ||
7341 		    ((struct scsi_status *)pkt->pkt_scbp)->sts_chk) {
7342 			scsi_destroy_pkt(pkt);
7343 			break;
7344 		}
7345 
7346 		/* Convert list_len from LE_32 to local */
7347 		for (p = (uchar_t *)bp->b_un.b_addr;
7348 		    p < (uchar_t *)bp->b_un.b_addr + 4; p++) {
7349 			data <<= 8;
7350 			data |= *p;
7351 		}
7352 		list_len = data;
7353 		if (buf_len < list_len + AAC_SCSI_RPTLUNS_HEAD_SIZE) {
7354 			scsi_free_consistent_buf(bp);
7355 			bp = NULL;
7356 			buf_len = list_len + AAC_SCSI_RPTLUNS_HEAD_SIZE;
7357 		}
7358 		scsi_destroy_pkt(pkt);
7359 	}
7360 	if (i >= 2) {
7361 		uint8_t *buf = (uint8_t *)(bp->b_un.b_addr +
7362 		    AAC_SCSI_RPTLUNS_HEAD_SIZE);
7363 
7364 		for (i = 0; i < (list_len / AAC_SCSI_RPTLUNS_ADDR_SIZE); i++) {
7365 			uint16_t lun;
7366 
7367 			/* Determine report luns addressing type */
7368 			switch (buf[0] & AAC_SCSI_RPTLUNS_ADDR_MASK) {
7369 			/*
7370 			 * Vendors in the field have been found to be
7371 			 * concatenating bus/target/lun to equal the
7372 			 * complete lun value instead of switching to
7373 			 * flat space addressing
7374 			 */
7375 			case AAC_SCSI_RPTLUNS_ADDR_PERIPHERAL:
7376 			case AAC_SCSI_RPTLUNS_ADDR_LOGICAL_UNIT:
7377 			case AAC_SCSI_RPTLUNS_ADDR_FLAT_SPACE:
7378 				lun = ((buf[0] & 0x3f) << 8) | buf[1];
7379 				if (lun > UINT8_MAX) {
7380 					AACDB_PRINT(softs, CE_WARN,
7381 					    "abnormal lun number: %d", lun);
7382 					break;
7383 				}
7384 				if (aac_config_lun(softs, tgt, lun, &ldip) ==
7385 				    NDI_SUCCESS)
7386 					lun_total++;
7387 				break;
7388 			}
7389 
7390 			buf += AAC_SCSI_RPTLUNS_ADDR_SIZE;
7391 		}
7392 	} else {
7393 		/* The target may do not support SCMD_REPORT_LUNS. */
7394 		if (aac_config_lun(softs, tgt, 0, &ldip) == NDI_SUCCESS)
7395 			lun_total++;
7396 	}
7397 	scsi_free_consistent_buf(bp);
7398 	return (lun_total);
7399 }
7400 
7401 static void
aac_devcfg(struct aac_softstate * softs,int tgt,int en)7402 aac_devcfg(struct aac_softstate *softs, int tgt, int en)
7403 {
7404 	struct aac_device *dvp;
7405 
7406 	mutex_enter(&softs->io_lock);
7407 	dvp = AAC_DEV(softs, tgt);
7408 	if (en)
7409 		dvp->flags |= AAC_DFLAG_CONFIGURING;
7410 	else
7411 		dvp->flags &= ~AAC_DFLAG_CONFIGURING;
7412 	mutex_exit(&softs->io_lock);
7413 }
7414 
7415 static int
aac_tran_bus_config(dev_info_t * parent,uint_t flags,ddi_bus_config_op_t op,void * arg,dev_info_t ** childp)7416 aac_tran_bus_config(dev_info_t *parent, uint_t flags, ddi_bus_config_op_t op,
7417     void *arg, dev_info_t **childp)
7418 {
7419 	struct aac_softstate *softs;
7420 	int rval = NDI_FAILURE;
7421 
7422 	if ((softs = ddi_get_soft_state(aac_softstatep,
7423 	    ddi_get_instance(parent))) == NULL)
7424 		return (NDI_FAILURE);
7425 
7426 	/* Commands for bus config should be blocked as the bus is quiesced */
7427 	mutex_enter(&softs->io_lock);
7428 	if (softs->state & AAC_STATE_QUIESCED) {
7429 		AACDB_PRINT(softs, CE_NOTE,
7430 		    "bus_config aborted because bus is quiesced");
7431 		mutex_exit(&softs->io_lock);
7432 		return (NDI_FAILURE);
7433 	}
7434 	mutex_exit(&softs->io_lock);
7435 
7436 	DBCALLED(softs, 1);
7437 
7438 	/* Hold the nexus across the bus_config */
7439 	ndi_devi_enter(parent);
7440 	switch (op) {
7441 	case BUS_CONFIG_ONE: {
7442 		int tgt, lun;
7443 
7444 		if (aac_parse_devname(arg, &tgt, &lun) != AACOK) {
7445 			rval = NDI_FAILURE;
7446 			break;
7447 		}
7448 		if (tgt >= AAC_MAX_LD) {
7449 			if (tgt >= AAC_MAX_DEV(softs)) {
7450 				rval = NDI_FAILURE;
7451 				break;
7452 			}
7453 		}
7454 
7455 		AAC_DEVCFG_BEGIN(softs, tgt);
7456 		rval = aac_config_lun(softs, tgt, lun, childp);
7457 		AAC_DEVCFG_END(softs, tgt);
7458 		break;
7459 	}
7460 
7461 	case BUS_CONFIG_DRIVER:
7462 	case BUS_CONFIG_ALL: {
7463 		uint32_t bus, tgt;
7464 		int index, total;
7465 
7466 		for (tgt = 0; tgt < AAC_MAX_LD; tgt++) {
7467 			AAC_DEVCFG_BEGIN(softs, tgt);
7468 			(void) aac_config_lun(softs, tgt, 0, NULL);
7469 			AAC_DEVCFG_END(softs, tgt);
7470 		}
7471 
7472 		/* Config the non-DASD devices connected to the card */
7473 		total = 0;
7474 		index = AAC_MAX_LD;
7475 		for (bus = 0; bus < softs->bus_max; bus++) {
7476 			AACDB_PRINT(softs, CE_NOTE, "bus %d:", bus);
7477 			for (tgt = 0; tgt < softs->tgt_max; tgt++, index++) {
7478 				AAC_DEVCFG_BEGIN(softs, index);
7479 				if (aac_config_tgt(softs, index))
7480 					total++;
7481 				AAC_DEVCFG_END(softs, index);
7482 			}
7483 		}
7484 		AACDB_PRINT(softs, CE_CONT,
7485 		    "?Total %d phys. device(s) found", total);
7486 		rval = NDI_SUCCESS;
7487 		break;
7488 	}
7489 	}
7490 
7491 	if (rval == NDI_SUCCESS)
7492 		rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
7493 	ndi_devi_exit(parent);
7494 	return (rval);
7495 }
7496 
7497 /*ARGSUSED*/
7498 static int
aac_handle_dr(struct aac_softstate * softs,int tgt,int lun,int event)7499 aac_handle_dr(struct aac_softstate *softs, int tgt, int lun, int event)
7500 {
7501 	struct aac_device *dvp;
7502 	dev_info_t *dip;
7503 	int valid;
7504 
7505 	DBCALLED(softs, 1);
7506 
7507 	/* Hold the nexus across the bus_config */
7508 	dvp = AAC_DEV(softs, tgt);
7509 	valid = AAC_DEV_IS_VALID(dvp);
7510 	dip = dvp->dip;
7511 	if (!(softs->state & AAC_STATE_RUN))
7512 		return (AACERR);
7513 	mutex_exit(&softs->io_lock);
7514 
7515 	switch (event) {
7516 	case AAC_CFG_ADD:
7517 	case AAC_CFG_DELETE:
7518 		/* Device onlined */
7519 		if (dip == NULL && valid) {
7520 			ndi_devi_enter(softs->devinfo_p);
7521 			(void) aac_config_lun(softs, tgt, 0, NULL);
7522 			AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d onlined",
7523 			    softs->instance, tgt, lun);
7524 			ndi_devi_exit(softs->devinfo_p);
7525 		}
7526 		/* Device offlined */
7527 		if (dip && !valid) {
7528 			mutex_enter(&softs->io_lock);
7529 			(void) aac_do_reset(softs);
7530 			mutex_exit(&softs->io_lock);
7531 
7532 			(void) ndi_devi_offline(dip, NDI_DEVI_REMOVE);
7533 			AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d offlined",
7534 			    softs->instance, tgt, lun);
7535 		}
7536 		break;
7537 	}
7538 
7539 	mutex_enter(&softs->io_lock);
7540 	return (AACOK);
7541 }
7542 
7543 #ifdef DEBUG
7544 
7545 /* -------------------------debug aid functions-------------------------- */
7546 
7547 #define	AAC_FIB_CMD_KEY_STRINGS \
7548 	TestCommandResponse, "TestCommandResponse", \
7549 	TestAdapterCommand, "TestAdapterCommand", \
7550 	LastTestCommand, "LastTestCommand", \
7551 	ReinitHostNormCommandQueue, "ReinitHostNormCommandQueue", \
7552 	ReinitHostHighCommandQueue, "ReinitHostHighCommandQueue", \
7553 	ReinitHostHighRespQueue, "ReinitHostHighRespQueue", \
7554 	ReinitHostNormRespQueue, "ReinitHostNormRespQueue", \
7555 	ReinitAdapNormCommandQueue, "ReinitAdapNormCommandQueue", \
7556 	ReinitAdapHighCommandQueue, "ReinitAdapHighCommandQueue", \
7557 	ReinitAdapHighRespQueue, "ReinitAdapHighRespQueue", \
7558 	ReinitAdapNormRespQueue, "ReinitAdapNormRespQueue", \
7559 	InterfaceShutdown, "InterfaceShutdown", \
7560 	DmaCommandFib, "DmaCommandFib", \
7561 	StartProfile, "StartProfile", \
7562 	TermProfile, "TermProfile", \
7563 	SpeedTest, "SpeedTest", \
7564 	TakeABreakPt, "TakeABreakPt", \
7565 	RequestPerfData, "RequestPerfData", \
7566 	SetInterruptDefTimer, "SetInterruptDefTimer", \
7567 	SetInterruptDefCount, "SetInterruptDefCount", \
7568 	GetInterruptDefStatus, "GetInterruptDefStatus", \
7569 	LastCommCommand, "LastCommCommand", \
7570 	NuFileSystem, "NuFileSystem", \
7571 	UFS, "UFS", \
7572 	HostFileSystem, "HostFileSystem", \
7573 	LastFileSystemCommand, "LastFileSystemCommand", \
7574 	ContainerCommand, "ContainerCommand", \
7575 	ContainerCommand64, "ContainerCommand64", \
7576 	ClusterCommand, "ClusterCommand", \
7577 	ScsiPortCommand, "ScsiPortCommand", \
7578 	ScsiPortCommandU64, "ScsiPortCommandU64", \
7579 	AifRequest, "AifRequest", \
7580 	CheckRevision, "CheckRevision", \
7581 	FsaHostShutdown, "FsaHostShutdown", \
7582 	RequestAdapterInfo, "RequestAdapterInfo", \
7583 	IsAdapterPaused, "IsAdapterPaused", \
7584 	SendHostTime, "SendHostTime", \
7585 	LastMiscCommand, "LastMiscCommand"
7586 
7587 #define	AAC_CTVM_SUBCMD_KEY_STRINGS \
7588 	VM_Null, "VM_Null", \
7589 	VM_NameServe, "VM_NameServe", \
7590 	VM_ContainerConfig, "VM_ContainerConfig", \
7591 	VM_Ioctl, "VM_Ioctl", \
7592 	VM_FilesystemIoctl, "VM_FilesystemIoctl", \
7593 	VM_CloseAll, "VM_CloseAll", \
7594 	VM_CtBlockRead, "VM_CtBlockRead", \
7595 	VM_CtBlockWrite, "VM_CtBlockWrite", \
7596 	VM_SliceBlockRead, "VM_SliceBlockRead", \
7597 	VM_SliceBlockWrite, "VM_SliceBlockWrite", \
7598 	VM_DriveBlockRead, "VM_DriveBlockRead", \
7599 	VM_DriveBlockWrite, "VM_DriveBlockWrite", \
7600 	VM_EnclosureMgt, "VM_EnclosureMgt", \
7601 	VM_Unused, "VM_Unused", \
7602 	VM_CtBlockVerify, "VM_CtBlockVerify", \
7603 	VM_CtPerf, "VM_CtPerf", \
7604 	VM_CtBlockRead64, "VM_CtBlockRead64", \
7605 	VM_CtBlockWrite64, "VM_CtBlockWrite64", \
7606 	VM_CtBlockVerify64, "VM_CtBlockVerify64", \
7607 	VM_CtHostRead64, "VM_CtHostRead64", \
7608 	VM_CtHostWrite64, "VM_CtHostWrite64", \
7609 	VM_NameServe64, "VM_NameServe64"
7610 
7611 #define	AAC_CT_SUBCMD_KEY_STRINGS \
7612 	CT_Null, "CT_Null", \
7613 	CT_GET_SLICE_COUNT, "CT_GET_SLICE_COUNT", \
7614 	CT_GET_PARTITION_COUNT, "CT_GET_PARTITION_COUNT", \
7615 	CT_GET_PARTITION_INFO, "CT_GET_PARTITION_INFO", \
7616 	CT_GET_CONTAINER_COUNT, "CT_GET_CONTAINER_COUNT", \
7617 	CT_GET_CONTAINER_INFO_OLD, "CT_GET_CONTAINER_INFO_OLD", \
7618 	CT_WRITE_MBR, "CT_WRITE_MBR", \
7619 	CT_WRITE_PARTITION, "CT_WRITE_PARTITION", \
7620 	CT_UPDATE_PARTITION, "CT_UPDATE_PARTITION", \
7621 	CT_UNLOAD_CONTAINER, "CT_UNLOAD_CONTAINER", \
7622 	CT_CONFIG_SINGLE_PRIMARY, "CT_CONFIG_SINGLE_PRIMARY", \
7623 	CT_READ_CONFIG_AGE, "CT_READ_CONFIG_AGE", \
7624 	CT_WRITE_CONFIG_AGE, "CT_WRITE_CONFIG_AGE", \
7625 	CT_READ_SERIAL_NUMBER, "CT_READ_SERIAL_NUMBER", \
7626 	CT_ZERO_PAR_ENTRY, "CT_ZERO_PAR_ENTRY", \
7627 	CT_READ_MBR, "CT_READ_MBR", \
7628 	CT_READ_PARTITION, "CT_READ_PARTITION", \
7629 	CT_DESTROY_CONTAINER, "CT_DESTROY_CONTAINER", \
7630 	CT_DESTROY2_CONTAINER, "CT_DESTROY2_CONTAINER", \
7631 	CT_SLICE_SIZE, "CT_SLICE_SIZE", \
7632 	CT_CHECK_CONFLICTS, "CT_CHECK_CONFLICTS", \
7633 	CT_MOVE_CONTAINER, "CT_MOVE_CONTAINER", \
7634 	CT_READ_LAST_DRIVE, "CT_READ_LAST_DRIVE", \
7635 	CT_WRITE_LAST_DRIVE, "CT_WRITE_LAST_DRIVE", \
7636 	CT_UNMIRROR, "CT_UNMIRROR", \
7637 	CT_MIRROR_DELAY, "CT_MIRROR_DELAY", \
7638 	CT_GEN_MIRROR, "CT_GEN_MIRROR", \
7639 	CT_GEN_MIRROR2, "CT_GEN_MIRROR2", \
7640 	CT_TEST_CONTAINER, "CT_TEST_CONTAINER", \
7641 	CT_MOVE2, "CT_MOVE2", \
7642 	CT_SPLIT, "CT_SPLIT", \
7643 	CT_SPLIT2, "CT_SPLIT2", \
7644 	CT_SPLIT_BROKEN, "CT_SPLIT_BROKEN", \
7645 	CT_SPLIT_BROKEN2, "CT_SPLIT_BROKEN2", \
7646 	CT_RECONFIG, "CT_RECONFIG", \
7647 	CT_BREAK2, "CT_BREAK2", \
7648 	CT_BREAK, "CT_BREAK", \
7649 	CT_MERGE2, "CT_MERGE2", \
7650 	CT_MERGE, "CT_MERGE", \
7651 	CT_FORCE_ERROR, "CT_FORCE_ERROR", \
7652 	CT_CLEAR_ERROR, "CT_CLEAR_ERROR", \
7653 	CT_ASSIGN_FAILOVER, "CT_ASSIGN_FAILOVER", \
7654 	CT_CLEAR_FAILOVER, "CT_CLEAR_FAILOVER", \
7655 	CT_GET_FAILOVER_DATA, "CT_GET_FAILOVER_DATA", \
7656 	CT_VOLUME_ADD, "CT_VOLUME_ADD", \
7657 	CT_VOLUME_ADD2, "CT_VOLUME_ADD2", \
7658 	CT_MIRROR_STATUS, "CT_MIRROR_STATUS", \
7659 	CT_COPY_STATUS, "CT_COPY_STATUS", \
7660 	CT_COPY, "CT_COPY", \
7661 	CT_UNLOCK_CONTAINER, "CT_UNLOCK_CONTAINER", \
7662 	CT_LOCK_CONTAINER, "CT_LOCK_CONTAINER", \
7663 	CT_MAKE_READ_ONLY, "CT_MAKE_READ_ONLY", \
7664 	CT_MAKE_READ_WRITE, "CT_MAKE_READ_WRITE", \
7665 	CT_CLEAN_DEAD, "CT_CLEAN_DEAD", \
7666 	CT_ABORT_MIRROR_COMMAND, "CT_ABORT_MIRROR_COMMAND", \
7667 	CT_SET, "CT_SET", \
7668 	CT_GET, "CT_GET", \
7669 	CT_GET_NVLOG_ENTRY, "CT_GET_NVLOG_ENTRY", \
7670 	CT_GET_DELAY, "CT_GET_DELAY", \
7671 	CT_ZERO_CONTAINER_SPACE, "CT_ZERO_CONTAINER_SPACE", \
7672 	CT_GET_ZERO_STATUS, "CT_GET_ZERO_STATUS", \
7673 	CT_SCRUB, "CT_SCRUB", \
7674 	CT_GET_SCRUB_STATUS, "CT_GET_SCRUB_STATUS", \
7675 	CT_GET_SLICE_INFO, "CT_GET_SLICE_INFO", \
7676 	CT_GET_SCSI_METHOD, "CT_GET_SCSI_METHOD", \
7677 	CT_PAUSE_IO, "CT_PAUSE_IO", \
7678 	CT_RELEASE_IO, "CT_RELEASE_IO", \
7679 	CT_SCRUB2, "CT_SCRUB2", \
7680 	CT_MCHECK, "CT_MCHECK", \
7681 	CT_CORRUPT, "CT_CORRUPT", \
7682 	CT_GET_TASK_COUNT, "CT_GET_TASK_COUNT", \
7683 	CT_PROMOTE, "CT_PROMOTE", \
7684 	CT_SET_DEAD, "CT_SET_DEAD", \
7685 	CT_CONTAINER_OPTIONS, "CT_CONTAINER_OPTIONS", \
7686 	CT_GET_NV_PARAM, "CT_GET_NV_PARAM", \
7687 	CT_GET_PARAM, "CT_GET_PARAM", \
7688 	CT_NV_PARAM_SIZE, "CT_NV_PARAM_SIZE", \
7689 	CT_COMMON_PARAM_SIZE, "CT_COMMON_PARAM_SIZE", \
7690 	CT_PLATFORM_PARAM_SIZE, "CT_PLATFORM_PARAM_SIZE", \
7691 	CT_SET_NV_PARAM, "CT_SET_NV_PARAM", \
7692 	CT_ABORT_SCRUB, "CT_ABORT_SCRUB", \
7693 	CT_GET_SCRUB_ERROR, "CT_GET_SCRUB_ERROR", \
7694 	CT_LABEL_CONTAINER, "CT_LABEL_CONTAINER", \
7695 	CT_CONTINUE_DATA, "CT_CONTINUE_DATA", \
7696 	CT_STOP_DATA, "CT_STOP_DATA", \
7697 	CT_GET_PARTITION_TABLE, "CT_GET_PARTITION_TABLE", \
7698 	CT_GET_DISK_PARTITIONS, "CT_GET_DISK_PARTITIONS", \
7699 	CT_GET_MISC_STATUS, "CT_GET_MISC_STATUS", \
7700 	CT_GET_CONTAINER_PERF_INFO, "CT_GET_CONTAINER_PERF_INFO", \
7701 	CT_GET_TIME, "CT_GET_TIME", \
7702 	CT_READ_DATA, "CT_READ_DATA", \
7703 	CT_CTR, "CT_CTR", \
7704 	CT_CTL, "CT_CTL", \
7705 	CT_DRAINIO, "CT_DRAINIO", \
7706 	CT_RELEASEIO, "CT_RELEASEIO", \
7707 	CT_GET_NVRAM, "CT_GET_NVRAM", \
7708 	CT_GET_MEMORY, "CT_GET_MEMORY", \
7709 	CT_PRINT_CT_LOG, "CT_PRINT_CT_LOG", \
7710 	CT_ADD_LEVEL, "CT_ADD_LEVEL", \
7711 	CT_NV_ZERO, "CT_NV_ZERO", \
7712 	CT_READ_SIGNATURE, "CT_READ_SIGNATURE", \
7713 	CT_THROTTLE_ON, "CT_THROTTLE_ON", \
7714 	CT_THROTTLE_OFF, "CT_THROTTLE_OFF", \
7715 	CT_GET_THROTTLE_STATS, "CT_GET_THROTTLE_STATS", \
7716 	CT_MAKE_SNAPSHOT, "CT_MAKE_SNAPSHOT", \
7717 	CT_REMOVE_SNAPSHOT, "CT_REMOVE_SNAPSHOT", \
7718 	CT_WRITE_USER_FLAGS, "CT_WRITE_USER_FLAGS", \
7719 	CT_READ_USER_FLAGS, "CT_READ_USER_FLAGS", \
7720 	CT_MONITOR, "CT_MONITOR", \
7721 	CT_GEN_MORPH, "CT_GEN_MORPH", \
7722 	CT_GET_SNAPSHOT_INFO, "CT_GET_SNAPSHOT_INFO", \
7723 	CT_CACHE_SET, "CT_CACHE_SET", \
7724 	CT_CACHE_STAT, "CT_CACHE_STAT", \
7725 	CT_TRACE_START, "CT_TRACE_START", \
7726 	CT_TRACE_STOP, "CT_TRACE_STOP", \
7727 	CT_TRACE_ENABLE, "CT_TRACE_ENABLE", \
7728 	CT_TRACE_DISABLE, "CT_TRACE_DISABLE", \
7729 	CT_FORCE_CORE_DUMP, "CT_FORCE_CORE_DUMP", \
7730 	CT_SET_SERIAL_NUMBER, "CT_SET_SERIAL_NUMBER", \
7731 	CT_RESET_SERIAL_NUMBER, "CT_RESET_SERIAL_NUMBER", \
7732 	CT_ENABLE_RAID5, "CT_ENABLE_RAID5", \
7733 	CT_CLEAR_VALID_DUMP_FLAG, "CT_CLEAR_VALID_DUMP_FLAG", \
7734 	CT_GET_MEM_STATS, "CT_GET_MEM_STATS", \
7735 	CT_GET_CORE_SIZE, "CT_GET_CORE_SIZE", \
7736 	CT_CREATE_CONTAINER_OLD, "CT_CREATE_CONTAINER_OLD", \
7737 	CT_STOP_DUMPS, "CT_STOP_DUMPS", \
7738 	CT_PANIC_ON_TAKE_A_BREAK, "CT_PANIC_ON_TAKE_A_BREAK", \
7739 	CT_GET_CACHE_STATS, "CT_GET_CACHE_STATS", \
7740 	CT_MOVE_PARTITION, "CT_MOVE_PARTITION", \
7741 	CT_FLUSH_CACHE, "CT_FLUSH_CACHE", \
7742 	CT_READ_NAME, "CT_READ_NAME", \
7743 	CT_WRITE_NAME, "CT_WRITE_NAME", \
7744 	CT_TOSS_CACHE, "CT_TOSS_CACHE", \
7745 	CT_LOCK_DRAINIO, "CT_LOCK_DRAINIO", \
7746 	CT_CONTAINER_OFFLINE, "CT_CONTAINER_OFFLINE", \
7747 	CT_SET_CACHE_SIZE, "CT_SET_CACHE_SIZE", \
7748 	CT_CLEAN_SHUTDOWN_STATUS, "CT_CLEAN_SHUTDOWN_STATUS", \
7749 	CT_CLEAR_DISKLOG_ON_DISK, "CT_CLEAR_DISKLOG_ON_DISK", \
7750 	CT_CLEAR_ALL_DISKLOG, "CT_CLEAR_ALL_DISKLOG", \
7751 	CT_CACHE_FAVOR, "CT_CACHE_FAVOR", \
7752 	CT_READ_PASSTHRU_MBR, "CT_READ_PASSTHRU_MBR", \
7753 	CT_SCRUB_NOFIX, "CT_SCRUB_NOFIX", \
7754 	CT_SCRUB2_NOFIX, "CT_SCRUB2_NOFIX", \
7755 	CT_FLUSH, "CT_FLUSH", \
7756 	CT_REBUILD, "CT_REBUILD", \
7757 	CT_FLUSH_CONTAINER, "CT_FLUSH_CONTAINER", \
7758 	CT_RESTART, "CT_RESTART", \
7759 	CT_GET_CONFIG_STATUS, "CT_GET_CONFIG_STATUS", \
7760 	CT_TRACE_FLAG, "CT_TRACE_FLAG", \
7761 	CT_RESTART_MORPH, "CT_RESTART_MORPH", \
7762 	CT_GET_TRACE_INFO, "CT_GET_TRACE_INFO", \
7763 	CT_GET_TRACE_ITEM, "CT_GET_TRACE_ITEM", \
7764 	CT_COMMIT_CONFIG, "CT_COMMIT_CONFIG", \
7765 	CT_CONTAINER_EXISTS, "CT_CONTAINER_EXISTS", \
7766 	CT_GET_SLICE_FROM_DEVT, "CT_GET_SLICE_FROM_DEVT", \
7767 	CT_OPEN_READ_WRITE, "CT_OPEN_READ_WRITE", \
7768 	CT_WRITE_MEMORY_BLOCK, "CT_WRITE_MEMORY_BLOCK", \
7769 	CT_GET_CACHE_PARAMS, "CT_GET_CACHE_PARAMS", \
7770 	CT_CRAZY_CACHE, "CT_CRAZY_CACHE", \
7771 	CT_GET_PROFILE_STRUCT, "CT_GET_PROFILE_STRUCT", \
7772 	CT_SET_IO_TRACE_FLAG, "CT_SET_IO_TRACE_FLAG", \
7773 	CT_GET_IO_TRACE_STRUCT, "CT_GET_IO_TRACE_STRUCT", \
7774 	CT_CID_TO_64BITS_UID, "CT_CID_TO_64BITS_UID", \
7775 	CT_64BITS_UID_TO_CID, "CT_64BITS_UID_TO_CID", \
7776 	CT_PAR_TO_64BITS_UID, "CT_PAR_TO_64BITS_UID", \
7777 	CT_CID_TO_32BITS_UID, "CT_CID_TO_32BITS_UID", \
7778 	CT_32BITS_UID_TO_CID, "CT_32BITS_UID_TO_CID", \
7779 	CT_PAR_TO_32BITS_UID, "CT_PAR_TO_32BITS_UID", \
7780 	CT_SET_FAILOVER_OPTION, "CT_SET_FAILOVER_OPTION", \
7781 	CT_GET_FAILOVER_OPTION, "CT_GET_FAILOVER_OPTION", \
7782 	CT_STRIPE_ADD2, "CT_STRIPE_ADD2", \
7783 	CT_CREATE_VOLUME_SET, "CT_CREATE_VOLUME_SET", \
7784 	CT_CREATE_STRIPE_SET, "CT_CREATE_STRIPE_SET", \
7785 	CT_VERIFY_CONTAINER, "CT_VERIFY_CONTAINER", \
7786 	CT_IS_CONTAINER_DEAD, "CT_IS_CONTAINER_DEAD", \
7787 	CT_GET_CONTAINER_OPTION, "CT_GET_CONTAINER_OPTION", \
7788 	CT_GET_SNAPSHOT_UNUSED_STRUCT, "CT_GET_SNAPSHOT_UNUSED_STRUCT", \
7789 	CT_CLEAR_SNAPSHOT_UNUSED_STRUCT, "CT_CLEAR_SNAPSHOT_UNUSED_STRUCT", \
7790 	CT_GET_CONTAINER_INFO, "CT_GET_CONTAINER_INFO", \
7791 	CT_CREATE_CONTAINER, "CT_CREATE_CONTAINER", \
7792 	CT_CHANGE_CREATIONINFO, "CT_CHANGE_CREATIONINFO", \
7793 	CT_CHECK_CONFLICT_UID, "CT_CHECK_CONFLICT_UID", \
7794 	CT_CONTAINER_UID_CHECK, "CT_CONTAINER_UID_CHECK", \
7795 	CT_IS_CONTAINER_MEATADATA_STANDARD, \
7796 	    "CT_IS_CONTAINER_MEATADATA_STANDARD", \
7797 	CT_IS_SLICE_METADATA_STANDARD, "CT_IS_SLICE_METADATA_STANDARD", \
7798 	CT_GET_IMPORT_COUNT, "CT_GET_IMPORT_COUNT", \
7799 	CT_CANCEL_ALL_IMPORTS, "CT_CANCEL_ALL_IMPORTS", \
7800 	CT_GET_IMPORT_INFO, "CT_GET_IMPORT_INFO", \
7801 	CT_IMPORT_ARRAY, "CT_IMPORT_ARRAY", \
7802 	CT_GET_LOG_SIZE, "CT_GET_LOG_SIZE", \
7803 	CT_ALARM_GET_STATE, "CT_ALARM_GET_STATE", \
7804 	CT_ALARM_SET_STATE, "CT_ALARM_SET_STATE", \
7805 	CT_ALARM_ON_OFF, "CT_ALARM_ON_OFF", \
7806 	CT_GET_EE_OEM_ID, "CT_GET_EE_OEM_ID", \
7807 	CT_GET_PPI_HEADERS, "CT_GET_PPI_HEADERS", \
7808 	CT_GET_PPI_DATA, "CT_GET_PPI_DATA", \
7809 	CT_GET_PPI_ENTRIES, "CT_GET_PPI_ENTRIES", \
7810 	CT_DELETE_PPI_BUNDLE, "CT_DELETE_PPI_BUNDLE", \
7811 	CT_GET_PARTITION_TABLE_2, "CT_GET_PARTITION_TABLE_2", \
7812 	CT_GET_PARTITION_INFO_2, "CT_GET_PARTITION_INFO_2", \
7813 	CT_GET_DISK_PARTITIONS_2, "CT_GET_DISK_PARTITIONS_2", \
7814 	CT_QUIESCE_ADAPTER, "CT_QUIESCE_ADAPTER", \
7815 	CT_CLEAR_PPI_TABLE, "CT_CLEAR_PPI_TABLE"
7816 
7817 #define	AAC_CL_SUBCMD_KEY_STRINGS \
7818 	CL_NULL, "CL_NULL", \
7819 	DS_INIT, "DS_INIT", \
7820 	DS_RESCAN, "DS_RESCAN", \
7821 	DS_CREATE, "DS_CREATE", \
7822 	DS_DELETE, "DS_DELETE", \
7823 	DS_ADD_DISK, "DS_ADD_DISK", \
7824 	DS_REMOVE_DISK, "DS_REMOVE_DISK", \
7825 	DS_MOVE_DISK, "DS_MOVE_DISK", \
7826 	DS_TAKE_OWNERSHIP, "DS_TAKE_OWNERSHIP", \
7827 	DS_RELEASE_OWNERSHIP, "DS_RELEASE_OWNERSHIP", \
7828 	DS_FORCE_OWNERSHIP, "DS_FORCE_OWNERSHIP", \
7829 	DS_GET_DISK_SET_PARAM, "DS_GET_DISK_SET_PARAM", \
7830 	DS_GET_DRIVE_PARAM, "DS_GET_DRIVE_PARAM", \
7831 	DS_GET_SLICE_PARAM, "DS_GET_SLICE_PARAM", \
7832 	DS_GET_DISK_SETS, "DS_GET_DISK_SETS", \
7833 	DS_GET_DRIVES, "DS_GET_DRIVES", \
7834 	DS_SET_DISK_SET_PARAM, "DS_SET_DISK_SET_PARAM", \
7835 	DS_ONLINE, "DS_ONLINE", \
7836 	DS_OFFLINE, "DS_OFFLINE", \
7837 	DS_ONLINE_CONTAINERS, "DS_ONLINE_CONTAINERS", \
7838 	DS_FSAPRINT, "DS_FSAPRINT", \
7839 	CL_CFG_SET_HOST_IDS, "CL_CFG_SET_HOST_IDS", \
7840 	CL_CFG_SET_PARTNER_HOST_IDS, "CL_CFG_SET_PARTNER_HOST_IDS", \
7841 	CL_CFG_GET_CLUSTER_CONFIG, "CL_CFG_GET_CLUSTER_CONFIG", \
7842 	CC_CLI_CLEAR_MESSAGE_BUFFER, "CC_CLI_CLEAR_MESSAGE_BUFFER", \
7843 	CC_SRV_CLEAR_MESSAGE_BUFFER, "CC_SRV_CLEAR_MESSAGE_BUFFER", \
7844 	CC_CLI_SHOW_MESSAGE_BUFFER, "CC_CLI_SHOW_MESSAGE_BUFFER", \
7845 	CC_SRV_SHOW_MESSAGE_BUFFER, "CC_SRV_SHOW_MESSAGE_BUFFER", \
7846 	CC_CLI_SEND_MESSAGE, "CC_CLI_SEND_MESSAGE", \
7847 	CC_SRV_SEND_MESSAGE, "CC_SRV_SEND_MESSAGE", \
7848 	CC_CLI_GET_MESSAGE, "CC_CLI_GET_MESSAGE", \
7849 	CC_SRV_GET_MESSAGE, "CC_SRV_GET_MESSAGE", \
7850 	CC_SEND_TEST_MESSAGE, "CC_SEND_TEST_MESSAGE", \
7851 	CC_GET_BUSINFO, "CC_GET_BUSINFO", \
7852 	CC_GET_PORTINFO, "CC_GET_PORTINFO", \
7853 	CC_GET_NAMEINFO, "CC_GET_NAMEINFO", \
7854 	CC_GET_CONFIGINFO, "CC_GET_CONFIGINFO", \
7855 	CQ_QUORUM_OP, "CQ_QUORUM_OP"
7856 
7857 #define	AAC_AIF_SUBCMD_KEY_STRINGS \
7858 	AifCmdEventNotify, "AifCmdEventNotify", \
7859 	AifCmdJobProgress, "AifCmdJobProgress", \
7860 	AifCmdAPIReport, "AifCmdAPIReport", \
7861 	AifCmdDriverNotify, "AifCmdDriverNotify", \
7862 	AifReqJobList, "AifReqJobList", \
7863 	AifReqJobsForCtr, "AifReqJobsForCtr", \
7864 	AifReqJobsForScsi, "AifReqJobsForScsi", \
7865 	AifReqJobReport, "AifReqJobReport", \
7866 	AifReqTerminateJob, "AifReqTerminateJob", \
7867 	AifReqSuspendJob, "AifReqSuspendJob", \
7868 	AifReqResumeJob, "AifReqResumeJob", \
7869 	AifReqSendAPIReport, "AifReqSendAPIReport", \
7870 	AifReqAPIJobStart, "AifReqAPIJobStart", \
7871 	AifReqAPIJobUpdate, "AifReqAPIJobUpdate", \
7872 	AifReqAPIJobFinish, "AifReqAPIJobFinish"
7873 
7874 #define	AAC_IOCTL_SUBCMD_KEY_STRINGS \
7875 	Reserved_IOCTL, "Reserved_IOCTL", \
7876 	GetDeviceHandle, "GetDeviceHandle", \
7877 	BusTargetLun_to_DeviceHandle, "BusTargetLun_to_DeviceHandle", \
7878 	DeviceHandle_to_BusTargetLun, "DeviceHandle_to_BusTargetLun", \
7879 	RescanBus, "RescanBus", \
7880 	GetDeviceProbeInfo, "GetDeviceProbeInfo", \
7881 	GetDeviceCapacity, "GetDeviceCapacity", \
7882 	GetContainerProbeInfo, "GetContainerProbeInfo", \
7883 	GetRequestedMemorySize, "GetRequestedMemorySize", \
7884 	GetBusInfo, "GetBusInfo", \
7885 	GetVendorSpecific, "GetVendorSpecific", \
7886 	EnhancedGetDeviceProbeInfo, "EnhancedGetDeviceProbeInfo", \
7887 	EnhancedGetBusInfo, "EnhancedGetBusInfo", \
7888 	SetupExtendedCounters, "SetupExtendedCounters", \
7889 	GetPerformanceCounters, "GetPerformanceCounters", \
7890 	ResetPerformanceCounters, "ResetPerformanceCounters", \
7891 	ReadModePage, "ReadModePage", \
7892 	WriteModePage, "WriteModePage", \
7893 	ReadDriveParameter, "ReadDriveParameter", \
7894 	WriteDriveParameter, "WriteDriveParameter", \
7895 	ResetAdapter, "ResetAdapter", \
7896 	ResetBus, "ResetBus", \
7897 	ResetBusDevice, "ResetBusDevice", \
7898 	ExecuteSrb, "ExecuteSrb", \
7899 	Create_IO_Task, "Create_IO_Task", \
7900 	Delete_IO_Task, "Delete_IO_Task", \
7901 	Get_IO_Task_Info, "Get_IO_Task_Info", \
7902 	Check_Task_Progress, "Check_Task_Progress", \
7903 	InjectError, "InjectError", \
7904 	GetDeviceDefectCounts, "GetDeviceDefectCounts", \
7905 	GetDeviceDefectInfo, "GetDeviceDefectInfo", \
7906 	GetDeviceStatus, "GetDeviceStatus", \
7907 	ClearDeviceStatus, "ClearDeviceStatus", \
7908 	DiskSpinControl, "DiskSpinControl", \
7909 	DiskSmartControl, "DiskSmartControl", \
7910 	WriteSame, "WriteSame", \
7911 	ReadWriteLong, "ReadWriteLong", \
7912 	FormatUnit, "FormatUnit", \
7913 	TargetDeviceControl, "TargetDeviceControl", \
7914 	TargetChannelControl, "TargetChannelControl", \
7915 	FlashNewCode, "FlashNewCode", \
7916 	DiskCheck, "DiskCheck", \
7917 	RequestSense, "RequestSense", \
7918 	DiskPERControl, "DiskPERControl", \
7919 	Read10, "Read10", \
7920 	Write10, "Write10"
7921 
7922 #define	AAC_AIFEN_KEY_STRINGS \
7923 	AifEnGeneric, "Generic", \
7924 	AifEnTaskComplete, "TaskComplete", \
7925 	AifEnConfigChange, "Config change", \
7926 	AifEnContainerChange, "Container change", \
7927 	AifEnDeviceFailure, "device failed", \
7928 	AifEnMirrorFailover, "Mirror failover", \
7929 	AifEnContainerEvent, "container event", \
7930 	AifEnFileSystemChange, "File system changed", \
7931 	AifEnConfigPause, "Container pause event", \
7932 	AifEnConfigResume, "Container resume event", \
7933 	AifEnFailoverChange, "Failover space assignment changed", \
7934 	AifEnRAID5RebuildDone, "RAID5 rebuild finished", \
7935 	AifEnEnclosureManagement, "Enclosure management event", \
7936 	AifEnBatteryEvent, "battery event", \
7937 	AifEnAddContainer, "Add container", \
7938 	AifEnDeleteContainer, "Delete container", \
7939 	AifEnSMARTEvent, "SMART Event", \
7940 	AifEnBatteryNeedsRecond, "battery needs reconditioning", \
7941 	AifEnClusterEvent, "cluster event", \
7942 	AifEnDiskSetEvent, "disk set event occured", \
7943 	AifDenMorphComplete, "morph operation completed", \
7944 	AifDenVolumeExtendComplete, "VolumeExtendComplete"
7945 
7946 struct aac_key_strings {
7947 	int key;
7948 	char *message;
7949 };
7950 
7951 extern struct scsi_key_strings scsi_cmds[];
7952 
7953 static struct aac_key_strings aac_fib_cmds[] = {
7954 	AAC_FIB_CMD_KEY_STRINGS,
7955 	-1,			NULL
7956 };
7957 
7958 static struct aac_key_strings aac_ctvm_subcmds[] = {
7959 	AAC_CTVM_SUBCMD_KEY_STRINGS,
7960 	-1,			NULL
7961 };
7962 
7963 static struct aac_key_strings aac_ct_subcmds[] = {
7964 	AAC_CT_SUBCMD_KEY_STRINGS,
7965 	-1,			NULL
7966 };
7967 
7968 static struct aac_key_strings aac_cl_subcmds[] = {
7969 	AAC_CL_SUBCMD_KEY_STRINGS,
7970 	-1,			NULL
7971 };
7972 
7973 static struct aac_key_strings aac_aif_subcmds[] = {
7974 	AAC_AIF_SUBCMD_KEY_STRINGS,
7975 	-1,			NULL
7976 };
7977 
7978 static struct aac_key_strings aac_ioctl_subcmds[] = {
7979 	AAC_IOCTL_SUBCMD_KEY_STRINGS,
7980 	-1,			NULL
7981 };
7982 
7983 static struct aac_key_strings aac_aifens[] = {
7984 	AAC_AIFEN_KEY_STRINGS,
7985 	-1,			NULL
7986 };
7987 
7988 /*
7989  * The following function comes from Adaptec:
7990  *
7991  * Get the firmware print buffer parameters from the firmware,
7992  * if the command was successful map in the address.
7993  */
7994 static int
aac_get_fw_debug_buffer(struct aac_softstate * softs)7995 aac_get_fw_debug_buffer(struct aac_softstate *softs)
7996 {
7997 	if (aac_sync_mbcommand(softs, AAC_MONKER_GETDRVPROP,
7998 	    0, 0, 0, 0, NULL) == AACOK) {
7999 		uint32_t mondrv_buf_paddrl = AAC_MAILBOX_GET(softs, 1);
8000 		uint32_t mondrv_buf_paddrh = AAC_MAILBOX_GET(softs, 2);
8001 		uint32_t mondrv_buf_size = AAC_MAILBOX_GET(softs, 3);
8002 		uint32_t mondrv_hdr_size = AAC_MAILBOX_GET(softs, 4);
8003 
8004 		if (mondrv_buf_size) {
8005 			uint32_t offset = mondrv_buf_paddrl - \
8006 			    softs->pci_mem_base_paddr;
8007 
8008 			/*
8009 			 * See if the address is already mapped in, and
8010 			 * if so set it up from the base address
8011 			 */
8012 			if ((mondrv_buf_paddrh == 0) &&
8013 			    (offset + mondrv_buf_size < softs->map_size)) {
8014 				mutex_enter(&aac_prt_mutex);
8015 				softs->debug_buf_offset = offset;
8016 				softs->debug_header_size = mondrv_hdr_size;
8017 				softs->debug_buf_size = mondrv_buf_size;
8018 				softs->debug_fw_flags = 0;
8019 				softs->debug_flags &= ~AACDB_FLAGS_FW_PRINT;
8020 				mutex_exit(&aac_prt_mutex);
8021 
8022 				return (AACOK);
8023 			}
8024 		}
8025 	}
8026 	return (AACERR);
8027 }
8028 
8029 int
aac_dbflag_on(struct aac_softstate * softs,int flag)8030 aac_dbflag_on(struct aac_softstate *softs, int flag)
8031 {
8032 	int debug_flags = softs ? softs->debug_flags : aac_debug_flags;
8033 
8034 	return ((debug_flags & (AACDB_FLAGS_FW_PRINT | \
8035 	    AACDB_FLAGS_KERNEL_PRINT)) && (debug_flags & flag));
8036 }
8037 
8038 static void
aac_cmn_err(struct aac_softstate * softs,uint_t lev,char sl,int noheader)8039 aac_cmn_err(struct aac_softstate *softs, uint_t lev, char sl, int noheader)
8040 {
8041 	if (noheader) {
8042 		if (sl) {
8043 			aac_fmt[0] = sl;
8044 			cmn_err(lev, aac_fmt, aac_prt_buf);
8045 		} else {
8046 			cmn_err(lev, &aac_fmt[1], aac_prt_buf);
8047 		}
8048 	} else {
8049 		if (sl) {
8050 			aac_fmt_header[0] = sl;
8051 			cmn_err(lev, aac_fmt_header,
8052 			    softs->vendor_name, softs->instance,
8053 			    aac_prt_buf);
8054 		} else {
8055 			cmn_err(lev, &aac_fmt_header[1],
8056 			    softs->vendor_name, softs->instance,
8057 			    aac_prt_buf);
8058 		}
8059 	}
8060 }
8061 
8062 /*
8063  * The following function comes from Adaptec:
8064  *
8065  * Format and print out the data passed in to UART or console
8066  * as specified by debug flags.
8067  */
8068 void
aac_printf(struct aac_softstate * softs,uint_t lev,const char * fmt,...)8069 aac_printf(struct aac_softstate *softs, uint_t lev, const char *fmt, ...)
8070 {
8071 	va_list args;
8072 	char sl; /* system log character */
8073 
8074 	mutex_enter(&aac_prt_mutex);
8075 	/* Set up parameters and call sprintf function to format the data */
8076 	if (strchr("^!?", fmt[0]) == NULL) {
8077 		sl = 0;
8078 	} else {
8079 		sl = fmt[0];
8080 		fmt++;
8081 	}
8082 	va_start(args, fmt);
8083 	(void) vsprintf(aac_prt_buf, fmt, args);
8084 	va_end(args);
8085 
8086 	/* Make sure the softs structure has been passed in for this section */
8087 	if (softs) {
8088 		if ((softs->debug_flags & AACDB_FLAGS_FW_PRINT) &&
8089 		    /* If we are set up for a Firmware print */
8090 		    (softs->debug_buf_size)) {
8091 			uint32_t count, i;
8092 
8093 			/* Make sure the string size is within boundaries */
8094 			count = strlen(aac_prt_buf);
8095 			if (count > softs->debug_buf_size)
8096 				count = (uint16_t)softs->debug_buf_size;
8097 
8098 			/*
8099 			 * Wait for no more than AAC_PRINT_TIMEOUT for the
8100 			 * previous message length to clear (the handshake).
8101 			 */
8102 			for (i = 0; i < AAC_PRINT_TIMEOUT; i++) {
8103 				if (!PCI_MEM_GET32(softs,
8104 				    softs->debug_buf_offset + \
8105 				    AAC_FW_DBG_STRLEN_OFFSET))
8106 					break;
8107 
8108 				drv_usecwait(1000);
8109 			}
8110 
8111 			/*
8112 			 * If the length is clear, copy over the message, the
8113 			 * flags, and the length. Make sure the length is the
8114 			 * last because that is the signal for the Firmware to
8115 			 * pick it up.
8116 			 */
8117 			if (!PCI_MEM_GET32(softs, softs->debug_buf_offset + \
8118 			    AAC_FW_DBG_STRLEN_OFFSET)) {
8119 				PCI_MEM_REP_PUT8(softs,
8120 				    softs->debug_buf_offset + \
8121 				    softs->debug_header_size,
8122 				    aac_prt_buf, count);
8123 				PCI_MEM_PUT32(softs,
8124 				    softs->debug_buf_offset + \
8125 				    AAC_FW_DBG_FLAGS_OFFSET,
8126 				    softs->debug_fw_flags);
8127 				PCI_MEM_PUT32(softs,
8128 				    softs->debug_buf_offset + \
8129 				    AAC_FW_DBG_STRLEN_OFFSET, count);
8130 			} else {
8131 				cmn_err(CE_WARN, "UART output fail");
8132 				softs->debug_flags &= ~AACDB_FLAGS_FW_PRINT;
8133 			}
8134 		}
8135 
8136 		/*
8137 		 * If the Kernel Debug Print flag is set, send it off
8138 		 * to the Kernel Debugger
8139 		 */
8140 		if (softs->debug_flags & AACDB_FLAGS_KERNEL_PRINT)
8141 			aac_cmn_err(softs, lev, sl,
8142 			    (softs->debug_flags & AACDB_FLAGS_NO_HEADERS));
8143 	} else {
8144 		/* Driver not initialized yet, no firmware or header output */
8145 		if (aac_debug_flags & AACDB_FLAGS_KERNEL_PRINT)
8146 			aac_cmn_err(softs, lev, sl, 1);
8147 	}
8148 	mutex_exit(&aac_prt_mutex);
8149 }
8150 
8151 /*
8152  * Translate command number to description string
8153  */
8154 static char *
aac_cmd_name(int cmd,struct aac_key_strings * cmdlist)8155 aac_cmd_name(int cmd, struct aac_key_strings *cmdlist)
8156 {
8157 	int i;
8158 
8159 	for (i = 0; cmdlist[i].key != -1; i++) {
8160 		if (cmd == cmdlist[i].key)
8161 			return (cmdlist[i].message);
8162 	}
8163 	return (NULL);
8164 }
8165 
8166 static void
aac_print_scmd(struct aac_softstate * softs,struct aac_cmd * acp)8167 aac_print_scmd(struct aac_softstate *softs, struct aac_cmd *acp)
8168 {
8169 	struct scsi_pkt *pkt = acp->pkt;
8170 	struct scsi_address *ap = &pkt->pkt_address;
8171 	int is_pd = 0;
8172 	int ctl = ddi_get_instance(softs->devinfo_p);
8173 	int tgt = ap->a_target;
8174 	int lun = ap->a_lun;
8175 	union scsi_cdb *cdbp = (void *)pkt->pkt_cdbp;
8176 	uchar_t cmd = cdbp->scc_cmd;
8177 	char *desc;
8178 
8179 	if (tgt >= AAC_MAX_LD) {
8180 		is_pd = 1;
8181 		ctl = ((struct aac_nondasd *)acp->dvp)->bus;
8182 		tgt = ((struct aac_nondasd *)acp->dvp)->tid;
8183 		lun = 0;
8184 	}
8185 
8186 	if ((desc = aac_cmd_name(cmd,
8187 	    (struct aac_key_strings *)scsi_cmds)) == NULL) {
8188 		aac_printf(softs, CE_NOTE,
8189 		    "SCMD> Unknown(0x%2x) --> c%dt%dL%d %s",
8190 		    cmd, ctl, tgt, lun, is_pd ? "(pd)" : "");
8191 		return;
8192 	}
8193 
8194 	switch (cmd) {
8195 	case SCMD_READ:
8196 	case SCMD_WRITE:
8197 		aac_printf(softs, CE_NOTE,
8198 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
8199 		    desc, GETG0ADDR(cdbp), GETG0COUNT(cdbp),
8200 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
8201 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8202 		break;
8203 	case SCMD_READ_G1:
8204 	case SCMD_WRITE_G1:
8205 		aac_printf(softs, CE_NOTE,
8206 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
8207 		    desc, GETG1ADDR(cdbp), GETG1COUNT(cdbp),
8208 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
8209 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8210 		break;
8211 	case SCMD_READ_G4:
8212 	case SCMD_WRITE_G4:
8213 		aac_printf(softs, CE_NOTE,
8214 		    "SCMD> %s 0x%x.%08x[%d] %s --> c%dt%dL%d %s",
8215 		    desc, GETG4ADDR(cdbp), GETG4ADDRTL(cdbp),
8216 		    GETG4COUNT(cdbp),
8217 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
8218 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8219 		break;
8220 	case SCMD_READ_G5:
8221 	case SCMD_WRITE_G5:
8222 		aac_printf(softs, CE_NOTE,
8223 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
8224 		    desc, GETG5ADDR(cdbp), GETG5COUNT(cdbp),
8225 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
8226 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8227 		break;
8228 	default:
8229 		aac_printf(softs, CE_NOTE, "SCMD> %s --> c%dt%dL%d %s",
8230 		    desc, ctl, tgt, lun, is_pd ? "(pd)" : "");
8231 	}
8232 }
8233 
8234 void
aac_print_fib(struct aac_softstate * softs,struct aac_slot * slotp)8235 aac_print_fib(struct aac_softstate *softs, struct aac_slot *slotp)
8236 {
8237 	struct aac_cmd *acp = slotp->acp;
8238 	struct aac_fib *fibp = slotp->fibp;
8239 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
8240 	uint16_t fib_size;
8241 	uint32_t fib_cmd, sub_cmd;
8242 	char *cmdstr, *subcmdstr;
8243 	char *caller;
8244 	int i;
8245 
8246 	if (acp) {
8247 		if (!(softs->debug_fib_flags & acp->fib_flags))
8248 			return;
8249 		if (acp->fib_flags & AACDB_FLAGS_FIB_SCMD)
8250 			caller = "SCMD";
8251 		else if (acp->fib_flags & AACDB_FLAGS_FIB_IOCTL)
8252 			caller = "IOCTL";
8253 		else if (acp->fib_flags & AACDB_FLAGS_FIB_SRB)
8254 			caller = "SRB";
8255 		else
8256 			return;
8257 	} else {
8258 		if (!(softs->debug_fib_flags & AACDB_FLAGS_FIB_SYNC))
8259 			return;
8260 		caller = "SYNC";
8261 	}
8262 
8263 	fib_cmd = ddi_get16(acc, &fibp->Header.Command);
8264 	cmdstr = aac_cmd_name(fib_cmd, aac_fib_cmds);
8265 	sub_cmd = (uint32_t)-1;
8266 	subcmdstr = NULL;
8267 
8268 	/* Print FIB header */
8269 	if (softs->debug_fib_flags & AACDB_FLAGS_FIB_HEADER) {
8270 		aac_printf(softs, CE_NOTE, "FIB> from %s", caller);
8271 		aac_printf(softs, CE_NOTE, "     XferState  %d",
8272 		    ddi_get32(acc, &fibp->Header.XferState));
8273 		aac_printf(softs, CE_NOTE, "     Command    %d",
8274 		    ddi_get16(acc, &fibp->Header.Command));
8275 		aac_printf(softs, CE_NOTE, "     StructType %d",
8276 		    ddi_get8(acc, &fibp->Header.StructType));
8277 		aac_printf(softs, CE_NOTE, "     Flags      0x%x",
8278 		    ddi_get8(acc, &fibp->Header.Flags));
8279 		aac_printf(softs, CE_NOTE, "     Size       %d",
8280 		    ddi_get16(acc, &fibp->Header.Size));
8281 		aac_printf(softs, CE_NOTE, "     SenderSize %d",
8282 		    ddi_get16(acc, &fibp->Header.SenderSize));
8283 		aac_printf(softs, CE_NOTE, "     SenderAddr 0x%x",
8284 		    ddi_get32(acc, &fibp->Header.SenderFibAddress));
8285 		aac_printf(softs, CE_NOTE, "     RcvrAddr   0x%x",
8286 		    ddi_get32(acc, &fibp->Header.ReceiverFibAddress));
8287 		aac_printf(softs, CE_NOTE, "     SenderData 0x%x",
8288 		    ddi_get32(acc, &fibp->Header.SenderData));
8289 	}
8290 
8291 	/* Print FIB data */
8292 	switch (fib_cmd) {
8293 	case ContainerCommand:
8294 		sub_cmd = ddi_get32(acc,
8295 		    (void *)&(((uint32_t *)(void *)&fibp->data[0])[0]));
8296 		subcmdstr = aac_cmd_name(sub_cmd, aac_ctvm_subcmds);
8297 		if (subcmdstr == NULL)
8298 			break;
8299 
8300 		switch (sub_cmd) {
8301 		case VM_ContainerConfig: {
8302 			struct aac_Container *pContainer =
8303 			    (struct aac_Container *)fibp->data;
8304 
8305 			fib_cmd = sub_cmd;
8306 			cmdstr = subcmdstr;
8307 			sub_cmd = (uint32_t)-1;
8308 			subcmdstr = NULL;
8309 
8310 			sub_cmd = ddi_get32(acc,
8311 			    &pContainer->CTCommand.command);
8312 			subcmdstr = aac_cmd_name(sub_cmd, aac_ct_subcmds);
8313 			if (subcmdstr == NULL)
8314 				break;
8315 			aac_printf(softs, CE_NOTE, "FIB> %s (0x%x, 0x%x, 0x%x)",
8316 			    subcmdstr,
8317 			    ddi_get32(acc, &pContainer->CTCommand.param[0]),
8318 			    ddi_get32(acc, &pContainer->CTCommand.param[1]),
8319 			    ddi_get32(acc, &pContainer->CTCommand.param[2]));
8320 			return;
8321 		}
8322 
8323 		case VM_Ioctl:
8324 			fib_cmd = sub_cmd;
8325 			cmdstr = subcmdstr;
8326 			sub_cmd = (uint32_t)-1;
8327 			subcmdstr = NULL;
8328 
8329 			sub_cmd = ddi_get32(acc,
8330 			    (void *)&(((uint32_t *)(void *)&fibp->data[0])[4]));
8331 			subcmdstr = aac_cmd_name(sub_cmd, aac_ioctl_subcmds);
8332 			break;
8333 
8334 		case VM_CtBlockRead:
8335 		case VM_CtBlockWrite: {
8336 			struct aac_blockread *br =
8337 			    (struct aac_blockread *)fibp->data;
8338 			struct aac_sg_table *sg = &br->SgMap;
8339 			uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
8340 
8341 			aac_printf(softs, CE_NOTE,
8342 			    "FIB> %s Container %d  0x%x/%d", subcmdstr,
8343 			    ddi_get32(acc, &br->ContainerId),
8344 			    ddi_get32(acc, &br->BlockNumber),
8345 			    ddi_get32(acc, &br->ByteCount));
8346 			for (i = 0; i < sgcount; i++)
8347 				aac_printf(softs, CE_NOTE,
8348 				    "     %d: 0x%08x/%d", i,
8349 				    ddi_get32(acc, &sg->SgEntry[i].SgAddress),
8350 				    ddi_get32(acc, &sg->SgEntry[i]. \
8351 				    SgByteCount));
8352 			return;
8353 		}
8354 		}
8355 		break;
8356 
8357 	case ContainerCommand64: {
8358 		struct aac_blockread64 *br =
8359 		    (struct aac_blockread64 *)fibp->data;
8360 		struct aac_sg_table64 *sg = &br->SgMap64;
8361 		uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
8362 		uint64_t sgaddr;
8363 
8364 		sub_cmd = br->Command;
8365 		subcmdstr = NULL;
8366 		if (sub_cmd == VM_CtHostRead64)
8367 			subcmdstr = "VM_CtHostRead64";
8368 		else if (sub_cmd == VM_CtHostWrite64)
8369 			subcmdstr = "VM_CtHostWrite64";
8370 		else
8371 			break;
8372 
8373 		aac_printf(softs, CE_NOTE,
8374 		    "FIB> %s Container %d  0x%x/%d", subcmdstr,
8375 		    ddi_get16(acc, &br->ContainerId),
8376 		    ddi_get32(acc, &br->BlockNumber),
8377 		    ddi_get16(acc, &br->SectorCount));
8378 		for (i = 0; i < sgcount; i++) {
8379 			sgaddr = ddi_get64(acc,
8380 			    &sg->SgEntry64[i].SgAddress);
8381 			aac_printf(softs, CE_NOTE,
8382 			    "     %d: 0x%08x.%08x/%d", i,
8383 			    AAC_MS32(sgaddr), AAC_LS32(sgaddr),
8384 			    ddi_get32(acc, &sg->SgEntry64[i]. \
8385 			    SgByteCount));
8386 		}
8387 		return;
8388 	}
8389 
8390 	case RawIo: {
8391 		struct aac_raw_io *io = (struct aac_raw_io *)fibp->data;
8392 		struct aac_sg_tableraw *sg = &io->SgMapRaw;
8393 		uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
8394 		uint64_t sgaddr;
8395 
8396 		aac_printf(softs, CE_NOTE,
8397 		    "FIB> RawIo Container %d  0x%llx/%d 0x%x",
8398 		    ddi_get16(acc, &io->ContainerId),
8399 		    ddi_get64(acc, &io->BlockNumber),
8400 		    ddi_get32(acc, &io->ByteCount),
8401 		    ddi_get16(acc, &io->Flags));
8402 		for (i = 0; i < sgcount; i++) {
8403 			sgaddr = ddi_get64(acc, &sg->SgEntryRaw[i].SgAddress);
8404 			aac_printf(softs, CE_NOTE, "     %d: 0x%08x.%08x/%d", i,
8405 			    AAC_MS32(sgaddr), AAC_LS32(sgaddr),
8406 			    ddi_get32(acc, &sg->SgEntryRaw[i].SgByteCount));
8407 		}
8408 		return;
8409 	}
8410 
8411 	case ClusterCommand:
8412 		sub_cmd = ddi_get32(acc,
8413 		    (void *)&(((uint32_t *)(void *)fibp->data)[0]));
8414 		subcmdstr = aac_cmd_name(sub_cmd, aac_cl_subcmds);
8415 		break;
8416 
8417 	case AifRequest:
8418 		sub_cmd = ddi_get32(acc,
8419 		    (void *)&(((uint32_t *)(void *)fibp->data)[0]));
8420 		subcmdstr = aac_cmd_name(sub_cmd, aac_aif_subcmds);
8421 		break;
8422 
8423 	default:
8424 		break;
8425 	}
8426 
8427 	fib_size = ddi_get16(acc, &(fibp->Header.Size));
8428 	if (subcmdstr)
8429 		aac_printf(softs, CE_NOTE, "FIB> %s, sz=%d",
8430 		    subcmdstr, fib_size);
8431 	else if (cmdstr && sub_cmd == (uint32_t)-1)
8432 		aac_printf(softs, CE_NOTE, "FIB> %s, sz=%d",
8433 		    cmdstr, fib_size);
8434 	else if (cmdstr)
8435 		aac_printf(softs, CE_NOTE, "FIB> %s: Unknown(0x%x), sz=%d",
8436 		    cmdstr, sub_cmd, fib_size);
8437 	else
8438 		aac_printf(softs, CE_NOTE, "FIB> Unknown(0x%x), sz=%d",
8439 		    fib_cmd, fib_size);
8440 }
8441 
8442 static void
aac_print_aif(struct aac_softstate * softs,struct aac_aif_command * aif)8443 aac_print_aif(struct aac_softstate *softs, struct aac_aif_command *aif)
8444 {
8445 	int aif_command;
8446 	uint32_t aif_seqnumber;
8447 	int aif_en_type;
8448 	char *str;
8449 
8450 	aif_command = LE_32(aif->command);
8451 	aif_seqnumber = LE_32(aif->seqNumber);
8452 	aif_en_type = LE_32(aif->data.EN.type);
8453 
8454 	switch (aif_command) {
8455 	case AifCmdEventNotify:
8456 		str = aac_cmd_name(aif_en_type, aac_aifens);
8457 		if (str)
8458 			aac_printf(softs, CE_NOTE, "AIF! %s", str);
8459 		else
8460 			aac_printf(softs, CE_NOTE, "AIF! Unknown(0x%x)",
8461 			    aif_en_type);
8462 		break;
8463 
8464 	case AifCmdJobProgress:
8465 		switch (LE_32(aif->data.PR[0].status)) {
8466 		case AifJobStsSuccess:
8467 			str = "success"; break;
8468 		case AifJobStsFinished:
8469 			str = "finished"; break;
8470 		case AifJobStsAborted:
8471 			str = "aborted"; break;
8472 		case AifJobStsFailed:
8473 			str = "failed"; break;
8474 		case AifJobStsSuspended:
8475 			str = "suspended"; break;
8476 		case AifJobStsRunning:
8477 			str = "running"; break;
8478 		default:
8479 			str = "unknown"; break;
8480 		}
8481 		aac_printf(softs, CE_NOTE,
8482 		    "AIF! JobProgress (%d) - %s (%d, %d)",
8483 		    aif_seqnumber, str,
8484 		    LE_32(aif->data.PR[0].currentTick),
8485 		    LE_32(aif->data.PR[0].finalTick));
8486 		break;
8487 
8488 	case AifCmdAPIReport:
8489 		aac_printf(softs, CE_NOTE, "AIF! APIReport (%d)",
8490 		    aif_seqnumber);
8491 		break;
8492 
8493 	case AifCmdDriverNotify:
8494 		aac_printf(softs, CE_NOTE, "AIF! DriverNotify (%d)",
8495 		    aif_seqnumber);
8496 		break;
8497 
8498 	default:
8499 		aac_printf(softs, CE_NOTE, "AIF! AIF %d (%d)",
8500 		    aif_command, aif_seqnumber);
8501 		break;
8502 	}
8503 }
8504 
8505 #endif /* DEBUG */
8506