1*80c94ecdSKeith M Wesolowski /*
2*80c94ecdSKeith M Wesolowski  * This file and its contents are supplied under the terms of the
3*80c94ecdSKeith M Wesolowski  * Common Development and Distribution License ("CDDL"), version 1.0.
4*80c94ecdSKeith M Wesolowski  * You may only use this file in accordance with the terms of version
5*80c94ecdSKeith M Wesolowski  * 1.0 of the CDDL.
6*80c94ecdSKeith M Wesolowski  *
7*80c94ecdSKeith M Wesolowski  * A full copy of the text of the CDDL should have accompanied this
8*80c94ecdSKeith M Wesolowski  * source.  A copy of the CDDL is also available via the Internet at
9*80c94ecdSKeith M Wesolowski  * http://www.illumos.org/license/CDDL.
10*80c94ecdSKeith M Wesolowski  */
11*80c94ecdSKeith M Wesolowski 
12*80c94ecdSKeith M Wesolowski /*
13*80c94ecdSKeith M Wesolowski  * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
14*80c94ecdSKeith M Wesolowski  */
15*80c94ecdSKeith M Wesolowski 
16*80c94ecdSKeith M Wesolowski #include <sys/sdt.h>
17*80c94ecdSKeith M Wesolowski #include "cpqary3.h"
18*80c94ecdSKeith M Wesolowski 
19*80c94ecdSKeith M Wesolowski /*
20*80c94ecdSKeith M Wesolowski  * Local Functions Definitions
21*80c94ecdSKeith M Wesolowski  */
22*80c94ecdSKeith M Wesolowski 
23*80c94ecdSKeith M Wesolowski int cpqary3_target_geometry(struct scsi_address *);
24*80c94ecdSKeith M Wesolowski int8_t cpqary3_detect_target_geometry(cpqary3_t *);
25*80c94ecdSKeith M Wesolowski 
26*80c94ecdSKeith M Wesolowski /*
27*80c94ecdSKeith M Wesolowski  * Function	: 	cpqary3_read_conf_file
28*80c94ecdSKeith M Wesolowski  * Description	: 	This routine reads the driver configuration file.
29*80c94ecdSKeith M Wesolowski  * Called By	: 	cpqary3_attach()
30*80c94ecdSKeith M Wesolowski  * Parameters	: 	device-information pointer, per_controller
31*80c94ecdSKeith M Wesolowski  * Calls	: 	None
32*80c94ecdSKeith M Wesolowski  * Return Values: 	None
33*80c94ecdSKeith M Wesolowski  */
34*80c94ecdSKeith M Wesolowski void
cpqary3_read_conf_file(dev_info_t * dip,cpqary3_t * cpqary3p)35*80c94ecdSKeith M Wesolowski cpqary3_read_conf_file(dev_info_t *dip, cpqary3_t *cpqary3p)
36*80c94ecdSKeith M Wesolowski {
37*80c94ecdSKeith M Wesolowski 	char		*ptr;
38*80c94ecdSKeith M Wesolowski 
39*80c94ecdSKeith M Wesolowski 	cpqary3p->noe_support = 0;
40*80c94ecdSKeith M Wesolowski 
41*80c94ecdSKeith M Wesolowski 	/*
42*80c94ecdSKeith M Wesolowski 	 * Plugin the code necessary to read from driver's conf file.
43*80c94ecdSKeith M Wesolowski 	 * As of now, we are not interested in reading the onf file
44*80c94ecdSKeith M Wesolowski 	 * for any purpose.
45*80c94ecdSKeith M Wesolowski 	 *
46*80c94ecdSKeith M Wesolowski 	 * eg. :
47*80c94ecdSKeith M Wesolowski 	 *
48*80c94ecdSKeith M Wesolowski 	 * retvalue = ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
49*80c94ecdSKeith M Wesolowski 	 *	"cpqary3_online_debug", -1);
50*80c94ecdSKeith M Wesolowski 	 */
51*80c94ecdSKeith M Wesolowski 
52*80c94ecdSKeith M Wesolowski 	/*
53*80c94ecdSKeith M Wesolowski 	 *  We are calling ddi_prop_lookup_string
54*80c94ecdSKeith M Wesolowski 	 *  which gets the property value, which is passed at
55*80c94ecdSKeith M Wesolowski 	 *  the grub menu. If the user wants to use the older
56*80c94ecdSKeith M Wesolowski 	 *  target mapping algorithm,(prior to 1.80)at the grub menu
57*80c94ecdSKeith M Wesolowski 	 *  "cpqary3_tgtmap=off" should be entered. if this
58*80c94ecdSKeith M Wesolowski 	 *  string is entered, then we will set the
59*80c94ecdSKeith M Wesolowski 	 *  value of the variable legacy_mapping to one, which
60*80c94ecdSKeith M Wesolowski 	 *  will be used in
61*80c94ecdSKeith M Wesolowski 	 *  cpqary3_detect_target_geometry()
62*80c94ecdSKeith M Wesolowski 	 *  and cpqary3_probe4LVs(), to decide on the
63*80c94ecdSKeith M Wesolowski 	 *  mapping algorithm
64*80c94ecdSKeith M Wesolowski 	 */
65*80c94ecdSKeith M Wesolowski 
66*80c94ecdSKeith M Wesolowski 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
67*80c94ecdSKeith M Wesolowski 	    "cpqary3_tgtmap", &ptr) == DDI_PROP_SUCCESS) {
68*80c94ecdSKeith M Wesolowski 		if (strcmp("off", ptr) == 0) {
69*80c94ecdSKeith M Wesolowski 			cpqary3p->legacy_mapping = 1;
70*80c94ecdSKeith M Wesolowski 		}
71*80c94ecdSKeith M Wesolowski 		ddi_prop_free(ptr);
72*80c94ecdSKeith M Wesolowski 	}
73*80c94ecdSKeith M Wesolowski 
74*80c94ecdSKeith M Wesolowski 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
75*80c94ecdSKeith M Wesolowski 	    "cpqary3_noesupport", &ptr) == DDI_PROP_SUCCESS) {
76*80c94ecdSKeith M Wesolowski 		if (strcmp("on", ptr) == 0) {
77*80c94ecdSKeith M Wesolowski 			cpqary3p->noe_support = 1;
78*80c94ecdSKeith M Wesolowski 		}
79*80c94ecdSKeith M Wesolowski 		if (strcmp("off", ptr) == 0) {
80*80c94ecdSKeith M Wesolowski 			cpqary3p->noe_support = 0;
81*80c94ecdSKeith M Wesolowski 		}
82*80c94ecdSKeith M Wesolowski 		ddi_prop_free(ptr);
83*80c94ecdSKeith M Wesolowski 	}
84*80c94ecdSKeith M Wesolowski }
85*80c94ecdSKeith M Wesolowski 
86*80c94ecdSKeith M Wesolowski /*
87*80c94ecdSKeith M Wesolowski  * Function	: 	cpqary3_tick_hdlr
88*80c94ecdSKeith M Wesolowski  * Description	: 	This routine is called once in 60 seconds to detect any
89*80c94ecdSKeith M Wesolowski  *			command that is pending with the controller and has
90*80c94ecdSKeith M Wesolowski  *			timed out.
91*80c94ecdSKeith M Wesolowski  *			Once invoked, it re-initializes itself such that it is
92*80c94ecdSKeith M Wesolowski  *			invoked after an interval of 60 seconds.
93*80c94ecdSKeith M Wesolowski  * Called By	: 	kernel
94*80c94ecdSKeith M Wesolowski  * Parameters	: 	per_controller
95*80c94ecdSKeith M Wesolowski  * Calls	: 	None
96*80c94ecdSKeith M Wesolowski  * Return Values: 	None
97*80c94ecdSKeith M Wesolowski  */
98*80c94ecdSKeith M Wesolowski void
cpqary3_tick_hdlr(void * arg)99*80c94ecdSKeith M Wesolowski cpqary3_tick_hdlr(void *arg)
100*80c94ecdSKeith M Wesolowski {
101*80c94ecdSKeith M Wesolowski 	clock_t			cpqary3_lbolt;
102*80c94ecdSKeith M Wesolowski 	clock_t			cpqary3_ticks;
103*80c94ecdSKeith M Wesolowski 	cpqary3_t		*ctlr;
104*80c94ecdSKeith M Wesolowski 	cpqary3_pkt_t		*pktp;
105*80c94ecdSKeith M Wesolowski 	struct scsi_pkt		*scsi_pktp;
106*80c94ecdSKeith M Wesolowski 	cpqary3_cmdpvt_t	*local;
107*80c94ecdSKeith M Wesolowski 	volatile CfgTable_t	*ctp;
108*80c94ecdSKeith M Wesolowski 	uint32_t		i;
109*80c94ecdSKeith M Wesolowski 	uint32_t		no_cmds = 0;
110*80c94ecdSKeith M Wesolowski 
111*80c94ecdSKeith M Wesolowski 	/*
112*80c94ecdSKeith M Wesolowski 	 * The per-controller shall be passed as argument.
113*80c94ecdSKeith M Wesolowski 	 * Read the HeartBeat of the controller.
114*80c94ecdSKeith M Wesolowski 	 * if the current heartbeat is the same as the one recorded earlier,
115*80c94ecdSKeith M Wesolowski 	 * the f/w has locked up!!!
116*80c94ecdSKeith M Wesolowski 	 */
117*80c94ecdSKeith M Wesolowski 
118*80c94ecdSKeith M Wesolowski 	if (NULL == (ctlr = (cpqary3_t *)arg))
119*80c94ecdSKeith M Wesolowski 		return;
120*80c94ecdSKeith M Wesolowski 
121*80c94ecdSKeith M Wesolowski 	ctp = (CfgTable_t *)ctlr->ct;
122*80c94ecdSKeith M Wesolowski 
123*80c94ecdSKeith M Wesolowski 	/* CONTROLLER_LOCKUP */
124*80c94ecdSKeith M Wesolowski 	if (ctlr->heartbeat == DDI_GET32(ctlr, &ctp->HeartBeat)) {
125*80c94ecdSKeith M Wesolowski 		if (ctlr->lockup_logged == CPQARY3_FALSE) {
126*80c94ecdSKeith M Wesolowski 			cmn_err(CE_WARN, "CPQary3 : "
127*80c94ecdSKeith M Wesolowski 			    "%s HBA firmware Locked !!!", ctlr->hba_name);
128*80c94ecdSKeith M Wesolowski 			cmn_err(CE_WARN, "CPQary3 : "
129*80c94ecdSKeith M Wesolowski 			    "Please reboot the system");
130*80c94ecdSKeith M Wesolowski 			cpqary3_intr_onoff(ctlr, CPQARY3_INTR_DISABLE);
131*80c94ecdSKeith M Wesolowski 			if (ctlr->host_support & 0x4)
132*80c94ecdSKeith M Wesolowski 				cpqary3_lockup_intr_onoff(ctlr,
133*80c94ecdSKeith M Wesolowski 				    CPQARY3_LOCKUP_INTR_DISABLE);
134*80c94ecdSKeith M Wesolowski 			ctlr->controller_lockup = CPQARY3_TRUE;
135*80c94ecdSKeith M Wesolowski 			ctlr->lockup_logged = CPQARY3_TRUE;
136*80c94ecdSKeith M Wesolowski 		}
137*80c94ecdSKeith M Wesolowski 	}
138*80c94ecdSKeith M Wesolowski 	/* CONTROLLER_LOCKUP */
139*80c94ecdSKeith M Wesolowski 	no_cmds  = (uint32_t)((ctlr->ctlr_maxcmds / 3) *
140*80c94ecdSKeith M Wesolowski 	    NO_OF_CMDLIST_IN_A_BLK);
141*80c94ecdSKeith M Wesolowski 	mutex_enter(&ctlr->sw_mutex);
142*80c94ecdSKeith M Wesolowski 
143*80c94ecdSKeith M Wesolowski 	for (i = 0; i < no_cmds; i++) {
144*80c94ecdSKeith M Wesolowski 		local = &ctlr->cmdmemlistp->pool[i];
145*80c94ecdSKeith M Wesolowski 		ASSERT(local != NULL);
146*80c94ecdSKeith M Wesolowski 		pktp = MEM2PVTPKT(local);
147*80c94ecdSKeith M Wesolowski 
148*80c94ecdSKeith M Wesolowski 		if (!pktp)
149*80c94ecdSKeith M Wesolowski 			continue;
150*80c94ecdSKeith M Wesolowski 
151*80c94ecdSKeith M Wesolowski 		if ((local->cmdpvt_flag == CPQARY3_TIMEOUT) ||
152*80c94ecdSKeith M Wesolowski 		    (local->cmdpvt_flag == CPQARY3_RESET)) {
153*80c94ecdSKeith M Wesolowski 			continue;
154*80c94ecdSKeith M Wesolowski 		}
155*80c94ecdSKeith M Wesolowski 
156*80c94ecdSKeith M Wesolowski 		if (local->occupied == CPQARY3_OCCUPIED) {
157*80c94ecdSKeith M Wesolowski 			scsi_pktp = pktp->scsi_cmd_pkt;
158*80c94ecdSKeith M Wesolowski 			cpqary3_lbolt = ddi_get_lbolt();
159*80c94ecdSKeith M Wesolowski 			if ((scsi_pktp) && (scsi_pktp->pkt_time)) {
160*80c94ecdSKeith M Wesolowski 				cpqary3_ticks = cpqary3_lbolt -
161*80c94ecdSKeith M Wesolowski 				    pktp->cmd_start_time;
162*80c94ecdSKeith M Wesolowski 
163*80c94ecdSKeith M Wesolowski 				if ((drv_hztousec(cpqary3_ticks)/1000000) >
164*80c94ecdSKeith M Wesolowski 				    scsi_pktp->pkt_time) {
165*80c94ecdSKeith M Wesolowski 					scsi_pktp->pkt_reason = CMD_TIMEOUT;
166*80c94ecdSKeith M Wesolowski 					scsi_pktp->pkt_statistics =
167*80c94ecdSKeith M Wesolowski 					    STAT_TIMEOUT;
168*80c94ecdSKeith M Wesolowski 					scsi_pktp->pkt_state = STATE_GOT_BUS |
169*80c94ecdSKeith M Wesolowski 					    STATE_GOT_TARGET | STATE_SENT_CMD;
170*80c94ecdSKeith M Wesolowski 					local->cmdpvt_flag = CPQARY3_TIMEOUT;
171*80c94ecdSKeith M Wesolowski 
172*80c94ecdSKeith M Wesolowski 					/* This should always be the case */
173*80c94ecdSKeith M Wesolowski 					if (scsi_pktp->pkt_comp) {
174*80c94ecdSKeith M Wesolowski 						mutex_exit(&ctlr->sw_mutex);
175*80c94ecdSKeith M Wesolowski 						(*scsi_pktp->pkt_comp)
176*80c94ecdSKeith M Wesolowski 						    (scsi_pktp);
177*80c94ecdSKeith M Wesolowski 						mutex_enter(&ctlr->sw_mutex);
178*80c94ecdSKeith M Wesolowski 						continue;
179*80c94ecdSKeith M Wesolowski 					}
180*80c94ecdSKeith M Wesolowski 				}
181*80c94ecdSKeith M Wesolowski 			}
182*80c94ecdSKeith M Wesolowski 		}
183*80c94ecdSKeith M Wesolowski 	}
184*80c94ecdSKeith M Wesolowski 
185*80c94ecdSKeith M Wesolowski 	ctlr->heartbeat = DDI_GET32(ctlr, &ctp->HeartBeat);
186*80c94ecdSKeith M Wesolowski 	mutex_exit(&ctlr->sw_mutex);
187*80c94ecdSKeith M Wesolowski 	ctlr->tick_tmout_id = timeout(cpqary3_tick_hdlr,
188*80c94ecdSKeith M Wesolowski 	    (caddr_t)ctlr, drv_usectohz(CPQARY3_TICKTMOUT_VALUE));
189*80c94ecdSKeith M Wesolowski }
190*80c94ecdSKeith M Wesolowski 
191*80c94ecdSKeith M Wesolowski /*
192*80c94ecdSKeith M Wesolowski  * Function	: 	cpqary3_init_ctlr_resource
193*80c94ecdSKeith M Wesolowski  * Description	: 	This routine initializes the command list, initializes
194*80c94ecdSKeith M Wesolowski  *			the controller, enables the interrupt.
195*80c94ecdSKeith M Wesolowski  * Called By	: 	cpqary3_attach()
196*80c94ecdSKeith M Wesolowski  * Parameters	: 	per_controller
197*80c94ecdSKeith M Wesolowski  * Calls	: 	cpqary3_init_ctlr(), cpqary3_meminit(),
198*80c94ecdSKeith M Wesolowski  * 			cpqary3_intr_onoff(),
199*80c94ecdSKeith M Wesolowski  * Return Values: 	SUCCESS / FAILURE
200*80c94ecdSKeith M Wesolowski  *			[ Shall return failure if any of the mandatory
201*80c94ecdSKeith M Wesolowski  *			initializations / setup of resources fail ]
202*80c94ecdSKeith M Wesolowski  */
203*80c94ecdSKeith M Wesolowski uint16_t
cpqary3_init_ctlr_resource(cpqary3_t * ctlr)204*80c94ecdSKeith M Wesolowski cpqary3_init_ctlr_resource(cpqary3_t *ctlr)
205*80c94ecdSKeith M Wesolowski {
206*80c94ecdSKeith M Wesolowski #ifdef CPQARY3_DEBUG_MEM
207*80c94ecdSKeith M Wesolowski 	int8_t i = 0;
208*80c94ecdSKeith M Wesolowski #endif
209*80c94ecdSKeith M Wesolowski 
210*80c94ecdSKeith M Wesolowski 	/*
211*80c94ecdSKeith M Wesolowski 	 * Initialize the Controller
212*80c94ecdSKeith M Wesolowski 	 * Alocate Memory Pool for driver supported number of Commands
213*80c94ecdSKeith M Wesolowski 	 * return if not successful
214*80c94ecdSKeith M Wesolowski 	 * Allocate target structure for controller and initialize the same
215*80c94ecdSKeith M Wesolowski 	 * Detect all existing targets and allocate target structure for each
216*80c94ecdSKeith M Wesolowski 	 * Determine geometry for all existing targets
217*80c94ecdSKeith M Wesolowski 	 * Initialize the condition variables
218*80c94ecdSKeith M Wesolowski 	 */
219*80c94ecdSKeith M Wesolowski 
220*80c94ecdSKeith M Wesolowski 	RETURN_FAILURE_IF_NULL(ctlr);
221*80c94ecdSKeith M Wesolowski 
222*80c94ecdSKeith M Wesolowski 	if (CPQARY3_FAILURE == cpqary3_init_ctlr(ctlr))
223*80c94ecdSKeith M Wesolowski 		return ((CPQARY3_FAILURE));
224*80c94ecdSKeith M Wesolowski 
225*80c94ecdSKeith M Wesolowski 	if (CPQARY3_FAILURE == cpqary3_meminit(ctlr))
226*80c94ecdSKeith M Wesolowski 		return ((CPQARY3_FAILURE));
227*80c94ecdSKeith M Wesolowski 
228*80c94ecdSKeith M Wesolowski 
229*80c94ecdSKeith M Wesolowski #ifdef CPQARY3_DEBUG_MEM
230*80c94ecdSKeith M Wesolowski 	/*
231*80c94ecdSKeith M Wesolowski 	 * This code is in place to test the memory management of this driver.
232*80c94ecdSKeith M Wesolowski 	 * This block of code allocates and de-allocates memory as many number
233*80c94ecdSKeith M Wesolowski 	 * of times as given in the for loop.
234*80c94ecdSKeith M Wesolowski 	 * After the for loop is executed, it returns a failure, which in turn
235*80c94ecdSKeith M Wesolowski 	 * would result in attach being failed.
236*80c94ecdSKeith M Wesolowski 	 */
237*80c94ecdSKeith M Wesolowski 	cmn_err(CE_CONT, "CPQary3 : _init_ctlr_resource : Testing memory \n");
238*80c94ecdSKeith M Wesolowski 	for (i = 0; i < 15; i++) {
239*80c94ecdSKeith M Wesolowski 		if (CPQARY3_SUCCESS != cpqary3_meminit(ctlr)) {
240*80c94ecdSKeith M Wesolowski 			cmn_err(CE_CONT, "CPQary3 : meminit failed : "
241*80c94ecdSKeith M Wesolowski 			    "attempt %d \n", i);
242*80c94ecdSKeith M Wesolowski 			return (CPQARY3_FAILURE);
243*80c94ecdSKeith M Wesolowski 		}
244*80c94ecdSKeith M Wesolowski 		cmn_err(CE_CONT,
245*80c94ecdSKeith M Wesolowski 		    "CPQary3 : INIT successful : attempt %d \n", i);
246*80c94ecdSKeith M Wesolowski 		cpqary3_memfini(ctlr, CPQARY3_MEMLIST_DONE |
247*80c94ecdSKeith M Wesolowski 		    CPQARY3_PHYCTGS_DONE | CPQARY3_CMDMEM_DONE);
248*80c94ecdSKeith M Wesolowski 		cmn_err(CE_CONT,
249*80c94ecdSKeith M Wesolowski 		    "CPQary3 : FINI successful : attempt %d \n", i);
250*80c94ecdSKeith M Wesolowski 	}
251*80c94ecdSKeith M Wesolowski 	return (CPQARY3_FAILURE);
252*80c94ecdSKeith M Wesolowski #endif
253*80c94ecdSKeith M Wesolowski 
254*80c94ecdSKeith M Wesolowski 	ctlr->cpqary3_tgtp[CTLR_SCSI_ID] = MEM_ZALLOC(sizeof (cpqary3_tgt_t));
255*80c94ecdSKeith M Wesolowski 	if (!(ctlr->cpqary3_tgtp[CTLR_SCSI_ID])) {
256*80c94ecdSKeith M Wesolowski 		cmn_err(CE_WARN, "CPQary3: Target Initialization Failed");
257*80c94ecdSKeith M Wesolowski 		cpqary3_memfini(ctlr, CPQARY3_MEMLIST_DONE |
258*80c94ecdSKeith M Wesolowski 		    CPQARY3_PHYCTGS_DONE | CPQARY3_CMDMEM_DONE);
259*80c94ecdSKeith M Wesolowski 		return (CPQARY3_FAILURE);
260*80c94ecdSKeith M Wesolowski 	}
261*80c94ecdSKeith M Wesolowski 	ctlr->cpqary3_tgtp[CTLR_SCSI_ID]->type = CPQARY3_TARGET_CTLR;
262*80c94ecdSKeith M Wesolowski 
263*80c94ecdSKeith M Wesolowski 	cpqary3_intr_onoff(ctlr, CPQARY3_INTR_DISABLE);
264*80c94ecdSKeith M Wesolowski 
265*80c94ecdSKeith M Wesolowski 	/*
266*80c94ecdSKeith M Wesolowski 	 * Initialize all condition variables :
267*80c94ecdSKeith M Wesolowski 	 * for the immediate call back
268*80c94ecdSKeith M Wesolowski 	 * for the disable noe
269*80c94ecdSKeith M Wesolowski 	 * for fulsh cache
270*80c94ecdSKeith M Wesolowski 	 * for probe device
271*80c94ecdSKeith M Wesolowski 	 */
272*80c94ecdSKeith M Wesolowski 
273*80c94ecdSKeith M Wesolowski 	cv_init(&ctlr->cv_immediate_wait, NULL, CV_DRIVER, NULL);
274*80c94ecdSKeith M Wesolowski 	cv_init(&ctlr->cv_noe_wait, NULL, CV_DRIVER, NULL);
275*80c94ecdSKeith M Wesolowski 	cv_init(&ctlr->cv_flushcache_wait, NULL, CV_DRIVER, NULL);
276*80c94ecdSKeith M Wesolowski 	cv_init(&ctlr->cv_abort_wait, NULL, CV_DRIVER, NULL);
277*80c94ecdSKeith M Wesolowski 	cv_init(&ctlr->cv_ioctl_wait, NULL, CV_DRIVER, NULL);
278*80c94ecdSKeith M Wesolowski 
279*80c94ecdSKeith M Wesolowski 	return (CPQARY3_SUCCESS);
280*80c94ecdSKeith M Wesolowski }
281*80c94ecdSKeith M Wesolowski 
282*80c94ecdSKeith M Wesolowski /*
283*80c94ecdSKeith M Wesolowski  * Function	: 	cpqary3_target_geometry
284*80c94ecdSKeith M Wesolowski  * Description	: 	This function returns the geometry for the target.
285*80c94ecdSKeith M Wesolowski  * Called By	: 	cpqary3_getcap()
286*80c94ecdSKeith M Wesolowski  * Parameters	:	Target SCSI address
287*80c94ecdSKeith M Wesolowski  * Calls	:	None
288*80c94ecdSKeith M Wesolowski  * Return Values: 	Device Geometry
289*80c94ecdSKeith M Wesolowski  */
290*80c94ecdSKeith M Wesolowski int
cpqary3_target_geometry(struct scsi_address * sa)291*80c94ecdSKeith M Wesolowski cpqary3_target_geometry(struct scsi_address *sa)
292*80c94ecdSKeith M Wesolowski {
293*80c94ecdSKeith M Wesolowski 	cpqary3_t	*ctlr = SA2CTLR(sa);
294*80c94ecdSKeith M Wesolowski 	cpqary3_tgt_t	*tgtp = ctlr->cpqary3_tgtp[SA2TGT(sa)];
295*80c94ecdSKeith M Wesolowski 
296*80c94ecdSKeith M Wesolowski 	/*
297*80c94ecdSKeith M Wesolowski 	 * The target CHS are stored in the per-target structure
298*80c94ecdSKeith M Wesolowski 	 * during attach time. Use these values
299*80c94ecdSKeith M Wesolowski 	 */
300*80c94ecdSKeith M Wesolowski 	return ((tgtp->properties.drive.heads << 16) |
301*80c94ecdSKeith M Wesolowski 	    tgtp->properties.drive.sectors);
302*80c94ecdSKeith M Wesolowski }
303*80c94ecdSKeith M Wesolowski 
304*80c94ecdSKeith M Wesolowski /*
305*80c94ecdSKeith M Wesolowski  * Function	:   	cpqary3_synccmd_alloc
306*80c94ecdSKeith M Wesolowski  * Description	:   	This function allocates the DMA buffer for the commands
307*80c94ecdSKeith M Wesolowski  * Called By	:   	cpqary3_ioctl_send_bmiccmd(),
308*80c94ecdSKeith M Wesolowski  *			cpqary3_ioctl_send_scsicmd()
309*80c94ecdSKeith M Wesolowski  *			cpqary3_send_abortcmd(), cpqary3_flush_cache(),
310*80c94ecdSKeith M Wesolowski  *			cpqary3_probe4LVs(), cpqary3_probe4Tapes(),
311*80c94ecdSKeith M Wesolowski  *			cpqary3_detect_target_geometry()
312*80c94ecdSKeith M Wesolowski  * Parameters	:   	per_controller, buffer size
313*80c94ecdSKeith M Wesolowski  * Calls	:   	cpqary3_alloc_phyctgs_mem(), cpqary3_cmdlist_occupy()
314*80c94ecdSKeith M Wesolowski  * Return Values:   	memp
315*80c94ecdSKeith M Wesolowski  */
316*80c94ecdSKeith M Wesolowski cpqary3_cmdpvt_t *
cpqary3_synccmd_alloc(cpqary3_t * cpqary3p,size_t bufsz)317*80c94ecdSKeith M Wesolowski cpqary3_synccmd_alloc(cpqary3_t *cpqary3p, size_t bufsz)
318*80c94ecdSKeith M Wesolowski {
319*80c94ecdSKeith M Wesolowski 	cpqary3_private_t	*cmddmah = NULL;
320*80c94ecdSKeith M Wesolowski 	uint32_t		dmabufpa = 0;	/* XXX 32-bit pa? */
321*80c94ecdSKeith M Wesolowski 	cpqary3_cmdpvt_t	*memp = NULL;
322*80c94ecdSKeith M Wesolowski 
323*80c94ecdSKeith M Wesolowski 	/*  first, allocate any necessary dma buffers  */
324*80c94ecdSKeith M Wesolowski 	if (bufsz > 0) {
325*80c94ecdSKeith M Wesolowski 		cpqary3_phyctg_t	*dmah = NULL;
326*80c94ecdSKeith M Wesolowski 		caddr_t			dmabufva = NULL;
327*80c94ecdSKeith M Wesolowski 
328*80c94ecdSKeith M Wesolowski 		/* first, allocate the command's dma handle */
329*80c94ecdSKeith M Wesolowski 		cmddmah = (cpqary3_private_t *)MEM_ZALLOC(sizeof (*cmddmah));
330*80c94ecdSKeith M Wesolowski 		if (cmddmah == NULL) {
331*80c94ecdSKeith M Wesolowski 			cmn_err(CE_WARN, "cpqary3_synccmd_alloc: "
332*80c94ecdSKeith M Wesolowski 			    "no memory for cmddmah");
333*80c94ecdSKeith M Wesolowski 			return (NULL);
334*80c94ecdSKeith M Wesolowski 		}
335*80c94ecdSKeith M Wesolowski 
336*80c94ecdSKeith M Wesolowski 		/* next, allocate dma handle */
337*80c94ecdSKeith M Wesolowski 		dmah = (cpqary3_phyctg_t *)MEM_ZALLOC(sizeof (*dmah));
338*80c94ecdSKeith M Wesolowski 		if (dmah == NULL) {
339*80c94ecdSKeith M Wesolowski 			MEM_SFREE(cmddmah, sizeof (*cmddmah));
340*80c94ecdSKeith M Wesolowski 			cmn_err(CE_WARN, "cpqary3_synccmd_alloc: "
341*80c94ecdSKeith M Wesolowski 			    "no memory for dmah");
342*80c94ecdSKeith M Wesolowski 			return (NULL);
343*80c94ecdSKeith M Wesolowski 		}
344*80c94ecdSKeith M Wesolowski 		/* now, allocate dma buffer */
345*80c94ecdSKeith M Wesolowski 		dmabufva = cpqary3_alloc_phyctgs_mem(cpqary3p, bufsz,
346*80c94ecdSKeith M Wesolowski 		    &dmabufpa, dmah);
347*80c94ecdSKeith M Wesolowski 		if (dmabufva == NULL) {
348*80c94ecdSKeith M Wesolowski 			MEM_SFREE(cmddmah, sizeof (*cmddmah));
349*80c94ecdSKeith M Wesolowski 			cmn_err(CE_WARN, "cpqary3_synccmd_alloc: "
350*80c94ecdSKeith M Wesolowski 			    "no memory for dma buf");
351*80c94ecdSKeith M Wesolowski 			return (NULL);
352*80c94ecdSKeith M Wesolowski 		}
353*80c94ecdSKeith M Wesolowski 		bzero(dmabufva, bufsz);
354*80c94ecdSKeith M Wesolowski 
355*80c94ecdSKeith M Wesolowski 		/* attach dma buffer to command dma handle */
356*80c94ecdSKeith M Wesolowski 		cmddmah->sg = dmabufva;
357*80c94ecdSKeith M Wesolowski 		cmddmah->phyctgp = dmah;
358*80c94ecdSKeith M Wesolowski 	}
359*80c94ecdSKeith M Wesolowski 
360*80c94ecdSKeith M Wesolowski 	/* next, allocate a command packet */
361*80c94ecdSKeith M Wesolowski 	memp = cpqary3_cmdlist_occupy(cpqary3p);
362*80c94ecdSKeith M Wesolowski 	if (memp == NULL) {
363*80c94ecdSKeith M Wesolowski 		if (cmddmah != NULL) {
364*80c94ecdSKeith M Wesolowski 			cpqary3_free_phyctgs_mem(cmddmah->phyctgp,
365*80c94ecdSKeith M Wesolowski 			    CPQARY3_FREE_PHYCTG_MEM);
366*80c94ecdSKeith M Wesolowski 			MEM_SFREE(cmddmah, sizeof (*cmddmah));
367*80c94ecdSKeith M Wesolowski 		}
368*80c94ecdSKeith M Wesolowski 		cmn_err(CE_WARN, "cpqary3_synccmd_alloc: "
369*80c94ecdSKeith M Wesolowski 		    "cannot get free command");
370*80c94ecdSKeith M Wesolowski 		return (NULL);
371*80c94ecdSKeith M Wesolowski 	}
372*80c94ecdSKeith M Wesolowski 	memp->cmdpvt_flag = 0;
373*80c94ecdSKeith M Wesolowski 	memp->cmdlist_memaddr->Header.Tag.drvinfo_n_err =
374*80c94ecdSKeith M Wesolowski 	    CPQARY3_SYNCCMD_SUCCESS;
375*80c94ecdSKeith M Wesolowski 
376*80c94ecdSKeith M Wesolowski 	/* attach dma resources to command */
377*80c94ecdSKeith M Wesolowski 	memp->driverdata = cmddmah;
378*80c94ecdSKeith M Wesolowski 	memp->cmdlist_memaddr->SG[0].Addr = dmabufpa;
379*80c94ecdSKeith M Wesolowski 	memp->cmdlist_memaddr->SG[0].Len  = (uint32_t)bufsz;
380*80c94ecdSKeith M Wesolowski 
381*80c94ecdSKeith M Wesolowski 	/* done */
382*80c94ecdSKeith M Wesolowski 	return (memp);
383*80c94ecdSKeith M Wesolowski }
384*80c94ecdSKeith M Wesolowski 
385*80c94ecdSKeith M Wesolowski /*
386*80c94ecdSKeith M Wesolowski  * Function	:   cpqary3_synccmd_cleanup
387*80c94ecdSKeith M Wesolowski  * Description	:   This routine cleans up the command
388*80c94ecdSKeith M Wesolowski  * Called By	:   cpqary3_process_pkt(), cpqary3_synccmd_free()
389*80c94ecdSKeith M Wesolowski  * Parameters	:   per_command_memory
390*80c94ecdSKeith M Wesolowski  * Calls	:   cpqary3_free_phyctgs_mem(), cpqary3_cmdlist_release()
391*80c94ecdSKeith M Wesolowski  * Return Values:   none
392*80c94ecdSKeith M Wesolowski  */
393*80c94ecdSKeith M Wesolowski void
cpqary3_synccmd_cleanup(cpqary3_cmdpvt_t * memp)394*80c94ecdSKeith M Wesolowski cpqary3_synccmd_cleanup(cpqary3_cmdpvt_t *memp)
395*80c94ecdSKeith M Wesolowski {
396*80c94ecdSKeith M Wesolowski 	/*
397*80c94ecdSKeith M Wesolowski 	 * ordinary users should not call this routine
398*80c94ecdSKeith M Wesolowski 	 * (use cpqary3_synccmd_free() instead).  this is
399*80c94ecdSKeith M Wesolowski 	 * for use ONLY by cpqary3_synccmd_free() and
400*80c94ecdSKeith M Wesolowski 	 * cpqary3_process_pkt().
401*80c94ecdSKeith M Wesolowski 	 */
402*80c94ecdSKeith M Wesolowski 
403*80c94ecdSKeith M Wesolowski 	if (memp->driverdata != NULL) {
404*80c94ecdSKeith M Wesolowski 		/* free dma resources */
405*80c94ecdSKeith M Wesolowski 		cpqary3_free_phyctgs_mem(memp->driverdata->phyctgp,
406*80c94ecdSKeith M Wesolowski 		    CPQARY3_FREE_PHYCTG_MEM);
407*80c94ecdSKeith M Wesolowski 		MEM_SFREE(memp->driverdata, sizeof (cpqary3_private_t));
408*80c94ecdSKeith M Wesolowski 		memp->driverdata = NULL;
409*80c94ecdSKeith M Wesolowski 	}
410*80c94ecdSKeith M Wesolowski 	/* release command */
411*80c94ecdSKeith M Wesolowski 	memp->cmdpvt_flag = 0;
412*80c94ecdSKeith M Wesolowski 	cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX);
413*80c94ecdSKeith M Wesolowski }
414*80c94ecdSKeith M Wesolowski 
415*80c94ecdSKeith M Wesolowski /*
416*80c94ecdSKeith M Wesolowski  * Function	:   	cpqary3_synccmd_free
417*80c94ecdSKeith M Wesolowski  * Description	:   	This routine frees the command and the
418*80c94ecdSKeith M Wesolowski  *			associated resources.
419*80c94ecdSKeith M Wesolowski  * Called By	:   	cpqary3_ioctl_send_bmiccmd(),
420*80c94ecdSKeith M Wesolowski  *			cpqary3_ioctl_send_scsicmd()
421*80c94ecdSKeith M Wesolowski  *			cpqary3_send_abortcmd(), cpqary3_flush_cache(),
422*80c94ecdSKeith M Wesolowski  *			cpqary3_probe4LVs(), cpqary3_probe4Tapes(),
423*80c94ecdSKeith M Wesolowski  *			cpqary3_detect_target_geometry()
424*80c94ecdSKeith M Wesolowski  * Parameters	:   	per_controller, per_command_memory
425*80c94ecdSKeith M Wesolowski  * Calls	:   	cpqary3_synccmd_cleanup()
426*80c94ecdSKeith M Wesolowski  * Return Values:   	NONE
427*80c94ecdSKeith M Wesolowski  */
428*80c94ecdSKeith M Wesolowski void
cpqary3_synccmd_free(cpqary3_t * cpqary3p,cpqary3_cmdpvt_t * memp)429*80c94ecdSKeith M Wesolowski cpqary3_synccmd_free(cpqary3_t *cpqary3p, cpqary3_cmdpvt_t *memp)
430*80c94ecdSKeith M Wesolowski {
431*80c94ecdSKeith M Wesolowski 	/*
432*80c94ecdSKeith M Wesolowski 	 * so, the user is done with this command packet.
433*80c94ecdSKeith M Wesolowski 	 * we have three possible scenarios here:
434*80c94ecdSKeith M Wesolowski 	 *
435*80c94ecdSKeith M Wesolowski 	 * 1) the command was never submitted to the controller
436*80c94ecdSKeith M Wesolowski 	 *
437*80c94ecdSKeith M Wesolowski 	 * or
438*80c94ecdSKeith M Wesolowski 	 *
439*80c94ecdSKeith M Wesolowski 	 * 2) the command has completed at the controller and has
440*80c94ecdSKeith M Wesolowski 	 *    been fully processed by the interrupt processing
441*80c94ecdSKeith M Wesolowski 	 *    mechanism and is no longer on the submitted or
442*80c94ecdSKeith M Wesolowski 	 *    retrieve queues.
443*80c94ecdSKeith M Wesolowski 	 *
444*80c94ecdSKeith M Wesolowski 	 * or
445*80c94ecdSKeith M Wesolowski 	 *
446*80c94ecdSKeith M Wesolowski 	 * 3) the command is not yet complete at the controller,
447*80c94ecdSKeith M Wesolowski 	 *    and/or hasn't made it through cpqary3_process_pkt()
448*80c94ecdSKeith M Wesolowski 	 *    yet.
449*80c94ecdSKeith M Wesolowski 	 *
450*80c94ecdSKeith M Wesolowski 	 * For cases (1) and (2), we can go ahead and free the
451*80c94ecdSKeith M Wesolowski 	 * command and the associated resources.  For case (3), we
452*80c94ecdSKeith M Wesolowski 	 * must mark the command as no longer needed, and let
453*80c94ecdSKeith M Wesolowski 	 * cpqary3_process_pkt() clean it up instead.
454*80c94ecdSKeith M Wesolowski 	 */
455*80c94ecdSKeith M Wesolowski 
456*80c94ecdSKeith M Wesolowski 	mutex_enter(&(cpqary3p->sw_mutex));
457*80c94ecdSKeith M Wesolowski 	if (memp->cmdpvt_flag == CPQARY3_SYNC_SUBMITTED) {
458*80c94ecdSKeith M Wesolowski 		/*
459*80c94ecdSKeith M Wesolowski 		 * command is still pending (case #3 above).
460*80c94ecdSKeith M Wesolowski 		 * mark the command as abandoned and let
461*80c94ecdSKeith M Wesolowski 		 * cpqary3_process_pkt() clean it up.
462*80c94ecdSKeith M Wesolowski 		 */
463*80c94ecdSKeith M Wesolowski 		memp->cmdpvt_flag = CPQARY3_SYNC_TIMEOUT;
464*80c94ecdSKeith M Wesolowski 		mutex_exit(&(cpqary3p->sw_mutex));
465*80c94ecdSKeith M Wesolowski 		return;
466*80c94ecdSKeith M Wesolowski 	}
467*80c94ecdSKeith M Wesolowski 	memp->cmdpvt_flag = 0;
468*80c94ecdSKeith M Wesolowski 	mutex_exit(&(cpqary3p->sw_mutex));
469*80c94ecdSKeith M Wesolowski 
470*80c94ecdSKeith M Wesolowski 	/*
471*80c94ecdSKeith M Wesolowski 	 * command was either never submitted or has completed
472*80c94ecdSKeith M Wesolowski 	 * (cases #1 and #2 above).  so, clean it up.
473*80c94ecdSKeith M Wesolowski 	 */
474*80c94ecdSKeith M Wesolowski 	cpqary3_synccmd_cleanup(memp);
475*80c94ecdSKeith M Wesolowski 
476*80c94ecdSKeith M Wesolowski 	/* done */
477*80c94ecdSKeith M Wesolowski 	return;
478*80c94ecdSKeith M Wesolowski 
479*80c94ecdSKeith M Wesolowski }  /* cpqary3_synccmd_free() */
480*80c94ecdSKeith M Wesolowski 
481*80c94ecdSKeith M Wesolowski /*
482*80c94ecdSKeith M Wesolowski  * Function	:   	cpqary3_synccmd_send
483*80c94ecdSKeith M Wesolowski  * Description	:   	This routine sends the command to the controller
484*80c94ecdSKeith M Wesolowski  * Called By	:	cpqary3_ioctl_send_bmiccmd(),
485*80c94ecdSKeith M Wesolowski  * 			cpqary3_ioctl_send_scsicmd()
486*80c94ecdSKeith M Wesolowski  * 			cpqary3_send_abortcmd(), cpqary3_flush_cache(),
487*80c94ecdSKeith M Wesolowski  * 			cpqary3_probe4LVs(), cpqary3_probe4Tapes(),
488*80c94ecdSKeith M Wesolowski  * 			cpqary3_detect_target_geometry()
489*80c94ecdSKeith M Wesolowski  * Parameters	:   	per_controller, per_command_memory, timeout value,
490*80c94ecdSKeith M Wesolowski  * 			flag(wait for reply)
491*80c94ecdSKeith M Wesolowski  * Calls	:   	cpqary3_submit(), cpqary3_add2submitted_cmdq()
492*80c94ecdSKeith M Wesolowski  * Return Values:   	SUCCESS / FAILURE
493*80c94ecdSKeith M Wesolowski  */
494*80c94ecdSKeith M Wesolowski int
cpqary3_synccmd_send(cpqary3_t * cpqary3p,cpqary3_cmdpvt_t * memp,clock_t timeoutms,int flags)495*80c94ecdSKeith M Wesolowski cpqary3_synccmd_send(cpqary3_t *cpqary3p, cpqary3_cmdpvt_t *memp,
496*80c94ecdSKeith M Wesolowski     clock_t timeoutms, int flags)
497*80c94ecdSKeith M Wesolowski {
498*80c94ecdSKeith M Wesolowski 	clock_t		absto = 0;  /* absolute timeout */
499*80c94ecdSKeith M Wesolowski 	int		waitsig = 0;
500*80c94ecdSKeith M Wesolowski 	int		rc = 0;
501*80c94ecdSKeith M Wesolowski 	kcondvar_t	*cv = 0;
502*80c94ecdSKeith M Wesolowski 
503*80c94ecdSKeith M Wesolowski 	/*  compute absolute timeout, if necessary  */
504*80c94ecdSKeith M Wesolowski 	if (timeoutms > 0)
505*80c94ecdSKeith M Wesolowski 		absto = ddi_get_lbolt() + drv_usectohz(timeoutms * 1000);
506*80c94ecdSKeith M Wesolowski 
507*80c94ecdSKeith M Wesolowski 	/*  heed signals during wait?  */
508*80c94ecdSKeith M Wesolowski 	if (flags & CPQARY3_SYNCCMD_SEND_WAITSIG)
509*80c94ecdSKeith M Wesolowski 		waitsig = 1;
510*80c94ecdSKeith M Wesolowski 
511*80c94ecdSKeith M Wesolowski 	/*  acquire the sw mutex for our wait  */
512*80c94ecdSKeith M Wesolowski 	mutex_enter(&(cpqary3p->sw_mutex));
513*80c94ecdSKeith M Wesolowski 
514*80c94ecdSKeith M Wesolowski 	/*  submit command to controller  */
515*80c94ecdSKeith M Wesolowski 	mutex_enter(&(cpqary3p->hw_mutex));
516*80c94ecdSKeith M Wesolowski 
517*80c94ecdSKeith M Wesolowski 	memp->cmdpvt_flag = CPQARY3_SYNC_SUBMITTED;
518*80c94ecdSKeith M Wesolowski 	memp->cmdlist_memaddr->Header.Tag.drvinfo_n_err =
519*80c94ecdSKeith M Wesolowski 	    CPQARY3_SYNCCMD_SUCCESS;
520*80c94ecdSKeith M Wesolowski 	if (EIO == cpqary3_submit(cpqary3p, memp->cmdlist_phyaddr)) {
521*80c94ecdSKeith M Wesolowski 		mutex_exit(&(cpqary3p->hw_mutex));
522*80c94ecdSKeith M Wesolowski 		mutex_exit(&(cpqary3p->sw_mutex));
523*80c94ecdSKeith M Wesolowski 		rc = -1;
524*80c94ecdSKeith M Wesolowski 		return (rc);
525*80c94ecdSKeith M Wesolowski 	}
526*80c94ecdSKeith M Wesolowski 	mutex_exit(&(cpqary3p->hw_mutex));
527*80c94ecdSKeith M Wesolowski 
528*80c94ecdSKeith M Wesolowski 	/*  wait for command completion, timeout, or signal  */
529*80c94ecdSKeith M Wesolowski 	while (memp->cmdpvt_flag == CPQARY3_SYNC_SUBMITTED) {
530*80c94ecdSKeith M Wesolowski 		kmutex_t *mt = &(cpqary3p->sw_mutex);
531*80c94ecdSKeith M Wesolowski 
532*80c94ecdSKeith M Wesolowski 		cv = &(cpqary3p->cv_ioctl_wait);
533*80c94ecdSKeith M Wesolowski 		/*  wait with the request behavior  */
534*80c94ecdSKeith M Wesolowski 		if (absto) {
535*80c94ecdSKeith M Wesolowski 			clock_t   crc;
536*80c94ecdSKeith M Wesolowski 			if (waitsig) {
537*80c94ecdSKeith M Wesolowski 				crc = cv_timedwait_sig(cv, mt, absto);
538*80c94ecdSKeith M Wesolowski 			} else {
539*80c94ecdSKeith M Wesolowski 				crc = cv_timedwait(cv, mt, absto);
540*80c94ecdSKeith M Wesolowski 			}
541*80c94ecdSKeith M Wesolowski 			if (crc > 0)
542*80c94ecdSKeith M Wesolowski 				rc = 0;
543*80c94ecdSKeith M Wesolowski 			else
544*80c94ecdSKeith M Wesolowski 				rc = (-1);
545*80c94ecdSKeith M Wesolowski 		} else {
546*80c94ecdSKeith M Wesolowski 			if (waitsig) {
547*80c94ecdSKeith M Wesolowski 				rc = cv_wait_sig(cv, mt);
548*80c94ecdSKeith M Wesolowski 				if (rc > 0)
549*80c94ecdSKeith M Wesolowski 					rc = 0;
550*80c94ecdSKeith M Wesolowski 				else
551*80c94ecdSKeith M Wesolowski 					rc = (-1);
552*80c94ecdSKeith M Wesolowski 			} else {
553*80c94ecdSKeith M Wesolowski 				cv_wait(cv, mt);
554*80c94ecdSKeith M Wesolowski 				rc = 0;
555*80c94ecdSKeith M Wesolowski 			}
556*80c94ecdSKeith M Wesolowski 		}
557*80c94ecdSKeith M Wesolowski 
558*80c94ecdSKeith M Wesolowski 
559*80c94ecdSKeith M Wesolowski 		/*
560*80c94ecdSKeith M Wesolowski 		 * if our wait was interrupted (timeout),
561*80c94ecdSKeith M Wesolowski 		 * then break here
562*80c94ecdSKeith M Wesolowski 		 */
563*80c94ecdSKeith M Wesolowski 		if (rc) {
564*80c94ecdSKeith M Wesolowski 			break;
565*80c94ecdSKeith M Wesolowski 		}
566*80c94ecdSKeith M Wesolowski 	}
567*80c94ecdSKeith M Wesolowski 
568*80c94ecdSKeith M Wesolowski 	/* our wait is done, so release the sw mutex */
569*80c94ecdSKeith M Wesolowski 	mutex_exit(&(cpqary3p->sw_mutex));
570*80c94ecdSKeith M Wesolowski 
571*80c94ecdSKeith M Wesolowski 	/* return the results */
572*80c94ecdSKeith M Wesolowski 	return (rc);
573*80c94ecdSKeith M Wesolowski }
574*80c94ecdSKeith M Wesolowski 
575*80c94ecdSKeith M Wesolowski /*
576*80c94ecdSKeith M Wesolowski  * Function	: 	cpqary3_detect_target_geometry
577*80c94ecdSKeith M Wesolowski  * Description	: 	This function determines the geometry for all
578*80c94ecdSKeith M Wesolowski  *			the existing targets for the controller.
579*80c94ecdSKeith M Wesolowski  * Called By	:	cpqary3_tgt_init()
580*80c94ecdSKeith M Wesolowski  * Parameters	:	per controller
581*80c94ecdSKeith M Wesolowski  * Calls	:	cpqary3_synccmd_alloc(), cpqary3_synccmd_send()
582*80c94ecdSKeith M Wesolowski  *			cpqary3_synccmd_free()
583*80c94ecdSKeith M Wesolowski  * Return Values: 	SUCCESS / FAILURE
584*80c94ecdSKeith M Wesolowski  *			[ Shall return failure only if Memory constraints exist
585*80c94ecdSKeith M Wesolowski  *			or controller does not respond ]
586*80c94ecdSKeith M Wesolowski  */
587*80c94ecdSKeith M Wesolowski int8_t
cpqary3_detect_target_geometry(cpqary3_t * ctlr)588*80c94ecdSKeith M Wesolowski cpqary3_detect_target_geometry(cpqary3_t *ctlr)
589*80c94ecdSKeith M Wesolowski {
590*80c94ecdSKeith M Wesolowski 	int			i;
591*80c94ecdSKeith M Wesolowski 	int8_t			ld_count = 0;
592*80c94ecdSKeith M Wesolowski 	int8_t			loop_cnt = 0;
593*80c94ecdSKeith M Wesolowski 	IdLogDrive		*idlogdrive;
594*80c94ecdSKeith M Wesolowski 	CommandList_t		*cmdlistp;
595*80c94ecdSKeith M Wesolowski 	cpqary3_cmdpvt_t	*cpqary3_cmdpvtp;
596*80c94ecdSKeith M Wesolowski 
597*80c94ecdSKeith M Wesolowski 	RETURN_FAILURE_IF_NULL(ctlr);
598*80c94ecdSKeith M Wesolowski 
599*80c94ecdSKeith M Wesolowski 	/*
600*80c94ecdSKeith M Wesolowski 	 * Occupy a Command List
601*80c94ecdSKeith M Wesolowski 	 * Allocate Memory for return data
602*80c94ecdSKeith M Wesolowski 	 * If error, RETURN 0.
603*80c94ecdSKeith M Wesolowski 	 * get the Request Block from the CommandList
604*80c94ecdSKeith M Wesolowski 	 * Fill in the Request Packet with the corresponding values
605*80c94ecdSKeith M Wesolowski 	 * Submit the Command and Poll for its completion
606*80c94ecdSKeith M Wesolowski 	 * If success, continue else RETURN 0
607*80c94ecdSKeith M Wesolowski 	 */
608*80c94ecdSKeith M Wesolowski 
609*80c94ecdSKeith M Wesolowski 	/* Sync Changes */
610*80c94ecdSKeith M Wesolowski 	cpqary3_cmdpvtp = cpqary3_synccmd_alloc(ctlr, sizeof (IdLogDrive));
611*80c94ecdSKeith M Wesolowski 	if (cpqary3_cmdpvtp == NULL)
612*80c94ecdSKeith M Wesolowski 		return (CPQARY3_FAILURE);
613*80c94ecdSKeith M Wesolowski 
614*80c94ecdSKeith M Wesolowski 	cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
615*80c94ecdSKeith M Wesolowski 	idlogdrive = (IdLogDrive *)cpqary3_cmdpvtp->driverdata->sg;
616*80c94ecdSKeith M Wesolowski 	/* Sync Changes */
617*80c94ecdSKeith M Wesolowski 
618*80c94ecdSKeith M Wesolowski 
619*80c94ecdSKeith M Wesolowski 	/* Update Cmd Header */
620*80c94ecdSKeith M Wesolowski 	cmdlistp->Header.SGList = 1;
621*80c94ecdSKeith M Wesolowski 	cmdlistp->Header.SGTotal = 1;
622*80c94ecdSKeith M Wesolowski 	cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS;
623*80c94ecdSKeith M Wesolowski 
624*80c94ecdSKeith M Wesolowski 	/* Cmd Reques */
625*80c94ecdSKeith M Wesolowski 	cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_16;
626*80c94ecdSKeith M Wesolowski 	cmdlistp->Request.CDB[0] = 0x26;
627*80c94ecdSKeith M Wesolowski 	cmdlistp->Request.CDB[6] = BMIC_IDENTIFY_LOGICAL_DRIVE;
628*80c94ecdSKeith M Wesolowski 	cmdlistp->Request.CDB[7] = (sizeof (IdLogDrive) >> 8) & 0xff;
629*80c94ecdSKeith M Wesolowski 	cmdlistp->Request.CDB[8] = sizeof (IdLogDrive) & 0xff;
630*80c94ecdSKeith M Wesolowski 	cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
631*80c94ecdSKeith M Wesolowski 	cmdlistp->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
632*80c94ecdSKeith M Wesolowski 	cmdlistp->Request.Type.Direction = CISS_XFER_READ;
633*80c94ecdSKeith M Wesolowski 
634*80c94ecdSKeith M Wesolowski 	/*
635*80c94ecdSKeith M Wesolowski 	 * For all the Targets that exist, issue an IDENTIFY LOGICAL DRIVE.
636*80c94ecdSKeith M Wesolowski 	 * That returns values which includes the dsired Geometry also.
637*80c94ecdSKeith M Wesolowski 	 * Update the Geometry in the per-target structure.
638*80c94ecdSKeith M Wesolowski 	 * NOTE : When the loop is executed for i=controller's SCSI ID, just
639*80c94ecdSKeith M Wesolowski 	 * increament by one so that we are talking to the next logical
640*80c94ecdSKeith M Wesolowski 	 * drive in our per-target structure.
641*80c94ecdSKeith M Wesolowski 	 */
642*80c94ecdSKeith M Wesolowski 
643*80c94ecdSKeith M Wesolowski 	/*
644*80c94ecdSKeith M Wesolowski 	 * Depending upon the value of the variable legacy_mapping
645*80c94ecdSKeith M Wesolowski 	 * set in cpqary3_attach(),
646*80c94ecdSKeith M Wesolowski 	 * the target mapping algorithm to be used by the driver is decided.
647*80c94ecdSKeith M Wesolowski 	 */
648*80c94ecdSKeith M Wesolowski 
649*80c94ecdSKeith M Wesolowski 	if (ctlr->legacy_mapping == 1) {
650*80c94ecdSKeith M Wesolowski 		loop_cnt = ((ctlr->num_of_targets > CTLR_SCSI_ID) ?
651*80c94ecdSKeith M Wesolowski 		    (ctlr->num_of_targets + 1) : (ctlr->num_of_targets));
652*80c94ecdSKeith M Wesolowski 
653*80c94ecdSKeith M Wesolowski 		for (i = 0; i < loop_cnt; i++) {
654*80c94ecdSKeith M Wesolowski 			if (i == CTLR_SCSI_ID)	/* Go to Next logical target */
655*80c94ecdSKeith M Wesolowski 				i++;
656*80c94ecdSKeith M Wesolowski 
657*80c94ecdSKeith M Wesolowski 			bzero(idlogdrive, sizeof (IdLogDrive));
658*80c94ecdSKeith M Wesolowski 			cmdlistp->Request.CDB[1] =
659*80c94ecdSKeith M Wesolowski 			    ctlr->cpqary3_tgtp[i]->logical_id;
660*80c94ecdSKeith M Wesolowski 
661*80c94ecdSKeith M Wesolowski 			/* Always zero */
662*80c94ecdSKeith M Wesolowski 			cmdlistp->Header.LUN.PhysDev.TargetId = 0;
663*80c94ecdSKeith M Wesolowski 
664*80c94ecdSKeith M Wesolowski 			/*
665*80c94ecdSKeith M Wesolowski 			 * Logical volume Id numbering scheme is as follows
666*80c94ecdSKeith M Wesolowski 			 * 0x00000, 0x00001, ... - for Direct Attached
667*80c94ecdSKeith M Wesolowski 			 * 0x10000, 0x10001, ... - If 1st Port of HBA is
668*80c94ecdSKeith M Wesolowski 			 * connected to  MSA20 / MSA500
669*80c94ecdSKeith M Wesolowski 			 * 0x20000, 0x20001, ... - If 2nd Port of HBA is
670*80c94ecdSKeith M Wesolowski 			 * connected to MSA20 / MSA500
671*80c94ecdSKeith M Wesolowski 			 */
672*80c94ecdSKeith M Wesolowski 			cmdlistp->Header.LUN.PhysDev.Bus =
673*80c94ecdSKeith M Wesolowski 			    (ctlr->cpqary3_tgtp[i]->logical_id) >> 16;
674*80c94ecdSKeith M Wesolowski 			cmdlistp->Header.LUN.PhysDev.Mode =
675*80c94ecdSKeith M Wesolowski 			    (cmdlistp->Header.LUN.PhysDev.Bus > 0) ?
676*80c94ecdSKeith M Wesolowski 			    MASK_PERIPHERIAL_DEV_ADDR : PERIPHERIAL_DEV_ADDR;
677*80c94ecdSKeith M Wesolowski 
678*80c94ecdSKeith M Wesolowski 			/*
679*80c94ecdSKeith M Wesolowski 			 * Submit the command
680*80c94ecdSKeith M Wesolowski 			 * Poll for its completion
681*80c94ecdSKeith M Wesolowski 			 * If polling is not successful, something is wrong
682*80c94ecdSKeith M Wesolowski 			 * with the controler
683*80c94ecdSKeith M Wesolowski 			 * Return FAILURE (No point in continuing if h/w is
684*80c94ecdSKeith M Wesolowski 			 * faulty !!!)
685*80c94ecdSKeith M Wesolowski 			 */
686*80c94ecdSKeith M Wesolowski 
687*80c94ecdSKeith M Wesolowski 			/* PERF */
688*80c94ecdSKeith M Wesolowski 			cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
689*80c94ecdSKeith M Wesolowski 			/* PERF */
690*80c94ecdSKeith M Wesolowski 
691*80c94ecdSKeith M Wesolowski 			/* Sync Changes */
692*80c94ecdSKeith M Wesolowski 			if (cpqary3_synccmd_send(ctlr, cpqary3_cmdpvtp, 90000,
693*80c94ecdSKeith M Wesolowski 			    CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
694*80c94ecdSKeith M Wesolowski 				/* Timed out */
695*80c94ecdSKeith M Wesolowski 				cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
696*80c94ecdSKeith M Wesolowski 				return (CPQARY3_FAILURE);
697*80c94ecdSKeith M Wesolowski 			}
698*80c94ecdSKeith M Wesolowski 			if ((cpqary3_cmdpvtp->
699*80c94ecdSKeith M Wesolowski 			    cmdlist_memaddr->Header.Tag.drvinfo_n_err ==
700*80c94ecdSKeith M Wesolowski 			    CPQARY3_SYNCCMD_FAILURE) &&
701*80c94ecdSKeith M Wesolowski 			    (cpqary3_cmdpvtp->errorinfop->CommandStatus != 2)) {
702*80c94ecdSKeith M Wesolowski 				DTRACE_PROBE1(id_logdrv_fail,
703*80c94ecdSKeith M Wesolowski 				    ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop);
704*80c94ecdSKeith M Wesolowski 				cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
705*80c94ecdSKeith M Wesolowski 				return (CPQARY3_FAILURE);
706*80c94ecdSKeith M Wesolowski 			}
707*80c94ecdSKeith M Wesolowski 			/* Sync Changes */
708*80c94ecdSKeith M Wesolowski 
709*80c94ecdSKeith M Wesolowski 			ctlr->cpqary3_tgtp[i]->properties.drive.heads =
710*80c94ecdSKeith M Wesolowski 			    idlogdrive->heads;
711*80c94ecdSKeith M Wesolowski 			ctlr->cpqary3_tgtp[i]->properties.drive.sectors =
712*80c94ecdSKeith M Wesolowski 			    idlogdrive->sectors;
713*80c94ecdSKeith M Wesolowski 
714*80c94ecdSKeith M Wesolowski 			DTRACE_PROBE2(tgt_geometry_detect,
715*80c94ecdSKeith M Wesolowski 			    int, i, IdLogDrive *, idlogdrive);
716*80c94ecdSKeith M Wesolowski 		}
717*80c94ecdSKeith M Wesolowski 	} else {
718*80c94ecdSKeith M Wesolowski 
719*80c94ecdSKeith M Wesolowski 		/*
720*80c94ecdSKeith M Wesolowski 		 * Fix for QXCR1000446657: Logical drives are re numbered
721*80c94ecdSKeith M Wesolowski 		 * after deleting a Logical drive.
722*80c94ecdSKeith M Wesolowski 		 * introduced, new variable ld_count, which gets
723*80c94ecdSKeith M Wesolowski 		 * incremented when the Target ID is found.
724*80c94ecdSKeith M Wesolowski 		 * And for i=controller's SCSI ID and LDs with holes are found,
725*80c94ecdSKeith M Wesolowski 		 * we continue talking to
726*80c94ecdSKeith M Wesolowski 		 * the next logical drive in the per-target structure
727*80c94ecdSKeith M Wesolowski 		 */
728*80c94ecdSKeith M Wesolowski 
729*80c94ecdSKeith M Wesolowski 		for (i = 0; ld_count < ctlr->num_of_targets; i++) {
730*80c94ecdSKeith M Wesolowski 			if (i == CTLR_SCSI_ID ||
731*80c94ecdSKeith M Wesolowski 			    ctlr->cpqary3_tgtp[i] == NULL)
732*80c94ecdSKeith M Wesolowski 			/*  Go to the Next logical target  */
733*80c94ecdSKeith M Wesolowski 			continue;
734*80c94ecdSKeith M Wesolowski 			bzero(idlogdrive, sizeof (IdLogDrive));
735*80c94ecdSKeith M Wesolowski 			cmdlistp->Request.CDB[1] =
736*80c94ecdSKeith M Wesolowski 			    ctlr->cpqary3_tgtp[i]->logical_id;
737*80c94ecdSKeith M Wesolowski 			/* Always zero */
738*80c94ecdSKeith M Wesolowski 			cmdlistp->Header.LUN.PhysDev.TargetId = 0;
739*80c94ecdSKeith M Wesolowski 			/*
740*80c94ecdSKeith M Wesolowski 			 * Logical volume Id numbering scheme is as follows
741*80c94ecdSKeith M Wesolowski 			 * 0x00000, 0x00001, ... - for Direct Attached
742*80c94ecdSKeith M Wesolowski 			 * 0x10000, 0x10001, ... - If 1st Port of HBA is
743*80c94ecdSKeith M Wesolowski 			 * connected to  MSA20 / MSA500
744*80c94ecdSKeith M Wesolowski 			 * 0x20000, 0x20001, ... - If 2nd Port of HBA is
745*80c94ecdSKeith M Wesolowski 			 * connected to MSA20 / MSA500
746*80c94ecdSKeith M Wesolowski 			 */
747*80c94ecdSKeith M Wesolowski 			cmdlistp->Header.LUN.PhysDev.Bus =
748*80c94ecdSKeith M Wesolowski 			    (ctlr->cpqary3_tgtp[i]->logical_id) >> 16;
749*80c94ecdSKeith M Wesolowski 			cmdlistp->Header.LUN.PhysDev.Mode =
750*80c94ecdSKeith M Wesolowski 			    (cmdlistp->Header.LUN.PhysDev.Bus > 0) ?
751*80c94ecdSKeith M Wesolowski 			    MASK_PERIPHERIAL_DEV_ADDR :	PERIPHERIAL_DEV_ADDR;
752*80c94ecdSKeith M Wesolowski 			/* PERF */
753*80c94ecdSKeith M Wesolowski 			cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
754*80c94ecdSKeith M Wesolowski 			/* PERF */
755*80c94ecdSKeith M Wesolowski 
756*80c94ecdSKeith M Wesolowski 			/*
757*80c94ecdSKeith M Wesolowski 			 * Submit the command
758*80c94ecdSKeith M Wesolowski 			 * Poll for its completion
759*80c94ecdSKeith M Wesolowski 			 * If polling is not successful, something is wrong
760*80c94ecdSKeith M Wesolowski 			 * with the controler
761*80c94ecdSKeith M Wesolowski 			 * Return FAILURE (No point in continuing if h/w is
762*80c94ecdSKeith M Wesolowski 			 * faulty !!!)
763*80c94ecdSKeith M Wesolowski 			 */
764*80c94ecdSKeith M Wesolowski 
765*80c94ecdSKeith M Wesolowski 			/* Sync Changes */
766*80c94ecdSKeith M Wesolowski 			if (cpqary3_synccmd_send(ctlr, cpqary3_cmdpvtp, 90000,
767*80c94ecdSKeith M Wesolowski 			    CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
768*80c94ecdSKeith M Wesolowski 				/* Timed out */
769*80c94ecdSKeith M Wesolowski 				cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
770*80c94ecdSKeith M Wesolowski 				return (CPQARY3_FAILURE);
771*80c94ecdSKeith M Wesolowski 			}
772*80c94ecdSKeith M Wesolowski 			if ((cpqary3_cmdpvtp->
773*80c94ecdSKeith M Wesolowski 			    cmdlist_memaddr->Header.Tag.drvinfo_n_err ==
774*80c94ecdSKeith M Wesolowski 			    CPQARY3_SYNCCMD_FAILURE) &&
775*80c94ecdSKeith M Wesolowski 			    (cpqary3_cmdpvtp->errorinfop->CommandStatus != 2)) {
776*80c94ecdSKeith M Wesolowski 				DTRACE_PROBE1(id_logdrv_fail,
777*80c94ecdSKeith M Wesolowski 				    ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop);
778*80c94ecdSKeith M Wesolowski 				cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
779*80c94ecdSKeith M Wesolowski 				return (CPQARY3_FAILURE);
780*80c94ecdSKeith M Wesolowski 			}
781*80c94ecdSKeith M Wesolowski 			/* Sync Changes */
782*80c94ecdSKeith M Wesolowski 
783*80c94ecdSKeith M Wesolowski 			ctlr->cpqary3_tgtp[i]->properties.drive.heads =
784*80c94ecdSKeith M Wesolowski 			    idlogdrive->heads;
785*80c94ecdSKeith M Wesolowski 			ctlr->cpqary3_tgtp[i]->properties.drive.sectors =
786*80c94ecdSKeith M Wesolowski 			    idlogdrive->sectors;
787*80c94ecdSKeith M Wesolowski 
788*80c94ecdSKeith M Wesolowski 			DTRACE_PROBE2(tgt_geometry_detect,
789*80c94ecdSKeith M Wesolowski 			    int, i, IdLogDrive *, idlogdrive);
790*80c94ecdSKeith M Wesolowski 
791*80c94ecdSKeith M Wesolowski 			ld_count++;
792*80c94ecdSKeith M Wesolowski 		}
793*80c94ecdSKeith M Wesolowski 	}
794*80c94ecdSKeith M Wesolowski 
795*80c94ecdSKeith M Wesolowski 	/* Sync Changes */
796*80c94ecdSKeith M Wesolowski 	cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp);
797*80c94ecdSKeith M Wesolowski 	/* Sync Changes */
798*80c94ecdSKeith M Wesolowski 
799*80c94ecdSKeith M Wesolowski 	return (CPQARY3_SUCCESS);
800*80c94ecdSKeith M Wesolowski }
801