xref: /illumos-gate/usr/src/uts/common/io/cpqary3/cpqary3_talk2ctlr.c (revision c5bab7026b8e0ac44b25ee08507ea360f177d844)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
14  */
15 
16 /*
17  * This module contains routines that program the controller. All
18  * operations  viz.,  initialization of  controller,  submision &
19  * retrieval  of  commands, enabling &  disabling of  interrupts,
20  * checking interrupt status are performed here.
21  */
22 
23 #include <sys/sdt.h>
24 #include "cpqary3.h"
25 
26 /*
27  * Local Functions Definitions
28  */
29 uint8_t cpqary3_check_simple_ctlr_intr(cpqary3_t *cpqary3p);
30 uint8_t cpqary3_check_perf_ctlr_intr(cpqary3_t *cpqary3p);
31 uint8_t cpqary3_check_perf_e200_intr(cpqary3_t *cpqary3p);
32 uint8_t cpqary3_check_ctlr_init(cpqary3_t *);
33 
34 /*
35  * Function	: 	cpqary3_check_simple_ctlr_intr
36  * Description	: 	This routine determines if the controller did interrupt.
37  * Called By	: 	cpqary3_hw_isr()
38  * Parameters	: 	per-controller
39  * Calls	: 	None
40  * Return Values: 	SUCCESS : This controller did interrupt.
41  *			FAILURE : It did not.
42  */
43 uint8_t
44 cpqary3_check_simple_ctlr_intr(cpqary3_t *cpqary3p)
45 {
46 	uint32_t	intr_pending_mask = 0;
47 
48 	/*
49 	 * Read the Interrupt Status Register and
50 	 * if bit 3 is set, it indicates that we have completed commands
51 	 * in the controller
52 	 */
53 	intr_pending_mask = cpqary3p->bddef->bd_intrpendmask;
54 
55 	if (intr_pending_mask &
56 	    (ddi_get32(cpqary3p->isr_handle, (uint32_t *)cpqary3p->isr)))
57 		return (CPQARY3_SUCCESS);
58 
59 	return (CPQARY3_FAILURE);
60 }
61 
62 /*
63  * Function	:      	cpqary3_check_perf_ctlr_intr
64  * Description	:      	This routine determines if the
65  *			controller did interrupt.
66  * Called By	:      	cpqary3_hw_isr()
67  * Parameters	:      	per-controller
68  * Calls	:      	None
69  * Return Values:      	SUCCESS : This controller did interrupt.
70  *			FAILURE : It did not.
71  */
72 uint8_t
73 cpqary3_check_perf_ctlr_intr(cpqary3_t *cpqary3p)
74 {
75 	/*
76 	 * Read the Interrupt Status Register and
77 	 * if bit 3 is set, it indicates that we have completed commands
78 	 * in the controller
79 	 */
80 	if (0x1 & (ddi_get32(cpqary3p->isr_handle,
81 	    (uint32_t *)cpqary3p->isr))) {
82 		return (CPQARY3_SUCCESS);
83 	}
84 
85 	return (CPQARY3_FAILURE);
86 }
87 
88 /*
89  * Function	:      	cpqary3_check_perf_e200_intr
90  * Description	:      	This routine determines if the controller
91  *			did interrupt.
92  * Called By	:      	cpqary3_hw_isr()
93  * Parameters	:      	per-controller
94  * Calls	:      	None
95  * Return Values:      	SUCCESS : This controller did interrupt.
96  *			FAILURE : It did not.
97  */
98 uint8_t
99 cpqary3_check_perf_e200_intr(cpqary3_t *cpqary3p)
100 {
101 	/*
102 	 * Read the Interrupt Status Register and
103 	 * if bit 3 is set, it indicates that we have completed commands
104 	 * in the controller
105 	 */
106 	if (0x4 & (ddi_get32(cpqary3p->isr_handle,
107 	    (uint32_t *)cpqary3p->isr))) {
108 		return (CPQARY3_SUCCESS);
109 	}
110 
111 	return (CPQARY3_FAILURE);
112 }
113 
114 
115 /*
116  * Function	: 	cpqary3_retrieve
117  * Description	: 	This routine retrieves the completed command from the
118  *			controller reply queue.
119  *			and processes the completed commands.
120  * Called By	:  	cpqary3_sw_isr(), cpqary3_handle_flag_nointr()
121  * Parameters	: 	per-controller
122  * Calls	: 	packet completion routines
123  * Return Values: 	SUCCESS : A completed command has been retrieved
124  *			and processed.
125  *			FAILURE : No completed command was in the controller.
126  */
127 uint8_t
128 cpqary3_retrieve(cpqary3_t *cpqary3p)
129 {
130 	uint32_t			tag;
131 	uint32_t			CmdsOutMax;
132 	cpqary3_cmdpvt_t		*cpqary3_cmdpvtp;
133 	cpqary3_drvr_replyq_t		*replyq_ptr;
134 
135 	/*
136 	 * Get the Reply Command List Addr
137 	 * Update the returned Tag in that particular command structure.
138 	 * If a valid one, de-q that from the SUBMITTED Q and
139 	 * enqueue that to the RETRIEVED Q.
140 	 */
141 
142 	RETURN_FAILURE_IF_NULL(cpqary3p);
143 
144 	/* PERF */
145 	replyq_ptr = (cpqary3_drvr_replyq_t *)cpqary3p->drvr_replyq;
146 	CmdsOutMax = cpqary3p->ctlr_maxcmds;
147 
148 	while ((replyq_ptr->replyq_headptr[0] & 0x01) ==
149 	    replyq_ptr->cyclic_indicator) {
150 		/* command has completed */
151 		/* Get the tag */
152 
153 		tag = replyq_ptr->replyq_headptr[0];
154 		if ((tag >> CPQARY3_GET_MEM_TAG) >= (CmdsOutMax / 3) * 3) {
155 			cmn_err(CE_WARN,
156 			    "CPQary3 : HBA returned Spurious Tag");
157 			return (CPQARY3_FAILURE);
158 		}
159 
160 		cpqary3_cmdpvtp = &cpqary3p->cmdmemlistp->pool[
161 		    tag >> CPQARY3_GET_MEM_TAG];
162 		cpqary3_cmdpvtp->cmdlist_memaddr->
163 		    Header.Tag.drvinfo_n_err = (tag & 0xF) >> 1;
164 		mutex_enter(&cpqary3p->sw_mutex);
165 		cpqary3_cmdpvtp->complete(cpqary3_cmdpvtp);
166 		mutex_exit(&cpqary3p->sw_mutex);
167 
168 		/* Traverse to the next command in reply queue */
169 
170 		++replyq_ptr->index;
171 		if (replyq_ptr->index == replyq_ptr->max_index) {
172 			replyq_ptr->index = 0;
173 			/* Toggle at wraparound */
174 			replyq_ptr->cyclic_indicator =
175 			    (replyq_ptr->cyclic_indicator == 0) ? 1 : 0;
176 			replyq_ptr->replyq_headptr =
177 			    /* LINTED: alignment */
178 			    (uint32_t *)(replyq_ptr->replyq_start_addr);
179 		} else {
180 			replyq_ptr->replyq_headptr += 2;
181 		}
182 	}
183 	/* PERF */
184 
185 	return (CPQARY3_SUCCESS);
186 }
187 
188 
189 /*
190  * Function	:  cpqary3_poll_retrieve
191  * Description	:  This routine retrieves the completed command from the
192  *			controller reply queue in poll mode.
193  *			and processes the completed commands.
194  * Called By	:  cpqary3_poll
195  * Parameters	:  per-controller
196  * Calls	:  packet completion routines
197  * Return Values:  If the polled command is completed, send back a success.
198  *			If not return failure.
199  */
200 uint8_t
201 cpqary3_poll_retrieve(cpqary3_t *cpqary3p, uint32_t poll_tag)
202 {
203 	uint32_t			tag;
204 	uint32_t			CmdsOutMax;
205 	cpqary3_cmdpvt_t		*cpqary3_cmdpvtp;
206 	cpqary3_drvr_replyq_t		*replyq_ptr;
207 	uint32_t			temp_tag;
208 	uint8_t				tag_flag = 0;
209 
210 	RETURN_FAILURE_IF_NULL(cpqary3p);
211 
212 	/* PERF */
213 	replyq_ptr = (cpqary3_drvr_replyq_t *)cpqary3p->drvr_replyq;
214 	CmdsOutMax = cpqary3p->cmdmemlistp->max_memcnt;
215 
216 	if (!(cpqary3p->bddef->bd_flags & SA_BD_SAS)) {
217 		while ((tag = ddi_get32(cpqary3p->opq_handle,
218 		    (uint32_t *)cpqary3p->opq)) != 0xFFFFFFFF) {
219 			cpqary3_cmdpvtp = &cpqary3p->cmdmemlistp->pool[
220 			    tag >> CPQARY3_GET_MEM_TAG];
221 			cpqary3_cmdpvtp->cmdlist_memaddr->
222 			    Header.Tag.drvinfo_n_err = (tag & 0xF) >> 1;
223 			temp_tag = cpqary3_cmdpvtp->tag.tag_value;
224 
225 			if (temp_tag == poll_tag)
226 				tag_flag = 1;
227 			cpqary3_cmdpvtp->complete(cpqary3_cmdpvtp);
228 		}
229 	} else {
230 		while ((replyq_ptr->replyq_headptr[0] & 0x01) ==
231 		    replyq_ptr->cyclic_indicator) {
232 			/* command has completed */
233 			/* Get the tag */
234 			tag = replyq_ptr->replyq_headptr[0];
235 
236 			if ((tag >> CPQARY3_GET_MEM_TAG) >= (CmdsOutMax/3)*3) {
237 				cmn_err(CE_WARN,
238 				    "CPQary3 : HBA returned Spurious Tag");
239 				return (CPQARY3_FAILURE);
240 			}
241 
242 			cpqary3_cmdpvtp = &cpqary3p->cmdmemlistp->pool[
243 			    tag >> CPQARY3_GET_MEM_TAG];
244 			cpqary3_cmdpvtp->cmdlist_memaddr->
245 			    Header.Tag.drvinfo_n_err = (tag & 0xF) >> 1;
246 			temp_tag = cpqary3_cmdpvtp->tag.tag_value;
247 
248 			if (temp_tag == poll_tag)
249 				tag_flag = 1;
250 
251 			cpqary3_cmdpvtp->complete(cpqary3_cmdpvtp);
252 
253 			/* Traverse to the next command in reply queue */
254 			++replyq_ptr->index;
255 			if (replyq_ptr->index == replyq_ptr->max_index) {
256 				replyq_ptr->index = 0;
257 				/* Toggle at wraparound */
258 				replyq_ptr->cyclic_indicator =
259 				    (replyq_ptr->cyclic_indicator == 0) ? 1 : 0;
260 				replyq_ptr->replyq_headptr =
261 				    /* LINTED: alignment */
262 				    (uint32_t *)(replyq_ptr->replyq_start_addr);
263 			} else {
264 				replyq_ptr->replyq_headptr += 2;
265 			}
266 		}
267 	}
268 	/* PERF */
269 	if (tag_flag) {
270 		return (CPQARY3_SUCCESS);
271 	}
272 
273 	return (CPQARY3_FAILURE);
274 }
275 
276 /*
277  * Function	: 	cpqary3_submit
278  * Description	: 	This routine submits the command to the Inbound Post Q.
279  * Called By	: 	cpqary3_transport(), cpqary3_send_NOE_command(),
280  *			cpqary3_disable_NOE_command(),
281  *			cpqary3_handle_flag_nointr(),
282  *			cpqary3_tick_hdlr(), cpqary3_synccmd_send()
283  * Parameters	: 	per-controller, physical address
284  * Calls	: 	None
285  * Return Values: 	None
286  */
287 int32_t
288 cpqary3_submit(cpqary3_t *cpqary3p, uint32_t cmd_phyaddr)
289 {
290 	uint32_t		phys_addr = 0;
291 	uint8_t			retval  = 0;
292 
293 	/*
294 	 * Write the Physical Address of the command-to-be-submitted
295 	 * into the Controller's Inbound Post Q.
296 	 */
297 
298 	ASSERT(cpqary3p != NULL);
299 
300 #ifdef AMD64_DEBUG
301 	{
302 	char		debug_char;
303 	uint32_t	tmp_cmd_phyaddr;
304 
305 	tmp_cmd_phyaddr = (uint32_t)(cmd_phyaddr & 0XFFFFFFFF);
306 
307 	cmn_err(CE_WARN, "CPQary3: cmd_phyaddr = %lX\n tmp_cmd_phyaddr = %lX",
308 	    cmd_phyaddr, tmp_cmd_phyaddr);
309 
310 	debug_enter(&debug_char);
311 	ddi_put32(cpqary3p->ipq_handle, (uint32_t *)cpqary3p->ipq, cmd_phyaddr);
312 	}
313 #endif
314 
315 
316 	/* CONTROLLER_LOCKUP */
317 	if (cpqary3p->controller_lockup == CPQARY3_TRUE) {
318 		retval = EIO;
319 		return (retval);
320 	}
321 	/* CONTROLLER_LOCKUP */
322 
323 	if (!(cpqary3p->bddef->bd_flags & SA_BD_SAS)) {
324 		ddi_put32(cpqary3p->ipq_handle,
325 		    (uint32_t *)cpqary3p->ipq, cmd_phyaddr);
326 	} else {
327 		/* The driver always uses the 0th block fetch count always */
328 		phys_addr = cmd_phyaddr | 0 | 0x1;
329 		ddi_put32(cpqary3p->ipq_handle,
330 		    (uint32_t *)cpqary3p->ipq, phys_addr);
331 	}
332 
333 	/* PERF */
334 
335 	/*
336 	 * Command submission can NEVER FAIL since the number of commands that
337 	 * can reside in the controller at any time is 1024 and our memory
338 	 * allocation is for 225 commands ONLY. Thus, at any given time the
339 	 * maximum number of commands in the controller is 225.
340 	 */
341 
342 	/* CONTROLLER_LOCKUP */
343 	return (retval);
344 	/* CONTROLLER_LOCKUP */
345 
346 }
347 
348 
349 /*
350  * Function	: 	cpqary3_intr_onoff
351  * Description	: 	This routine enables/disables the HBA interrupt.
352  * Called By	: 	cpqary3_attach(), ry3_handle_flag_nointr(),
353  *			cpqary3_tick_hdlr(), cpqary3_init_ctlr_resource()
354  * Parameters	: 	per-controller, flag stating enable/disable
355  * Calls	: 	None
356  * Return Values: 	None
357  */
358 void
359 cpqary3_intr_onoff(cpqary3_t *cpqary3p, uint8_t flag)
360 {
361 	uint32_t	intr = 0;
362 	uint32_t	intr_mask = 0;
363 
364 	/*
365 	 * Enable or disable the interrupt based on the flag
366 	 * Read the Interrupt Mask Register first and then update it
367 	 * accordingly
368 	 */
369 
370 	ASSERT(cpqary3p != NULL);
371 
372 	intr = ddi_get32(cpqary3p->imr_handle, (uint32_t *)cpqary3p->imr);
373 	intr_mask = cpqary3p->bddef->bd_intrmask;
374 
375 	if (flag == CPQARY3_INTR_ENABLE) {
376 		ddi_put32(cpqary3p->imr_handle,
377 		    (uint32_t *)cpqary3p->imr, intr & ~(intr_mask));
378 	} else {
379 		ddi_put32(cpqary3p->imr_handle,
380 		    (uint32_t *)cpqary3p->imr, (intr | intr_mask));
381 	}
382 }
383 
384 
385 /*
386  * Function	: 	cpqary3_lockup_intr_onoff
387  * Description	: 	This routine enables/disables the lockup interrupt.
388  * Called By	: 	cpqary3_attach(), cpqary3_handle_flag_nointr(),
389  *			cpqary3_tick_hdlr(), cpqary3_hw_isr,
390  *			cpqary3_init_ctlr_resource()
391  * Parameters	: 	per-controller, flag stating enable/disable
392  * Calls	: 	None
393  * Return Values: 	None
394  */
395 void
396 cpqary3_lockup_intr_onoff(cpqary3_t *cpqary3p, uint8_t flag)
397 {
398 	uint32_t	intr = 0;
399 	uint32_t	intr_lockup_mask = 0;
400 
401 	/*
402 	 * Enable or disable the interrupt based on the flag
403 	 * Read the Interrupt Mask Register first and then update it
404 	 * accordingly
405 	 */
406 
407 	ASSERT(cpqary3p != NULL);
408 
409 	intr = ddi_get32(cpqary3p->imr_handle, (uint32_t *)cpqary3p->imr);
410 	intr_lockup_mask = cpqary3p->bddef->bd_lockup_intrmask;
411 
412 	if (flag == CPQARY3_INTR_ENABLE) {
413 		ddi_put32(cpqary3p->imr_handle,
414 		    (uint32_t *)cpqary3p->imr, intr & ~(intr_lockup_mask));
415 	} else {
416 		ddi_put32(cpqary3p->imr_handle,
417 		    (uint32_t *)cpqary3p->imr, (intr | intr_lockup_mask));
418 	}
419 }
420 
421 /*
422  * Function	: 	cpqary3_init_ctlr
423  * Description	: 	This routine initialises the HBA to Simple Transport
424  *			Method. Refer to CISS for more information.
425  *			It checks the readiness of the HBA.
426  * Called By	: 	cpqary3_init_ctlr_resource()
427  * Parameters	: 	per-controller(), physical address()
428  * Calls	: 	cpqary3_check_ctlr_init
429  * Return Values: 	SUCCESS / FAILURE
430  *			[Shall return failure if the initialization of the
431  *			controller to the Simple Transport Method fails]
432  */
433 uint8_t
434 cpqary3_init_ctlr(cpqary3_t *cpqary3p)
435 {
436 	uint8_t				cntr;
437 	uint8_t				signature[4] = { 'C', 'I', 'S', 'S' };
438 	volatile CfgTable_t		*ctp;
439 	volatile CfgTrans_Perf_t	*perf_cfg;
440 	cpqary3_phyctg_t		*cpqary3_phyctgp;
441 	uint32_t			phy_addr;
442 	size_t				cmd_size;
443 	uint32_t			queue_depth;
444 	uint32_t			CmdsOutMax;
445 	uint32_t			BlockFetchCnt[8];
446 	caddr_t				replyq_start_addr = NULL;
447 	/* SG */
448 	uint32_t			max_blk_fetch_cnt = 0;
449 	uint32_t			max_sg_cnt = 0;
450 	uint32_t			optimal_sg = 0;
451 	uint32_t			optimal_sg_size = 0;
452 	/* Header + Request + Error */
453 	uint32_t			size_of_HRE = 0;
454 	uint32_t			size_of_cmdlist = 0;
455 	/* SG */
456 
457 	RETURN_FAILURE_IF_NULL(cpqary3p);
458 	ctp = (CfgTable_t *)cpqary3p->ct;
459 	perf_cfg = (CfgTrans_Perf_t *)cpqary3p->cp;
460 
461 	/* QUEUE CHANGES */
462 	cpqary3p->drvr_replyq =
463 	    (cpqary3_drvr_replyq_t *)MEM_ZALLOC(sizeof (cpqary3_drvr_replyq_t));
464 	/* QUEUE CHANGES */
465 
466 	if (!cpqary3_check_ctlr_init(cpqary3p))
467 		return (CPQARY3_FAILURE);
468 
469 	DTRACE_PROBE1(ctlr_init_start, CfgTable_t *, ctp);
470 
471 	/*
472 	 * Validate the signature - should be "CISS"
473 	 * Use of cntr in the for loop does not suggest a counter - it just
474 	 * saves declaration of another variable.
475 	 */
476 
477 	for (cntr = 0; cntr < 4; cntr++) {
478 		if (DDI_GET8(cpqary3p, &ctp->Signature[cntr]) !=
479 		    signature[cntr]) {
480 			cmn_err(CE_WARN, "CPQary3 : Controller NOT ready");
481 			cmn_err(CE_WARN, "CPQary3 : _cpqary3_init_ctlr : "
482 			    "Signature not stamped");
483 			return (CPQARY3_FAILURE);
484 		}
485 	}
486 
487 
488 	if (!(cpqary3p->bddef->bd_flags & SA_BD_SAS)) {
489 		CmdsOutMax = DDI_GET32(cpqary3p, &ctp->CmdsOutMax);
490 
491 		if (CmdsOutMax == 0) {
492 			cmn_err(CE_CONT, "CPQary3 : HBA Maximum Outstanding "
493 			    "Commands set to Zero\n");
494 			cmn_err(CE_CONT, "CPQary3 : Cannot continue driver "
495 			    "initialization \n");
496 			return (CPQARY3_FAILURE);
497 		}
498 
499 		cpqary3p->ctlr_maxcmds = CmdsOutMax;
500 		cpqary3p->sg_cnt = CPQARY3_SG_CNT;
501 
502 		queue_depth = cpqary3p->ctlr_maxcmds;
503 		cmd_size = (8 * queue_depth);
504 		/* QUEUE CHANGES */
505 		cpqary3p->drvr_replyq->cyclic_indicator =
506 		    CPQARY3_REPLYQ_INIT_CYCLIC_IND;
507 		cpqary3p->drvr_replyq->simple_cyclic_indicator =
508 		    CPQARY3_REPLYQ_INIT_CYCLIC_IND;
509 		cpqary3p->drvr_replyq->max_index = cpqary3p->ctlr_maxcmds;
510 		cpqary3p->drvr_replyq->simple_index = 0;
511 		replyq_start_addr = MEM_ZALLOC(cmd_size);
512 		bzero(replyq_start_addr, cmd_size);
513 		cpqary3p->drvr_replyq->replyq_headptr =
514 		    /* LINTED: alignment */
515 		    (uint32_t *)replyq_start_addr;
516 		cpqary3p->drvr_replyq->replyq_simple_ptr =
517 		    /* LINTED: alignment */
518 		    (uint32_t *)replyq_start_addr;
519 		cpqary3p->drvr_replyq->replyq_start_addr = replyq_start_addr;
520 
521 		/* PERF */
522 
523 		/*
524 		 * Check for support of SIMPLE Transport Method
525 		 */
526 		if (!(DDI_GET32(cpqary3p, &ctp->TransportSupport) &
527 		    CFGTBL_XPORT_SIMPLE)) {
528 			cmn_err(CE_WARN, "CPQary3 : Controller "
529 			    "NOT YET INITIALIZED");
530 			cmn_err(CE_CONT, "CPQary3 : For Hot Plug Operations, "
531 			    "try again later \n");
532 			return (CPQARY3_FAILURE);
533 		}
534 
535 		/*
536 		 * Configuration Table Initialization
537 		 * Set bit 0 of InBound Door Bell Reg to inform the controller
538 		 * about the changes related to the Configuration table
539 		 */
540 		DTRACE_PROBE(cfgtable_init_start);
541 
542 		DDI_PUT32(cpqary3p, &ctp->HostWrite.TransportRequest,
543 		    CFGTBL_XPORT_SIMPLE);
544 		ddi_put32(cpqary3p->idr_handle, (uint32_t *)cpqary3p->idr,
545 		    ddi_get32(cpqary3p->idr_handle, (uint32_t *)cpqary3p->idr) |
546 		    CFGTBL_CHANGE_REQ);
547 
548 		/*
549 		 * Check whether the controller is  ready
550 		 */
551 
552 		cntr = 0;
553 		while (ddi_get32(cpqary3p->idr_handle,
554 		    (uint32_t *)cpqary3p->idr) & CFGTBL_ACC_CMDS) {
555 			drv_usecwait(1000000); /* Wait for 1 Sec. */
556 			cntr++;
557 
558 			/*
559 			 * Wait for a maximum of 90 seconds. No f/w should take
560 			 * more than 90 secs to initialize. If the controller
561 			 * is not ready even after 90 secs, it suggests that
562 			 * something is wrong
563 			 * (wrt the controller, what else) !!!
564 			 */
565 
566 			if (cntr > CISS_INIT_TIME) /* 1.30 Mins */ {
567 				cmn_err(CE_CONT, "CPQary3 : Controller "
568 				    "Initialization Failed \n");
569 				return (CPQARY3_FAILURE);
570 			}
571 		}
572 
573 		DTRACE_PROBE(cfgtable_init_done);
574 
575 		/*
576 		 * Check whether controller accepts the requested method of
577 		 * transport
578 		 */
579 		if (!(DDI_GET32(cpqary3p, &ctp->TransportActive) &
580 		    CFGTBL_XPORT_SIMPLE)) {
581 			cmn_err(CE_CONT, "CPQary3 : Failed to Initialize "
582 			    "Controller \n");
583 			cmn_err(CE_CONT, "CPQary3 : For Hot Plug Operations, "
584 			    "try again later\n");
585 			return (CPQARY3_FAILURE);
586 		}
587 
588 		DTRACE_PROBE(ctlr_init_simple);
589 
590 		/*
591 		 * Check if Controller is ready to accept Commands
592 		 */
593 
594 		if (!(DDI_GET32(cpqary3p, &ctp->TransportActive) &
595 		    CFGTBL_ACC_CMDS)) {
596 			cmn_err(CE_CONT, "CPQary3: Controller NOT ready to "
597 			    "accept Commands \n");
598 			return (CPQARY3_FAILURE);
599 		}
600 
601 		DTRACE_PROBE(ctlr_init_ready);
602 
603 		/*
604 		 * Check if the maximum number of oustanding commands for the
605 		 * initialized controller is something greater than Zero.
606 		 */
607 
608 		CmdsOutMax = DDI_GET32(cpqary3p, &ctp->CmdsOutMax);
609 
610 		if (CmdsOutMax == 0) {
611 			cmn_err(CE_CONT, "CPQary3 : HBA Maximum Outstanding "
612 			    "Commands set to Zero\n");
613 			cmn_err(CE_CONT, "CPQary3 : Cannot continue driver "
614 			    "initialization \n");
615 			return (CPQARY3_FAILURE);
616 		}
617 		cpqary3p->ctlr_maxcmds = CmdsOutMax;
618 
619 		/*
620 		 * Zero the Upper 32 Address in the Controller
621 		 */
622 
623 		DDI_PUT32(cpqary3p, &ctp->HostWrite.Upper32Addr, 0x00000000);
624 		cpqary3p->heartbeat = DDI_GET32(cpqary3p, &ctp->HeartBeat);
625 
626 		/* Set the controller interrupt check routine */
627 		cpqary3p->check_ctlr_intr = cpqary3_check_simple_ctlr_intr;
628 
629 		cpqary3p->host_support =
630 		    DDI_GET32(cpqary3p, &ctp->HostDrvrSupport);
631 		DDI_PUT32(cpqary3p, &ctp->HostDrvrSupport,
632 		    (cpqary3p->host_support | 0x4));
633 		cpqary3p->host_support =
634 		    DDI_GET32(cpqary3p, &ctp->HostDrvrSupport);
635 
636 		cpqary3p->lockup_logged = CPQARY3_FALSE;
637 	} else {
638 	/* PERF */
639 
640 		/*
641 		 * Check for support of PERF Transport Method
642 		 */
643 		if (!(DDI_GET32(cpqary3p, &ctp->TransportSupport)
644 		    & CFGTBL_XPORT_PERFORMANT)) {
645 			cmn_err(CE_WARN, "CPQary3 : Controller "
646 			    "NOT YET INITIALIZED");
647 			cmn_err(CE_CONT, "CPQary3 : For Hot Plug Operations, "
648 			    "try again later \n");
649 			return (CPQARY3_FAILURE);
650 		}
651 
652 		CmdsOutMax = DDI_GET32(cpqary3p, &ctp->MaxPerfModeCmdsOutMax);
653 		if (CmdsOutMax == 0)
654 			CmdsOutMax = DDI_GET32(cpqary3p, &ctp->CmdsOutMax);
655 		if (CmdsOutMax == 0) {
656 			cmn_err(CE_CONT, "CPQary3 : HBA Maximum Outstanding "
657 			    "Commands set to Zero\n");
658 			cmn_err(CE_CONT, "CPQary3 : Cannot continue driver "
659 			    "initialization \n");
660 			return (CPQARY3_FAILURE);
661 		}
662 
663 		cpqary3p->ctlr_maxcmds = CmdsOutMax;
664 
665 
666 		/* Initialize the Performant Method Transport Method Table */
667 
668 		queue_depth = cpqary3p->ctlr_maxcmds;
669 
670 		DDI_PUT32_CP(cpqary3p, &perf_cfg->ReplyQSize, queue_depth);
671 		DDI_PUT32_CP(cpqary3p, &perf_cfg->ReplyQCount, 1);
672 		DDI_PUT32_CP(cpqary3p, &perf_cfg->ReplyQCntrAddrLow32, 0);
673 		DDI_PUT32_CP(cpqary3p, &perf_cfg->ReplyQCntrAddrHigh32, 0);
674 
675 		cpqary3_phyctgp =
676 		    (cpqary3_phyctg_t *)MEM_ZALLOC(sizeof (cpqary3_phyctg_t));
677 
678 		if (!cpqary3_phyctgp) {
679 			cmn_err(CE_NOTE,
680 			    "CPQary3: Initial mem zalloc failed");
681 			return (CPQARY3_FAILURE);
682 		}
683 		cmd_size = (8 * queue_depth);
684 		phy_addr = 0;
685 		replyq_start_addr = cpqary3_alloc_phyctgs_mem(cpqary3p,
686 		    cmd_size, &phy_addr, cpqary3_phyctgp);
687 
688 		if (!replyq_start_addr) {
689 			cmn_err(CE_WARN, "MEMALLOC returned failure");
690 			return (CPQARY3_FAILURE);
691 		}
692 
693 		bzero(replyq_start_addr, cmd_size);
694 		cpqary3p->drvr_replyq->replyq_headptr =
695 		    /* LINTED: alignment */
696 		    (uint32_t *)replyq_start_addr;
697 		cpqary3p->drvr_replyq->index = 0;
698 		cpqary3p->drvr_replyq->max_index = queue_depth;
699 		cpqary3p->drvr_replyq->replyq_start_addr = replyq_start_addr;
700 		cpqary3p->drvr_replyq->cyclic_indicator =
701 		    CPQARY3_REPLYQ_INIT_CYCLIC_IND;
702 		cpqary3p->drvr_replyq->replyq_start_paddr = phy_addr;
703 
704 		DDI_PUT32_CP(cpqary3p, &perf_cfg->ReplyQAddr0Low32, phy_addr);
705 		DDI_PUT32_CP(cpqary3p, &perf_cfg->ReplyQAddr0High32, 0);
706 
707 		max_blk_fetch_cnt =
708 		    DDI_GET32(cpqary3p, &ctp->MaxBlockFetchCount);
709 
710 		/*
711 		 * For non-proton FW controllers, max_blk_fetch_count is not
712 		 * implemented in the firmware
713 		 */
714 
715 		/*
716 		 * When blk fetch count is 0, FW auto fetches 564 bytes
717 		 * corresponding to an optimal S/G of 31
718 		 */
719 		if (max_blk_fetch_cnt == 0) {
720 			BlockFetchCnt[0] = 35;
721 		} else {
722 			/*
723 			 * With MAX_PERF_SG_CNT set to 64, block fetch count
724 			 * is got by:(sizeof (CommandList_t) + 15)/16
725 			 */
726 			if (max_blk_fetch_cnt > 68)
727 				BlockFetchCnt[0] = 68;
728 			else
729 				BlockFetchCnt[0] = max_blk_fetch_cnt;
730 		}
731 
732 		DDI_PUT32_CP(cpqary3p, &perf_cfg->BlockFetchCnt[0],
733 		    BlockFetchCnt[0]);
734 		DDI_PUT32(cpqary3p, &ctp->HostWrite.TransportRequest,
735 		    CFGTBL_XPORT_PERFORMANT);
736 		ddi_put32(cpqary3p->idr_handle, (uint32_t *)cpqary3p->idr,
737 		    ddi_get32(cpqary3p->idr_handle, (uint32_t *)cpqary3p->idr) |
738 		    CFGTBL_CHANGE_REQ);
739 
740 		/*
741 		 * Check whether the controller is  ready
742 		 */
743 
744 		cntr = 0;
745 		while (ddi_get32(cpqary3p->idr_handle,
746 		    (uint32_t *)cpqary3p->idr) & CFGTBL_ACC_CMDS) {
747 			drv_usecwait(1000000); /* Wait for 1 Sec. */
748 			cntr++;
749 
750 
751 			/*
752 			 * Wait for a maximum of 90 seconds. No f/w should take
753 			 * more than 90 secs to initialize. If the controller
754 			 * is not ready even after 90 secs, it suggests that
755 			 * something is wrong
756 			 * (wrt the controller, what else) !!!
757 			 */
758 
759 			if (cntr > CISS_INIT_TIME) /* 1.30 Mins */ {
760 				cmn_err(CE_CONT, "CPQary3 : Controller "
761 				    "Initialization Failed \n");
762 				return (CPQARY3_FAILURE);
763 			}
764 		}
765 
766 		/*
767 		 * Check whether controller accepts the requested method of
768 		 * transport
769 		 */
770 
771 		if (!(DDI_GET32(cpqary3p, &ctp->TransportActive) &
772 		    CFGTBL_XPORT_PERFORMANT)) {
773 			cmn_err(CE_NOTE, "CPQary3 : Failed to Initialize "
774 			    "Controller");
775 			cmn_err(CE_CONT, "CPQary3 : For Hot Plug Operations, "
776 			    "try again later\n");
777 			DTRACE_PROBE1(ctlr_init_perf_fail, CfgTable_t *, ctp);
778 			return (CPQARY3_FAILURE);
779 		}
780 
781 		DTRACE_PROBE(ctlr_init_simple);
782 
783 		/*
784 		 * Check if Controller is ready to accept Commands
785 		 */
786 
787 		if (!(DDI_GET32(cpqary3p, &ctp->TransportActive) &
788 		    CFGTBL_ACC_CMDS)) {
789 			cmn_err(CE_NOTE, "CPQary3: Controller NOT ready to "
790 			    "accept Commands");
791 			return (CPQARY3_FAILURE);
792 		}
793 
794 		/*
795 		 * Check if the maximum number of oustanding commands for the
796 		 * initialized controller is something greater than Zero.
797 		 */
798 
799 		CmdsOutMax = DDI_GET32(cpqary3p, &ctp->MaxPerfModeCmdsOutMax);
800 		if (CmdsOutMax == 0)
801 			CmdsOutMax = DDI_GET32(cpqary3p, &ctp->CmdsOutMax);
802 
803 		if (CmdsOutMax == 0) {
804 			cmn_err(CE_NOTE, "CPQary3 : HBA Maximum Outstanding "
805 			    "Commands set to Zero");
806 			cmn_err(CE_NOTE, "CPQary3 : Cannot continue driver "
807 			    "initialization");
808 			return (CPQARY3_FAILURE);
809 		}
810 
811 		cpqary3p->ctlr_maxcmds = CmdsOutMax;
812 
813 		/* SG */
814 		max_sg_cnt = DDI_GET32(cpqary3p, &ctp->MaxSGElements);
815 		max_blk_fetch_cnt =
816 		    DDI_GET32(cpqary3p, &ctp->MaxBlockFetchCount);
817 
818 		/* 32 byte aligned - size_of_cmdlist */
819 		size_of_cmdlist = ((sizeof (CommandList_t) + 31) / 32) * 32;
820 		size_of_HRE  = size_of_cmdlist -
821 		    (sizeof (SGDescriptor_t) * CISS_MAXSGENTRIES);
822 
823 		if ((max_blk_fetch_cnt == 0) || (max_sg_cnt == 0) ||
824 		    ((max_blk_fetch_cnt * 16) <= size_of_HRE)) {
825 			cpqary3p->sg_cnt = CPQARY3_PERF_SG_CNT;
826 		} else {
827 			/*
828 			 * Get the optimal_sg - no of the SG's that will fit
829 			 * into the max_blk_fetch_cnt
830 			 */
831 
832 			optimal_sg_size =
833 			    (max_blk_fetch_cnt * 16) - size_of_HRE;
834 
835 			if (optimal_sg_size < sizeof (SGDescriptor_t)) {
836 				optimal_sg = CPQARY3_PERF_SG_CNT;
837 			} else {
838 				optimal_sg =
839 				    optimal_sg_size / sizeof (SGDescriptor_t);
840 			}
841 
842 			cpqary3p->sg_cnt = MIN(max_sg_cnt, optimal_sg);
843 
844 			if (cpqary3p->sg_cnt > MAX_PERF_SG_CNT)
845 				cpqary3p->sg_cnt = MAX_PERF_SG_CNT;
846 		}
847 
848 		/* SG */
849 
850 		/*
851 		 * Zero the Upper 32 Address in the Controller
852 		 */
853 
854 		DDI_PUT32(cpqary3p, &ctp->HostWrite.Upper32Addr, 0x00000000);
855 		cpqary3p->heartbeat = DDI_GET32(cpqary3p, &ctp->HeartBeat);
856 
857 		/* Set the controller interrupt check routine */
858 
859 		if (cpqary3p->bddef->bd_is_e200) {
860 			cpqary3p->check_ctlr_intr =
861 			    cpqary3_check_perf_e200_intr;
862 		} else {
863 			cpqary3p->check_ctlr_intr =
864 			    cpqary3_check_perf_ctlr_intr;
865 		}
866 
867 		if ((!cpqary3p->bddef->bd_is_e200) &&
868 		    (!cpqary3p->bddef->bd_is_ssll)) {
869 			cpqary3p->host_support =
870 			    DDI_GET32(cpqary3p, &ctp->HostDrvrSupport);
871 			DDI_PUT32(cpqary3p, &ctp->HostDrvrSupport,
872 			    (cpqary3p->host_support | 0x4));
873 		}
874 		cpqary3p->host_support =
875 		    DDI_GET32(cpqary3p, &ctp->HostDrvrSupport);
876 		cpqary3p->lockup_logged = CPQARY3_FALSE;
877 	}
878 
879 	return (CPQARY3_SUCCESS);
880 }
881 
882 /*
883  * Function	: 	cpqary3_check_ctlr_init
884  * Description	: 	This routine checks to see if the HBA is initialized.
885  * Called By	: 	cpqary3_init_ctlr()
886  * Parameters	: 	per-controller
887  * Calls	: 	None
888  * Return Values: 	SUCCESS / FAILURE
889  */
890 uint8_t
891 cpqary3_check_ctlr_init(cpqary3_t *cpqary3p)
892 {
893 	int8_t				retvalue;
894 	uint16_t			i;
895 	uint32_t			*ctlr_init;
896 	ddi_acc_handle_t		ctlr_init_handle;
897 	extern ddi_device_acc_attr_t	cpqary3_dev_attributes;
898 
899 	RETURN_FAILURE_IF_NULL(cpqary3p);
900 
901 	/*
902 	 * Set up the mapping for a Register at offset 0xB0 from I2O Bar
903 	 * The value 0xB0 taken from the CONFIGM utility.
904 	 * It should read 0xffff0000 if the controller is initialized.
905 	 * if not yet initialized, read it every second for 300 secs.
906 	 * If not set even after 300 secs, return FAILURE.
907 	 * If set, free the mapping and continue
908 	 */
909 	retvalue = ddi_regs_map_setup(cpqary3p->dip, INDEX_PCI_BASE0,
910 	    (caddr_t *)&ctlr_init, (offset_t)I2O_CTLR_INIT, 4,
911 	    &cpqary3_dev_attributes, &ctlr_init_handle);
912 
913 	if (retvalue != DDI_SUCCESS) {
914 		if (DDI_REGS_ACC_CONFLICT == retvalue)
915 			cmn_err(CE_WARN,
916 			    "CPQary3 : HBA Init Register Mapping Conflict");
917 		cmn_err(CE_WARN,
918 		    "CPQary3 : HBA Init Regsiter Mapping Failed");
919 		return (CPQARY3_FAILURE);
920 	}
921 
922 	for (i = 0; i < 300; i++) {	/* loop for 300 seconds */
923 		if (CISS_CTLR_INIT == ddi_get32(ctlr_init_handle, ctlr_init)) {
924 			DTRACE_PROBE(ctlr_init_check_ready);
925 			ddi_regs_map_free(&ctlr_init_handle);
926 			break;
927 		} else {
928 			DTRACE_PROBE(ctlr_init_check_notready);
929 			delay(drv_usectohz(1000000));
930 		}
931 	}
932 
933 	if (i >= 300) {	/* HBA not initialized even after 300 seconds !!! */
934 		ddi_regs_map_free(&ctlr_init_handle);
935 		cmn_err(CE_WARN, "CPQary3 : %s NOT initialized !!! HBA may not "
936 		    "function properly. Please replace the hardware or check "
937 		    "the connections", cpqary3p->hba_name);
938 		return (CPQARY3_FAILURE);
939 	}
940 
941 	return (CPQARY3_SUCCESS);
942 }
943