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
cpqary3_check_simple_ctlr_intr(cpqary3_t * cpqary3p)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
cpqary3_check_perf_ctlr_intr(cpqary3_t * cpqary3p)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
cpqary3_check_perf_e200_intr(cpqary3_t * cpqary3p)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
cpqary3_retrieve(cpqary3_t * cpqary3p)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
cpqary3_poll_retrieve(cpqary3_t * cpqary3p,uint32_t poll_tag)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
cpqary3_submit(cpqary3_t * cpqary3p,uint32_t cmd_phyaddr)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
cpqary3_intr_onoff(cpqary3_t * cpqary3p,uint8_t flag)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
cpqary3_lockup_intr_onoff(cpqary3_t * cpqary3p,uint8_t flag)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
cpqary3_init_ctlr(cpqary3_t * cpqary3p)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
cpqary3_check_ctlr_init(cpqary3_t * cpqary3p)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