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
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.
13 * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
19 * Local Autoconfiguration Function Prototype Declations
22 int cpqary3_attach(dev_info_t
*, ddi_attach_cmd_t
);
23 int cpqary3_detach(dev_info_t
*, ddi_detach_cmd_t
);
24 int cpqary3_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
27 * Local Functions Definitions
30 static void cpqary3_cleanup(cpqary3_t
*, uint32_t);
31 static uint8_t cpqary3_update_ctlrdetails(cpqary3_t
*, uint32_t *);
32 int8_t cpqary3_detect_target_geometry(cpqary3_t
*);
35 * External Variable Definitions
38 extern cpqary3_driver_info_t gdriver_info
;
41 * Global Variables Definitions
44 static char cpqary3_brief
[] = "HP Smart Array Driver";
47 /* HPQaculi Changes */
50 * HBA minor number schema
52 * The minor numbers for any minor device nodes that we create are
53 * governed by the SCSA framework. We use the macros below to
54 * fabricate minor numbers for nodes that we own.
56 * See sys/impl/transport.h for more info.
59 /* Macro to extract interface from minor number */
60 #define CPQARY3_MINOR2INTERFACE(_x) ((_x) & (TRAN_MINOR_MASK))
62 /* Base of range assigned to HBAs: */
63 #define SCSA_MINOR_HBABASE (32)
65 /* Our minor nodes: */
66 #define CPQARY3_MINOR (0 + SCSA_MINOR_HBABASE)
68 /* Convenience macros to convert device instances to minor numbers */
69 #define CPQARY3_INST2x(_i, _x) (((_i) << INST_MINOR_SHIFT) | (_x))
70 #define CPQARY3_INST2CPQARY3(_i) CPQARY3_INST2x(_i, CPQARY3_MINOR)
72 /* HPQacucli Changes */
75 * The Driver DMA Limit structure.
76 * Data used for SMART Integrated Array Controller shall be used.
79 ddi_dma_attr_t cpqary3_dma_attr
= {
80 DMA_ATTR_V0
, /* ddi_dma_attr version */
82 0xFFFFFFFFFFFFFFFF, /* High Address */
83 0x00FFFFFF, /* Max DMA Counter register */
84 0x20, /* Byte Alignment */
85 0x20, /* Burst Sizes : 32 Byte */
86 DMA_UNIT_8
, /* Minimum DMA xfer Size */
87 0xFFFFFFFF, /* Maximum DMA xfer Size */
89 * Segment boundary restrictions
90 * The addr should not cross 4GB boundry.
91 * This is required to address an issue
92 * in the Surge ASIC, with earlier FW versions.
95 CPQARY3_SG_CNT
, /* Scatter/Gather List Length */
96 512, /* Device Granularity */
101 * The Device Access Attribute Structure.
104 ddi_device_acc_attr_t cpqary3_dev_attributes
= {
106 DDI_STRUCTURE_LE_ACC
,
111 * Character-Block Operations Structure
114 static struct cb_ops cpqary3_cb_ops
= {
115 /* HPQacucli Changes */
118 /* HPQacucli Changes */
119 nodev
, /* cb_strategy */
120 nodev
, /* cb_print */
123 nodev
, /* cb_write */
124 cpqary3_ioctl
, /* cb_ioctl */
125 nodev
, /* cb_devmap */
127 nodev
, /* cb_segmap */
128 nochpoll
, /* cb_chpoll */
129 ddi_prop_op
, /* cb_prop_op */
130 NULL
, /* cb_stream */
131 (int)(D_NEW
|D_MP
), /* cb_flag */
138 * Device Operations Structure
141 static struct dev_ops cpqary3_dev_ops
= {
142 DEVO_REV
, /* Driver Build Version */
143 0, /* Driver reference count */
144 nodev
, /* Get Info */
145 nulldev
, /* Identify not required */
146 nulldev
, /* Probe, obselete for s2.6 and up */
147 cpqary3_attach
, /* Attach routine */
148 cpqary3_detach
, /* Detach routine */
150 &cpqary3_cb_ops
, /* Entry Points for C&B drivers */
152 nodev
/* cpqary3_power */
159 static struct modldrv cpqary3_modldrv
= {
160 &mod_driverops
, /* Module Type - driver */
161 cpqary3_brief
, /* Driver Desc */
162 &cpqary3_dev_ops
/* Driver Ops */
165 static struct modlinkage cpqary3_modlinkage
= {
166 MODREV_1
, /* Loadable module rev. no. */
167 &cpqary3_modldrv
, /* Loadable module */
174 * Description : This routine allocates soft state resources for the
175 * driver, registers the HBA with the system and
176 * adds the driver(loadable module).
179 * Return Values: 0 / Non-Zero
180 * [as returned by the mod_install OS function]
188 * Allocate Soft State Resources; if failure, return.
190 retvalue
= ddi_soft_state_init(&cpqary3_state
,
191 sizeof (cpqary3_t
), MAX_CTLRS
);
192 VERIFY(retvalue
== 0);
195 * Initialise the HBA Interface.
197 if (!(retvalue
= scsi_hba_init(&cpqary3_modlinkage
))) {
198 /* Load the driver */
199 if ((retvalue
= mod_install(&cpqary3_modlinkage
))) {
201 * Failed to load the driver, undo HBA interface
202 * and soft state allocation.
204 scsi_hba_fini(&cpqary3_modlinkage
);
205 ddi_soft_state_fini(&cpqary3_state
);
209 * Failed to register HBA interface, undo all soft state
212 ddi_soft_state_fini(&cpqary3_state
);
220 * Description : This routine removes the loadable module, cancels the
221 * HBA registration and deallocates soft state resources.
224 * Return Values: 0 - Success / Non-Zero - Failure
225 * [as returned by the mod_remove(OS provided) function]
232 /* Unload the Driver(loadable module) */
234 if ((retvalue
= mod_remove(&cpqary3_modlinkage
)) == 0) {
236 /* Cancel the registeration for the HBA Interface */
237 scsi_hba_fini(&cpqary3_modlinkage
);
239 /* dealloacte soft state resources of the driver */
240 ddi_soft_state_fini(&cpqary3_state
);
248 * Description : This routine returns information about the driver.
251 * Return Values: 0 / Non-Zero
252 * [as returned by mod_info(OS provided) function]
255 _info(struct modinfo
*modinfop
)
258 * Get the module information.
260 return (mod_info(&cpqary3_modlinkage
, modinfop
));
265 * Function : cpqary3_attach
266 * Description : This routine initializes the driver specific soft state
267 * structure, initializes the HBA, interrupt handlers,
268 * memory pool, timeout handler, various mutex, creates the
271 * Parameters : dip, command for attach
272 * Return Values: DDI_SUCCESS / DDI_FAILURE
273 * [Success on overall initialization & configuration
274 * being successful. Failure if any of the initialization
275 * or any driver-specific mandatory configuration fails]
278 cpqary3_attach(dev_info_t
*dip
, ddi_attach_cmd_t attach_cmd
)
280 int8_t minor_node_name
[14];
283 uint32_t cleanstatus
= 0;
284 cpqary3_t
*cpqary3p
; /* per-controller */
285 ddi_dma_attr_t tmp_dma_attr
;
287 /* Return Failure, If the Command is other than - DDI_ATTACH. */
289 if (attach_cmd
!= DDI_ATTACH
)
290 return (DDI_FAILURE
);
292 /* Get the Instance of the Device */
294 instance
= ddi_get_instance(dip
);
296 /* Allocate the per-device-instance soft state structure */
298 retvalue
= ddi_soft_state_zalloc(cpqary3_state
, instance
);
299 VERIFY(retvalue
== 0);
301 cleanstatus
|= CPQARY3_SOFTSTATE_ALLOC_DONE
;
303 /* Per Controller Pointer */
304 cpqary3p
= ddi_get_soft_state(cpqary3_state
, instance
);
306 cmn_err(CE_WARN
, "CPQary3: Soft State Retrieval Failed");
307 cpqary3_cleanup(cpqary3p
, cleanstatus
);
308 return (DDI_FAILURE
);
311 /* Maintain a record in per-ctlr structure */
313 cpqary3p
->instance
= instance
;
315 /* Get the User Configuration information from Driver's conf File */
316 cpqary3_read_conf_file(dip
, cpqary3p
);
318 /* Get and Map the HW Configuration */
319 retvalue
= cpqary3_update_ctlrdetails(cpqary3p
, &cleanstatus
);
320 if (retvalue
== CPQARY3_FAILURE
) {
321 cpqary3_cleanup(cpqary3p
, cleanstatus
);
322 return (DDI_FAILURE
);
325 /* Get the Cookie for hardware Interrupt Handler */
326 if (ddi_get_iblock_cookie(dip
, 0, &cpqary3p
->hw_iblock_cookie
) !=
328 cpqary3_cleanup(cpqary3p
, cleanstatus
);
329 return (DDI_FAILURE
);
332 /* Initialize Per Controller Mutex */
333 mutex_init(&cpqary3p
->hw_mutex
, NULL
, MUTEX_DRIVER
,
334 (void *)cpqary3p
->hw_iblock_cookie
);
336 cleanstatus
|= CPQARY3_MUTEX_INIT_DONE
;
338 /* Get the Cookie for Soft(low level) Interrupt Handler */
339 if (ddi_get_soft_iblock_cookie(dip
, DDI_SOFTINT_HIGH
,
340 &cpqary3p
->sw_iblock_cookie
) != DDI_SUCCESS
) {
341 cpqary3_cleanup(cpqary3p
, cleanstatus
);
342 return (DDI_FAILURE
);
345 /* Initialize the s/w Mutex */
346 mutex_init(&cpqary3p
->sw_mutex
, NULL
, MUTEX_DRIVER
,
347 (void *)cpqary3p
->sw_iblock_cookie
);
348 cleanstatus
|= CPQARY3_SW_MUTEX_INIT_DONE
;
350 /* Initialize per Controller private details */
351 retvalue
= cpqary3_init_ctlr_resource(cpqary3p
);
352 if (retvalue
!= CPQARY3_SUCCESS
) {
353 cpqary3_cleanup(cpqary3p
, cleanstatus
);
354 return (DDI_FAILURE
);
356 cleanstatus
|= CPQARY3_CTLR_CONFIG_DONE
;
359 * Allocate HBA transport structure
361 cpqary3p
->hba_tran
= scsi_hba_tran_alloc(dip
, SCSI_HBA_CANSLEEP
);
362 if (!cpqary3p
->hba_tran
) {
363 cpqary3_cleanup(cpqary3p
, cleanstatus
);
364 return (DDI_FAILURE
);
366 cleanstatus
|= CPQARY3_HBA_TRAN_ALLOC_DONE
;
369 * Set private field for the HBA tran structure.
370 * Initialise the HBA tran entry points.
371 * Attach the controller to HBA.
373 cpqary3_init_hbatran(cpqary3p
);
377 tmp_dma_attr
= cpqary3_dma_attr
;
378 tmp_dma_attr
.dma_attr_sgllen
= cpqary3p
->sg_cnt
;
382 * Register the DMA attributes and the transport vectors
383 * of each instance of the HBA device.
385 if (scsi_hba_attach_setup(dip
, &tmp_dma_attr
, cpqary3p
->hba_tran
,
386 SCSI_HBA_TRAN_CLONE
) == DDI_FAILURE
) {
387 cpqary3_cleanup(cpqary3p
, cleanstatus
);
388 return (DDI_FAILURE
);
390 cleanstatus
|= CPQARY3_HBA_TRAN_ATTACH_DONE
;
393 * Create a minor node for Ioctl interface.
394 * The nomenclature used will be "cpqary3" immediately followed by
395 * the current driver instance in the system.
396 * for e.g.: for 0th instance : cpqary3,0
397 * for 1st instance : cpqary3,1
400 (void) sprintf(minor_node_name
, "cpqary3,%d", instance
);
402 /* HPQacucli Changes */
403 if (ddi_create_minor_node(dip
, minor_node_name
, S_IFCHR
,
404 CPQARY3_INST2CPQARY3(instance
), DDI_NT_SCSI_NEXUS
, 0) ==
406 /* HPQacucli Changes */
407 cleanstatus
|= CPQARY3_CREATE_MINOR_NODE
;
409 cmn_err(CE_NOTE
, "CPQary3 : Failed to create minor node");
410 cpqary3_cleanup(cpqary3p
, cleanstatus
);
411 return (DDI_FAILURE
);
415 /* Register a timeout driver-routine to be called every 2 secs */
416 cpqary3p
->tick_tmout_id
= timeout(cpqary3_tick_hdlr
,
417 (caddr_t
)cpqary3p
, drv_usectohz(CPQARY3_TICKTMOUT_VALUE
));
418 cleanstatus
|= CPQARY3_TICK_TMOUT_REGD
;
420 /* Register Software Interrupt Handler */
421 if (ddi_add_softintr(dip
, DDI_SOFTINT_HIGH
,
422 &cpqary3p
->cpqary3_softintr_id
, &cpqary3p
->sw_iblock_cookie
, NULL
,
423 cpqary3_sw_isr
, (caddr_t
)cpqary3p
) != DDI_SUCCESS
) {
424 cpqary3_cleanup(cpqary3p
, cleanstatus
);
425 return (DDI_FAILURE
);
427 cleanstatus
|= CPQARY3_SW_INTR_HDLR_SET
;
429 /* Register Interrupt Handler */
430 if (ddi_add_intr(dip
, 0, &cpqary3p
->hw_iblock_cookie
, NULL
,
431 cpqary3_hw_isr
, (caddr_t
)cpqary3p
) != DDI_SUCCESS
) {
432 cpqary3_cleanup(cpqary3p
, cleanstatus
);
433 return (DDI_FAILURE
);
435 cleanstatus
|= CPQARY3_INTR_HDLR_SET
;
437 /* Enable the Controller Interrupt */
438 cpqary3_intr_onoff(cpqary3p
, CPQARY3_INTR_ENABLE
);
439 if (cpqary3p
->host_support
& 0x4)
440 cpqary3_lockup_intr_onoff(cpqary3p
, CPQARY3_LOCKUP_INTR_ENABLE
);
443 * We have come with hmaeventd - which logs the storage events on
444 * console as well as in IML. So we are commenting the NOE support in
449 if (cpqary3p
->noe_support
== 1) {
450 /* Enable the Notification on Event in this controller */
451 if (CPQARY3_SUCCESS
==
452 cpqary3_send_NOE_command(cpqary3p
,
453 NULL
, CPQARY3_NOE_INIT
)) {
454 cleanstatus
|= CPQARY3_NOE_INIT_DONE
;
456 cmn_err(CE_CONT
, "CPQary3 : Failed to initialize "
457 "NOTIFICATION ON EVENT \n");
462 /* Report that an Instance of the Driver is Attached Successfully */
466 * Now update the num_ctlr
467 * This is required for the agents
470 gdriver_info
.num_ctlr
++;
472 return (DDI_SUCCESS
);
477 * Function : cpqary3_detach
478 * Description : This routine removes the state associated with a
479 * given instance of a device node prior to the
480 * removal of that instance from the system
482 * Parameters : dip, command for detach
483 * Return Values: DDI_SUCCESS / DDI_FAILURE
484 * [failure ONLY if the command sent with this function
485 * as a paramter is not DETACH]
488 cpqary3_detach(dev_info_t
*dip
, ddi_detach_cmd_t detach_cmd
)
491 scsi_hba_tran_t
*hba_tran
;
493 /* Return failure, If Command is not DDI_DETACH */
495 if (DDI_DETACH
!= detach_cmd
)
496 return (DDI_FAILURE
);
499 * Get scsi_hba_tran structure.
500 * Get per controller structure.
503 hba_tran
= (scsi_hba_tran_t
*)ddi_get_driver_private(dip
);
504 cpqary3p
= (cpqary3_t
*)hba_tran
->tran_hba_private
;
506 /* Flush the cache */
508 cpqary3_flush_cache(cpqary3p
);
510 /* Undo cpqary3_attach */
512 cpqary3_cleanup(cpqary3p
, CPQARY3_CLEAN_ALL
);
514 return (DDI_SUCCESS
);
519 * Function : cpary3_ioctl
520 * Description : This routine services ioctl requests.
522 * Parameters : Too many to list. Please look below !!!
523 * Return Values: 0 / EINVAL / EFAULT /
524 * [0 on normal successful completion of the ioctl
528 cpqary3_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
,
531 minor_t cpqary3_minor_num
;
536 * Get the soft state structure for this instance
537 * Return ENODEV if the structure does not exist.
541 * minor() call used in cpqary3_ioctl() returns minor number of the
542 * device which are in the
543 * range 0-255. if the minor number of the device is greater than 255,
544 * data will get truncated. so we are now using getminor(),
548 if (EINVAL
== (cpqary3_minor_num
= getminor(dev
))) {
553 /* HPQacucli Changes */
556 instance
= MINOR2INST(cpqary3_minor_num
);
558 cpqary3p
= (cpqary3_t
*)ddi_get_soft_state(cpqary3_state
, instance
);
560 /* HPQacucli Changes */
567 /* HPQacucli Changes */
569 /* check which interface is being requested */
570 if (CPQARY3_MINOR2INTERFACE(cpqary3_minor_num
) != CPQARY3_MINOR
) {
572 return (scsi_hba_ioctl(dev
, cmd
, arg
, mode
, credp
, retvaluep
));
575 /* HPQacucli Changes */
578 case CPQARY3_IOCTL_DRIVER_INFO
:
580 cpqary3_ioctl_driver_info(arg
, mode
);
583 case CPQARY3_IOCTL_CTLR_INFO
:
585 cpqary3_ioctl_ctlr_info(arg
, cpqary3p
, mode
);
588 case CPQARY3_IOCTL_BMIC_PASS
:
590 cpqary3_ioctl_bmic_pass(arg
, cpqary3p
, mode
);
593 case CPQARY3_IOCTL_SCSI_PASS
:
595 cpqary3_ioctl_scsi_pass(arg
, cpqary3p
, mode
);
609 * Function : cqpary3_cleanup
610 * Description : This routine frees all allocated resources.
612 * Parameters : per-controller, bit-map(stating what all to clean)
613 * Return Values: None
616 cpqary3_cleanup(cpqary3_t
*cpqary3p
, uint32_t status
)
618 int8_t node_name
[10];
619 clock_t cpqary3_lbolt
;
622 ASSERT(cpqary3p
!= NULL
);
625 * Disable the NOE command
626 * Free the Command Memory Pool
627 * destroy all conditional variables
631 * We have removed NOE functionality from the
632 * driver. So commenting the below piece of code
635 if (status
& CPQARY3_NOE_INIT_DONE
) {
636 if (CPQARY3_SUCCESS
== cpqary3_disable_NOE_command(cpqary3p
)) {
637 mutex_enter(&cpqary3p
->hw_mutex
);
638 cpqary3_lbolt
= ddi_get_lbolt();
640 cv_timedwait_sig(&cpqary3p
->cv_noe_wait
,
642 cpqary3_lbolt
+ drv_usectohz(3000000))) {
644 "CPQary3: Resume signal for disable NOE "
645 "command not received \n");
647 mutex_exit(&cpqary3p
->hw_mutex
);
653 * Free / Release / Destroy the following entities/resources:
655 * h/w & s/w interrupt handlers
661 * any register/memory mapping
664 if (status
& CPQARY3_INTR_HDLR_SET
)
665 ddi_remove_intr(cpqary3p
->dip
, 0, cpqary3p
->hw_iblock_cookie
);
667 if (status
& CPQARY3_SW_INTR_HDLR_SET
)
668 ddi_remove_softintr(cpqary3p
->cpqary3_softintr_id
);
670 if ((status
& CPQARY3_TICK_TMOUT_REGD
) && cpqary3p
->tick_tmout_id
) {
671 VERIFY(untimeout(cpqary3p
->tick_tmout_id
) >= 0);
672 cpqary3p
->tick_tmout_id
= NULL
;
675 if (status
& CPQARY3_CREATE_MINOR_NODE
) {
676 (void) sprintf(node_name
, "cpqary3%d", cpqary3p
->instance
);
677 ddi_remove_minor_node(cpqary3p
->dip
, node_name
);
680 if (status
& CPQARY3_HBA_TRAN_ATTACH_DONE
)
681 (void) scsi_hba_detach(cpqary3p
->dip
);
683 if (status
& CPQARY3_HBA_TRAN_ALLOC_DONE
)
684 scsi_hba_tran_free(cpqary3p
->hba_tran
);
686 if (status
& CPQARY3_CTLR_CONFIG_DONE
) {
687 mutex_enter(&cpqary3p
->hw_mutex
);
689 cv_destroy(&cpqary3p
->cv_abort_wait
);
690 cv_destroy(&cpqary3p
->cv_flushcache_wait
);
691 cv_destroy(&cpqary3p
->cv_noe_wait
);
692 cv_destroy(&cpqary3p
->cv_immediate_wait
);
693 cv_destroy(&cpqary3p
->cv_ioctl_wait
);
695 for (targ
= 0; targ
< CPQARY3_MAX_TGT
; targ
++) {
696 if (cpqary3p
->cpqary3_tgtp
[targ
] == NULL
)
698 MEM_SFREE(cpqary3p
->cpqary3_tgtp
[targ
],
699 sizeof (cpqary3_tgt_t
));
702 mutex_exit(&cpqary3p
->hw_mutex
);
704 cpqary3_memfini(cpqary3p
, CPQARY3_MEMLIST_DONE
|
705 CPQARY3_PHYCTGS_DONE
| CPQARY3_CMDMEM_DONE
);
708 if (status
& CPQARY3_SW_MUTEX_INIT_DONE
)
709 mutex_destroy(&cpqary3p
->sw_mutex
);
711 if (status
& CPQARY3_MUTEX_INIT_DONE
)
712 mutex_destroy(&cpqary3p
->hw_mutex
);
715 * If this flag is set, free all mapped registers
717 if (status
& CPQARY3_MEM_MAPPED
) {
718 if (cpqary3p
->idr_handle
)
719 ddi_regs_map_free(&cpqary3p
->idr_handle
);
720 if (cpqary3p
->isr_handle
)
721 ddi_regs_map_free(&cpqary3p
->isr_handle
);
722 if (cpqary3p
->imr_handle
)
723 ddi_regs_map_free(&cpqary3p
->imr_handle
);
724 if (cpqary3p
->ipq_handle
)
725 ddi_regs_map_free(&cpqary3p
->ipq_handle
);
726 if (cpqary3p
->opq_handle
)
727 ddi_regs_map_free(&cpqary3p
->opq_handle
);
728 if (cpqary3p
->ct_handle
)
729 ddi_regs_map_free(&cpqary3p
->ct_handle
);
732 if (status
& CPQARY3_SOFTSTATE_ALLOC_DONE
) {
733 ddi_soft_state_free(cpqary3_state
,
734 ddi_get_instance(cpqary3p
->dip
));
739 * Function : cpqary3_update_ctlrdetails
740 * Description : Performs Sanity check of the hw, Updates PCI Config
741 * Information, Verifies the supported board-id and
742 * Sets up a mapping for the Primary I2O Memory BAR and
743 * the Primary DRAM 1 BAR to access Host Interface
744 * registers and the Transport Configuration table.
745 * Called By : cpqary3_attach()
746 * Parameters : per-controller, bitmap (used for cleaning operations)
747 * Return Values: SUCCESS / FAILURE
748 * [Success / failure depending upon the outcome of all
749 * checks and mapping. If any of them fail, a failure is
753 cpqary3_update_ctlrdetails(cpqary3_t
*cpqary3p
, uint32_t *cleanstatus
)
756 uint8_t mem_bar0_set
= 0;
757 uint8_t mem_64_bar0_set
= 0;
758 uint8_t mem_bar1_set
= 0;
759 uint8_t mem_64_bar1_set
= 0;
762 uint32_t mem_bar0
= 0;
763 uint32_t mem_64_bar0
;
764 uint32_t mem_bar1
= 0;
765 uint32_t mem_64_bar1
= 0;
766 uint32_t ct_mem_bar
= 0;
767 uint32_t ct_cfgmem_val
= 0;
768 uint32_t ct_memoff_val
= 0;
769 uint32_t ct_cfg_bar
= 0;
770 uint32_t ct_mem_len
= 0;
771 offset_t map_len
= 0;
772 uint32_t regset_index
;
773 ddi_acc_handle_t pci_handle
;
774 uint32_t *ct_cfg_offset
;
775 ddi_acc_handle_t ct_cfgoff_handle
;
776 uint32_t *ct_mem_offset
;
777 ddi_acc_handle_t ct_memoff_handle
;
779 RETURN_FAILURE_IF_NULL(cpqary3p
);
782 * Check if the bus, or part of the bus that the device is installed
783 * on, permits the device to become a DMA master.
784 * If our device is not permitted to become master, return
786 if (ddi_slaveonly(cpqary3p
->dip
) == DDI_SUCCESS
)
787 return (CPQARY3_FAILURE
);
790 * Get the HW Configuration
791 * Get Bus #, Dev # and Func # for this device
792 * Free the memory that regp points towards after the
793 * ddi_getlongprop() call
795 if (ddi_getlongprop(DDI_DEV_T_NONE
, cpqary3p
->dip
, DDI_PROP_DONTPASS
,
796 "reg", (caddr_t
)®p
, ®len
) != DDI_PROP_SUCCESS
)
797 return (CPQARY3_FAILURE
);
799 cpqary3p
->bus
= PCI_REG_BUS_G(*regp
);
800 cpqary3p
->dev
= PCI_REG_DEV_G(*regp
);
801 cpqary3p
->fun
= PCI_REG_FUNC_G(*regp
);
803 for (regset_index
= 0; regset_index
< reglen
/ 20; regset_index
++) {
804 if (PCI_REG_ADDR_G(*(regp
+ regset_index
* 5)) == 0x2) {
806 mem_bar0
= regset_index
;
808 } else if (!mem_bar1_set
) {
809 mem_bar1
= regset_index
;
815 mem_64_bar0
= mem_bar0
;
816 mem_64_bar1
= mem_bar1
;
818 for (regset_index
= 0; regset_index
< reglen
/ 20; regset_index
++) {
819 if (PCI_REG_ADDR_G(*(regp
+ regset_index
* 5)) == 0x3) {
820 if (!mem_64_bar0_set
) {
821 mem_64_bar0
= regset_index
;
823 } else if (!mem_64_bar1_set
) {
824 mem_64_bar1
= regset_index
;
830 mem_bar0
= mem_64_bar0
;
831 mem_bar1
= mem_64_bar1
;
833 MEM_SFREE(regp
, reglen
);
836 * Setup resources to access the Local PCI Bus
837 * If unsuccessful, return.
838 * Else, read the following from the PCI space:
839 * Sub-System Vendor ID
840 * Sub-System Device ID
843 * Free the just allocated resources.
845 if (pci_config_setup(cpqary3p
->dip
, &pci_handle
) != DDI_SUCCESS
)
846 return (CPQARY3_FAILURE
);
848 cpqary3p
->irq
= pci_config_get8(pci_handle
, PCI_CONF_ILINE
);
850 (pci_config_get16(pci_handle
, PCI_CONF_SUBVENID
) << 16)
851 | pci_config_get16(pci_handle
, PCI_CONF_SUBSYSID
);
853 pci_config_teardown(&pci_handle
);
857 * If unsupported boards are detected, return.
858 * Update name for controller for driver use.
860 cpqary3p
->bddef
= cpqary3_bd_getbybid(cpqary3p
->board_id
);
861 if (cpqary3p
->bddef
== NULL
) {
863 "CPQary3: <Bid 0x%X> Controller NOT Supported",
865 return (CPQARY3_FAILURE
);
867 map_len
= cpqary3p
->bddef
->bd_maplen
;
868 (void) strcpy(cpqary3p
->hba_name
, cpqary3p
->bddef
->bd_dispname
);
871 * Set up a mapping for the following registers:
873 * Outbound List Status
874 * Outbound Interrupt Mask
876 * Host Outbound Queue
877 * Host Transport Configuration Table
878 * Mapping of the above has been done in that order.
880 retvalue
= ddi_regs_map_setup(cpqary3p
->dip
,
881 mem_bar0
, /* INDEX_PCI_BASE0, */
882 (caddr_t
*)&cpqary3p
->idr
, (offset_t
)I2O_IBDB_SET
, map_len
,
883 &cpqary3_dev_attributes
, &cpqary3p
->idr_handle
);
885 if (retvalue
!= DDI_SUCCESS
) {
886 if (DDI_REGS_ACC_CONFLICT
== retvalue
) {
888 "CPQary3 : Registers Mapping Conflict");
890 cmn_err(CE_WARN
, "CPQary3 : Inbound Doorbell "
891 "Register Mapping Failed");
892 return (CPQARY3_FAILURE
);
896 retvalue
= ddi_regs_map_setup(cpqary3p
->dip
,
897 mem_bar0
, /* INDEX_PCI_BASE0, */
898 (caddr_t
*)&cpqary3p
->odr
, (offset_t
)I2O_OBDB_STATUS
, map_len
,
899 &cpqary3_dev_attributes
, &cpqary3p
->odr_handle
);
901 if (retvalue
!= DDI_SUCCESS
) {
902 if (DDI_REGS_ACC_CONFLICT
== retvalue
) {
904 "CPQary3 : Registers Mapping Conflict");
907 "CPQary3 : Outbound Doorbell Register Mapping Failed");
908 return (CPQARY3_FAILURE
);
911 retvalue
= ddi_regs_map_setup(cpqary3p
->dip
,
912 mem_bar0
, /* INDEX_PCI_BASE0, */
913 (caddr_t
*)&cpqary3p
->odr_cl
, (offset_t
)I2O_OBDB_CLEAR
, map_len
,
914 &cpqary3_dev_attributes
, &cpqary3p
->odr_cl_handle
);
916 if (retvalue
!= DDI_SUCCESS
) {
917 if (DDI_REGS_ACC_CONFLICT
== retvalue
) {
919 "CPQary3 : Registers Mapping Conflict");
921 cmn_err(CE_WARN
, "CPQary3 : Outbound Doorbell "
922 "Register Clear Mapping Failed");
923 return (CPQARY3_FAILURE
);
927 retvalue
= ddi_regs_map_setup(cpqary3p
->dip
,
928 mem_bar0
, /* INDEX_PCI_BASE0, */
929 (caddr_t
*)&cpqary3p
->spr0
, (offset_t
)I2O_CTLR_INIT
, map_len
,
930 &cpqary3_dev_attributes
, &cpqary3p
->spr0_handle
);
932 if (retvalue
!= DDI_SUCCESS
) {
933 if (DDI_REGS_ACC_CONFLICT
== retvalue
) {
935 "CPQary3 : Registers Mapping Conflict");
938 "CPQary3 : Scratch Pad register zero Mapping Failed");
939 return (CPQARY3_FAILURE
);
944 *cleanstatus
|= CPQARY3_MEM_MAPPED
;
946 retvalue
= ddi_regs_map_setup(cpqary3p
->dip
,
947 mem_bar0
, /* INDEX_PCI_BASE0, */
948 (caddr_t
*)&cpqary3p
->isr
, (offset_t
)I2O_INT_STATUS
, map_len
,
949 &cpqary3_dev_attributes
, &cpqary3p
->isr_handle
);
951 if (retvalue
!= DDI_SUCCESS
) {
952 if (retvalue
== DDI_REGS_ACC_CONFLICT
) {
954 "CPQary3 : Registers Mapping Conflict");
957 "CPQary3 : Interrupt Status Register Mapping Failed");
958 return (CPQARY3_FAILURE
);
961 retvalue
= ddi_regs_map_setup(cpqary3p
->dip
,
962 mem_bar0
, /* INDEX_PCI_BASE0, */
963 (caddr_t
*)&cpqary3p
->imr
, (offset_t
)I2O_INT_MASK
, map_len
,
964 &cpqary3_dev_attributes
, &cpqary3p
->imr_handle
);
966 if (retvalue
!= DDI_SUCCESS
) {
967 if (retvalue
== DDI_REGS_ACC_CONFLICT
) {
969 "CPQary3 : Registers Mapping Conflict");
972 "CPQary3 : Interrupt Mask Register Mapping Failed");
973 return (CPQARY3_FAILURE
);
976 retvalue
= ddi_regs_map_setup(cpqary3p
->dip
,
977 mem_bar0
, /* INDEX_PCI_BASE0, */
978 (caddr_t
*)&cpqary3p
->ipq
, (offset_t
)I2O_IBPOST_Q
, map_len
,
979 &cpqary3_dev_attributes
, &cpqary3p
->ipq_handle
);
981 if (retvalue
!= DDI_SUCCESS
) {
982 if (retvalue
== DDI_REGS_ACC_CONFLICT
) {
984 "CPQary3 : Registers Mapping Conflict");
987 "CPQary3 : Inbound Queue Register Mapping Failed");
988 return (CPQARY3_FAILURE
);
991 retvalue
= ddi_regs_map_setup(cpqary3p
->dip
,
992 mem_bar0
, /* INDEX_PCI_BASE0, */ (caddr_t
*)&cpqary3p
->opq
,
993 (offset_t
)I2O_OBPOST_Q
, map_len
, &cpqary3_dev_attributes
,
994 &cpqary3p
->opq_handle
);
996 if (retvalue
!= DDI_SUCCESS
) {
997 if (retvalue
== DDI_REGS_ACC_CONFLICT
) {
999 "CPQary3 : Registers Mapping Conflict");
1001 cmn_err(CE_WARN
, "CPQary3 : Outbound Post Queue "
1002 "Register Mapping Failed");
1003 return (CPQARY3_FAILURE
);
1008 * The config offset and memory offset have to be obtained in order to
1009 * locate the config table.
1011 retvalue
= ddi_regs_map_setup(cpqary3p
->dip
,
1012 mem_bar0
, /* INDEX_PCI_BASE0, */ (caddr_t
*)&ct_cfg_offset
,
1013 (offset_t
)CT_CFG_OFFSET
, map_len
, &cpqary3_dev_attributes
,
1016 if (retvalue
!= DDI_SUCCESS
) {
1017 if (retvalue
== DDI_REGS_ACC_CONFLICT
) {
1019 "CPQary3 : Registers Mapping Conflict");
1021 cmn_err(CE_WARN
, "CPQary3 : Configuration Table "
1022 "Register Mapping Failed");
1023 return (CPQARY3_FAILURE
);
1026 retvalue
= ddi_regs_map_setup(cpqary3p
->dip
,
1027 mem_bar0
, /* INDEX_PCI_BASE0, */
1028 (caddr_t
*)&ct_mem_offset
, (offset_t
)CT_MEM_OFFSET
, map_len
,
1029 &cpqary3_dev_attributes
, &ct_memoff_handle
);
1031 if (retvalue
!= DDI_SUCCESS
) {
1032 if (retvalue
== DDI_REGS_ACC_CONFLICT
) {
1034 "CPQary3 : Registers Mapping Conflict");
1036 cmn_err(CE_WARN
, "CPQary3 : Configuration Table "
1037 "Register Mapping Failed");
1038 return (CPQARY3_FAILURE
);
1041 ct_cfgmem_val
= (uint32_t)ddi_get32(ct_cfgoff_handle
, ct_cfg_offset
);
1042 ct_memoff_val
= (uint32_t)ddi_get32(ct_memoff_handle
, ct_mem_offset
);
1044 ddi_regs_map_free(&ct_cfgoff_handle
);
1045 ddi_regs_map_free(&ct_memoff_handle
);
1047 ct_cfg_bar
= (ct_cfgmem_val
& 0x0000ffff);
1048 ct_mem_len
= (ct_cfgmem_val
& 0xffff0000);
1049 ct_mem_len
= (ct_mem_len
>> 16);
1051 if (ct_cfg_bar
== 0x10) {
1053 ct_mem_bar
= mem_64_bar0
;
1055 ct_mem_bar
= mem_bar0
;
1058 } else if (ct_cfg_bar
== 0x14) {
1060 ct_mem_bar
= mem_64_bar1
;
1062 ct_mem_bar
= mem_bar1
;
1065 return (CPQARY3_FAILURE
);
1070 * The Configuration Table(CT) shall be mapped in the form of a
1071 * structure since several members in the CT need to be accessed
1072 * to read and write.
1074 retvalue
= ddi_regs_map_setup(cpqary3p
->dip
,
1075 ct_mem_bar
, /* INDEX_PCI_BASE0/1, */
1076 (caddr_t
*)&cpqary3p
->ct
, (offset_t
)ct_memoff_val
,
1077 sizeof (CfgTable_t
), &cpqary3_dev_attributes
, &cpqary3p
->ct_handle
);
1079 if (retvalue
!= DDI_SUCCESS
) {
1080 if (retvalue
== DDI_REGS_ACC_CONFLICT
) {
1082 "CPQary3 : Registers Mapping Conflict");
1084 cmn_err(CE_WARN
, "CPQary3 : Configuration Table "
1085 "Register Mapping Failed");
1086 return (CPQARY3_FAILURE
);
1091 retvalue
= ddi_regs_map_setup(cpqary3p
->dip
,
1092 ct_mem_bar
, /* INDEX_PCI_BASE0/1, */
1093 (caddr_t
*)&cpqary3p
->cp
,
1094 (offset_t
)(ct_memoff_val
+ cpqary3p
->ct
->TransportMethodOffset
),
1095 sizeof (CfgTrans_Perf_t
), &cpqary3_dev_attributes
,
1096 &cpqary3p
->cp_handle
);
1098 if (retvalue
!= DDI_SUCCESS
) {
1099 if (retvalue
== DDI_REGS_ACC_CONFLICT
)
1101 "CPQary3 : Registers Mapping Conflict");
1102 cmn_err(CE_WARN
, "CPQary3 : Performant Transport Method Table "
1104 return (CPQARY3_FAILURE
);
1109 return (CPQARY3_SUCCESS
);