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