xref: /illumos-gate/usr/src/uts/common/io/cpqary3/cpqary3_scsi.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
14  * Copyright (c) 2016 by Delphix. All rights reserved.
15  */
16 
17 #include <sys/sdt.h>
18 #include "cpqary3.h"
19 
20 /*
21  * Local Functions Definitions
22  */
23 
24 uint8_t cpqary3_format_unit(cpqary3_cmdpvt_t *);
25 
26 static uint8_t cpqary3_probe4LVs(cpqary3_t *);
27 static uint8_t cpqary3_probe4Tapes(cpqary3_t *);
28 
29 
30 /*
31  * Function	:	cpqary3_probe4targets
32  * Description	: 	This routine detects all existing logical drives
33  *			and updates per target structure.
34  * Called By	:  	cpqary3_tgt_init()
35  * Parameters	: 	per-controller
36  * Calls	:  	cpqary3_probe4LVs(), cpqary3_probe4Tapes()
37  * Return Values: 	SUCCESS/ FAILURE
38  *			[Shall fail only if Memory Constraints exist, the
39  *			controller is defective/does not respond]
40  */
41 uint8_t
42 cpqary3_probe4targets(cpqary3_t *cpqary3p)
43 {
44 	uint8_t rv;
45 
46 	rv = cpqary3_probe4LVs(cpqary3p);
47 
48 	if (CPQARY3_FAILURE == rv) {
49 		return (rv);
50 	}
51 
52 	rv = cpqary3_probe4Tapes(cpqary3p);
53 
54 	if (CPQARY3_FAILURE == rv) {
55 		return (rv);
56 	}
57 
58 	return (CPQARY3_SUCCESS);
59 
60 }
61 
62 /*
63  * Function	:	cpqary3_build_cmdlist
64  * Description	: 	This routine builds the command list for the specific
65  *			opcode.
66  * Called By	: 	cpqary3_transport()
67  * Parameters	: 	cmdlist pvt struct, target id as received by SA.
68  * Calls	: 	None
69  * Return Values: 	SUCCESS		: 	Build is successful
70  *			FAILURE		: 	Build has Failed
71  */
72 uint8_t
73 cpqary3_build_cmdlist(cpqary3_cmdpvt_t *cpqary3_cmdpvtp, uint32_t tid)
74 {
75 	int		cntr;
76 	cpqary3_t	*cpqary3p;
77 	struct buf	*bfp;
78 	cpqary3_tgt_t	*tgtp;
79 	CommandList_t	*cmdlistp;
80 
81 	RETURN_FAILURE_IF_NULL(cpqary3_cmdpvtp);
82 
83 	if (NULL == (cpqary3p = cpqary3_cmdpvtp->ctlr))
84 		return (CPQARY3_FAILURE);
85 
86 	bfp = (struct buf *)cpqary3_cmdpvtp->pvt_pkt->bf;
87 
88 	tgtp = cpqary3p->cpqary3_tgtp[tid];
89 
90 	if (!tgtp) {
91 		return (CPQARY3_FAILURE);
92 	}
93 
94 	cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
95 
96 	/* Update Cmd Header */
97 	cmdlistp->Header.SGList = cpqary3_cmdpvtp->pvt_pkt->cmd_cookiecnt;
98 	cmdlistp->Header.SGTotal = cpqary3_cmdpvtp->pvt_pkt->cmd_cookiecnt;
99 	cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_OSCMD_SUCCESS;
100 
101 	if (tgtp->type == CPQARY3_TARGET_CTLR) {
102 		cmdlistp->Header.LUN.PhysDev.TargetId = 0;
103 		cmdlistp->Header.LUN.PhysDev.Bus = 0;
104 		cmdlistp->Header.LUN.PhysDev.Mode = MASK_PERIPHERIAL_DEV_ADDR;
105 	} else if (tgtp->type == CPQARY3_TARGET_LOG_VOL) {
106 		cmdlistp->Header.LUN.LogDev.VolId = tgtp->logical_id;
107 		cmdlistp->Header.LUN.LogDev.Mode = LOGICAL_VOL_ADDR;
108 	} else if (tgtp->type == CPQARY3_TARGET_TAPE) {
109 		bcopy(&(tgtp->PhysID), &(cmdlistp->Header.LUN.PhysDev),
110 		    sizeof (PhysDevAddr_t));
111 
112 		DTRACE_PROBE1(build_cmdlist_tape, CommandList_t *, cmdlistp);
113 	}
114 
115 	/* Cmd Request */
116 	cmdlistp->Request.CDBLen = cpqary3_cmdpvtp->pvt_pkt->cdb_len;
117 
118 	bcopy((caddr_t)cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt->pkt_cdbp,
119 	    (caddr_t)cmdlistp->Request.CDB, cpqary3_cmdpvtp->pvt_pkt->cdb_len);
120 
121 
122 	cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
123 	cmdlistp->Request.Type.Attribute = CISS_ATTR_ORDERED;
124 
125 	DTRACE_PROBE2(build_cmdlist_buf, struct buf *, bfp,
126 	    CommandList_t *, cmdlistp);
127 
128 	if (bfp && (bfp->b_flags & B_READ))
129 		cmdlistp->Request.Type.Direction = CISS_XFER_READ;
130 	else if (bfp && (bfp->b_flags & B_WRITE))
131 		cmdlistp->Request.Type.Direction = CISS_XFER_WRITE;
132 	else
133 		cmdlistp->Request.Type.Direction = CISS_XFER_NONE;
134 	/*
135 	 * Looks like the above Direction is going for a toss in case of
136 	 * MSA20(perticularly for 0x0a-write) connected to SMART Array.
137 	 * If the above check fails, the below switch should take care.
138 	 */
139 
140 	switch (cmdlistp->Request.CDB[0]) {
141 		case 0x08:
142 		case 0x28:
143 			cmdlistp->Request.Type.Direction = CISS_XFER_READ;
144 			break;
145 		case 0x0A:
146 		case 0x2A:
147 			cmdlistp->Request.Type.Direction = CISS_XFER_WRITE;
148 			break;
149 	}
150 	/*
151 	 * NEED to increase this TimeOut value when the concerned
152 	 * targets are tape devices(i.e., we need to do it here manually).
153 	 */
154 	cmdlistp->Request.Timeout = 2 *
155 	    (cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt->pkt_time);
156 
157 	for (cntr = 0; cntr < cpqary3_cmdpvtp->pvt_pkt->cmd_cookiecnt; cntr++) {
158 		cmdlistp->SG[cntr].Addr =
159 		    cpqary3_cmdpvtp->pvt_pkt->
160 		    cmd_dmacookies[cntr].dmac_laddress;
161 		cmdlistp->SG[cntr].Len = (uint32_t)
162 		    cpqary3_cmdpvtp->pvt_pkt->cmd_dmacookies[cntr].dmac_size;
163 	}
164 
165 	return (CPQARY3_SUCCESS);
166 }
167 
168 
169 /*
170  * Function	: 	cpqary3_send_abortcmd
171  * Description	: 	Sends the Abort command to abort
172  *			a set of cmds(on a target) or a cmdlist.
173  * Called By	: 	cpqary3_abort
174  * Parameters	: 	per controller, target_id, cmdlist to abort
175  * Calls	:  	cpqary3_synccmd_alloc(), cpqary3_synccmd_send(),
176  *			cpqary3_synccmd_free()
177  * Return Values: 	SUCCESS - abort cmd submit is successful.
178  *			FAILURE - Could not submit the abort cmd.
179  */
180 uint8_t
181 cpqary3_send_abortcmd(cpqary3_t *cpqary3p, uint16_t target_id,
182     CommandList_t *cmdlist2abortp)
183 {
184 	CommandList_t		*cmdlistp;
185 	cpqary3_tgt_t		*cpqtgtp;
186 	cpqary3_tag_t		*cpqary3_tagp;
187 	cpqary3_cmdpvt_t	*cpqary3_cmdpvtp;
188 
189 	/*
190 	 * NOTE : DO NOT perform this operation for cmdlist2abortp.
191 	 * It may be NULL
192 	 */
193 	RETURN_FAILURE_IF_NULL(cpqary3p);
194 
195 	if (target_id == CTLR_SCSI_ID)
196 		return (CPQARY3_FAILURE);
197 
198 	cpqtgtp = cpqary3p->cpqary3_tgtp[target_id];
199 
200 	if (!cpqtgtp) {
201 		return (CPQARY3_FAILURE);
202 	}
203 
204 	/*
205 	 * Occupy the Command List
206 	 * Update the Command List accordingly
207 	 * Submit the command and wait for a signal
208 	 */
209 
210 	/* BGB: CVFIX -> Introduced the call to cpqary3_synccmd_alloc */
211 	cpqary3_cmdpvtp = cpqary3_synccmd_alloc(cpqary3p, 0);
212 	if (cpqary3_cmdpvtp == NULL)
213 		return (CPQARY3_FAILURE);
214 
215 	cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
216 
217 	cmdlistp->Header.SGList = 0;
218 	cmdlistp->Header.SGTotal = 0;
219 	cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS;
220 	cmdlistp->Header.LUN.PhysDev.TargetId = 0;
221 	cmdlistp->Header.LUN.PhysDev.Bus = 0;
222 	cmdlistp->Header.LUN.PhysDev.Mode = PERIPHERIAL_DEV_ADDR;
223 
224 	cmdlistp->Request.Type.Type = CISS_TYPE_MSG;
225 	cmdlistp->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
226 	cmdlistp->Request.Type.Direction = CISS_XFER_NONE;
227 	cmdlistp->Request.Timeout = CISS_NO_TIMEOUT;
228 	cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_16;
229 	cmdlistp->Request.CDB[0] = CISS_MSG_ABORT;
230 
231 	if (cmdlist2abortp) { /* Abort this Particular Task */
232 		cmdlistp->Request.CDB[1] = CISS_ABORT_TASK;
233 		cpqary3_tagp = (cpqary3_tag_t *)&cmdlistp->Request.CDB[4];
234 		cpqary3_tagp->drvinfo_n_err =
235 		    cmdlist2abortp->Header.Tag.drvinfo_n_err;
236 		cpqary3_tagp->tag_value = cmdlist2abortp->Header.Tag.tag_value;
237 	} else { /* Abort all tasks for this Target */
238 		cmdlistp->Request.CDB[1] = CISS_ABORT_TASKSET;
239 
240 		switch (cpqtgtp->type) {
241 		case CPQARY3_TARGET_LOG_VOL:
242 			cmdlistp->Header.LUN.LogDev.Mode = LOGICAL_VOL_ADDR;
243 			cmdlistp->Header.LUN.LogDev.VolId = cpqtgtp->logical_id;
244 			break;
245 		case CPQARY3_TARGET_TAPE:
246 			bcopy(&(cpqtgtp->PhysID),
247 			    &(cmdlistp->Header.LUN.PhysDev),
248 			    sizeof (PhysDevAddr_t));
249 		}
250 	}
251 
252 	/* PERF */
253 
254 	cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
255 
256 	/* PERF */
257 
258 	/* BGB: CVFIX -> Introduced a call to cpqary3_synccmd_send */
259 	if (cpqary3_synccmd_send(cpqary3p, cpqary3_cmdpvtp, 30000,
260 	    CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
261 		cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
262 		return (CPQARY3_FAILURE);
263 	}
264 
265 	if (cpqary3_cmdpvtp->cmdlist_memaddr->Header.Tag.drvinfo_n_err ==
266 	    CPQARY3_SYNCCMD_FAILURE) {
267 		cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
268 		return (CPQARY3_FAILURE);
269 	}
270 
271 	cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
272 
273 	return (CPQARY3_SUCCESS);
274 
275 }
276 
277 
278 /*
279  * Function	: 	cpqary3_fulsh_cache
280  * Description	: 	This routine flushes the controller cache.
281  * Called By	: 	cpqary3_detach(), cpqary3_additional_cmd()
282  * Parameters	: 	per controller
283  * Calls	:  	cpqary3_synccmd_alloc(), cpqary3_synccmd_send()
284  *			cpqary3_synccmd_free()
285  * Return Values:	None
286  */
287 void
288 cpqary3_flush_cache(cpqary3_t *cpqary3p)
289 {
290 	CommandList_t		*cmdlistp;
291 	cpqary3_cmdpvt_t	*cpqary3_cmdpvtp;
292 
293 	/*
294 	 * Occupy the Command List
295 	 * Allocate Physically Contigous Memory for the FLUSH CACHE buffer
296 	 * Update the Command List accordingly
297 	 * Submit the command and wait for a signal
298 	 */
299 
300 	ASSERT(cpqary3p != NULL);
301 
302 	/* grab a command and allocate a dma buffer */
303 	cpqary3_cmdpvtp = cpqary3_synccmd_alloc(cpqary3p,
304 	    sizeof (flushcache_buf_t));
305 	if (cpqary3_cmdpvtp == NULL)
306 		return;
307 
308 	cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
309 	cmdlistp->Header.SGList = 1;
310 	cmdlistp->Header.SGTotal = 1;
311 	cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS;
312 	cmdlistp->Header.LUN.PhysDev.TargetId = 0;
313 	cmdlistp->Header.LUN.PhysDev.Bus = 0;
314 	cmdlistp->Header.LUN.PhysDev.Mode = PERIPHERIAL_DEV_ADDR;
315 
316 	cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_16;
317 	cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
318 	cmdlistp->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
319 	cmdlistp->Request.Type.Direction = CISS_XFER_WRITE;
320 	cmdlistp->Request.Timeout = CISS_NO_TIMEOUT;
321 	cmdlistp->Request.CDB[0] = ARRAY_WRITE;
322 	cmdlistp->Request.CDB[6] = CISS_FLUSH_CACHE; /* 0xC2 */
323 	cmdlistp->Request.CDB[8] = 0x02;
324 
325 	/* PERF */
326 
327 	cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
328 
329 	/* PERF */
330 
331 	if (cpqary3_synccmd_send(cpqary3p, cpqary3_cmdpvtp, 90000,
332 	    CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
333 		cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
334 		cmn_err(CE_WARN, "CPQary3  %s : Flush Cache Operation"
335 		    "Failed, Timeout", cpqary3p->hba_name);
336 		return;
337 	}
338 
339 	cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
340 }
341 
342 /*
343  * Function	:  	cpqary3_probe4LVs
344  * Description	:  	This routine probes for the logical drives
345  *			configured on the HP Smart Array controllers
346  * Called By	:  	cpqary3_probe4targets()
347  * Parameters	:  	per controller
348  * Calls	:  	cpqary3_synccmd_alloc(), cpqary3_synccmd_send()
349  *			cpqary3_synccmd_free()
350  * Return Values:  	None
351  */
352 uint8_t
353 cpqary3_probe4LVs(cpqary3_t *cpqary3p)
354 {
355 	ulong_t			log_lun_no = 0;
356 	ulong_t			lun_id = 0;
357 	ulong_t			ld_count = 0;
358 	ulong_t			i = 0;
359 	ulong_t			cntr = 0;
360 	uint32_t		data_addr_len;
361 	rll_data_t		*rllp;
362 	CommandList_t		*cmdlistp;
363 	cpqary3_cmdpvt_t	*cpqary3_cmdpvtp;
364 
365 	/*
366 	 * Occupy the Command List
367 	 * Allocate Physically Contigous Memory
368 	 * Update the Command List for Report Logical LUNS (rll) Command
369 	 * This command detects all existing logical drives.
370 	 * Submit and Poll for completion
371 	 */
372 
373 	RETURN_FAILURE_IF_NULL(cpqary3p);
374 
375 	/* Sync Changes */
376 	cpqary3_cmdpvtp = cpqary3_synccmd_alloc(cpqary3p, sizeof (rll_data_t));
377 	if (cpqary3_cmdpvtp == NULL)
378 		return (CPQARY3_FAILURE);
379 
380 	cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
381 	rllp = (rll_data_t *)cpqary3_cmdpvtp->driverdata->sg;
382 
383 	cmdlistp->Header.SGList = 1;
384 	cmdlistp->Header.SGTotal = 1;
385 	cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS;
386 	cmdlistp->Header.LUN.PhysDev.Mode = MASK_PERIPHERIAL_DEV_ADDR;
387 
388 	cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_12;
389 	cmdlistp->Request.Timeout = CISS_NO_TIMEOUT;
390 	cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
391 	cmdlistp->Request.Type.Attribute = CISS_ATTR_ORDERED;
392 	cmdlistp->Request.Type.Direction = CISS_XFER_READ;
393 	cmdlistp->Request.CDB[0] = CISS_OPCODE_RLL;
394 
395 	data_addr_len = sizeof (rll_data_t);
396 
397 	cmdlistp->Request.CDB[6] = (data_addr_len >> 24) & 0xff;
398 	cmdlistp->Request.CDB[7] = (data_addr_len >> 16) & 0xff;
399 	cmdlistp->Request.CDB[8] = (data_addr_len >> 8) & 0xff;
400 	cmdlistp->Request.CDB[9] = (data_addr_len) & 0xff;
401 
402 	DTRACE_PROBE2(rll_cmd_send, CommandList_t *, cmdlistp,
403 	    cpqary3_cmdpvt_t *, cpqary3_cmdpvtp);
404 
405 	/* PERF */
406 	cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
407 	/* PERF */
408 
409 	if (cpqary3_synccmd_send(cpqary3p, cpqary3_cmdpvtp, 90000,
410 	    CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
411 		cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
412 		return (CPQARY3_FAILURE);
413 	}
414 
415 	if ((cpqary3_cmdpvtp->cmdlist_memaddr->Header.Tag.drvinfo_n_err ==
416 	    CPQARY3_SYNCCMD_FAILURE) &&
417 	    (cpqary3_cmdpvtp->errorinfop->CommandStatus !=
418 	    CISS_CMD_DATA_UNDERRUN)) {
419 		cmn_err(CE_WARN, "CPQary3 : Probe for logical targets "
420 		    "returned ERROR !");
421 		DTRACE_PROBE1(rll_cmd_fail,
422 		    ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop);
423 		cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
424 		return (CPQARY3_FAILURE);
425 	}
426 	/* Sync Changes */
427 
428 	log_lun_no = ((rllp->lunlist_byte0 + (rllp->lunlist_byte1 << 8) +
429 	    (rllp->lunlist_byte2 << 16) + (rllp->lunlist_byte3 << 24)) / 8);
430 
431 	DTRACE_PROBE2(rll_cmd_result, rll_data_t *, rllp, ulong_t, log_lun_no);
432 
433 	/*
434 	 * The following is to restrict the maximum number of supported logical
435 	 * volumes to 32. This is very important as controller support upto 128
436 	 * logical volumes and this driver implementation supports only 32.
437 	 */
438 
439 	if (log_lun_no > MAX_LOGDRV) {
440 		log_lun_no = MAX_LOGDRV;
441 	}
442 
443 	cpqary3p->num_of_targets = log_lun_no;
444 	DTRACE_PROBE1(update_lvlun_count, ulong_t, log_lun_no);
445 
446 	/*
447 	 * Update per target structure with relevant information
448 	 * CPQARY#_TGT_ALLIGNMENT is 1 because of the following mapping:
449 	 * Target IDs 0-6 	in the OS = Logical Drives 0 - 6 in the HBA
450 	 * Target ID  7 	in the OS = none in the HBA
451 	 * Target IDs 8-32 	in the OS = Logical Drives 7 - 31 in the HBA
452 	 * Everytime we reference a logical drive with ID > 6, we shall use
453 	 * the alignment.
454 	 */
455 
456 
457 	/*
458 	 * Depending upon the value of the variable legacy_mapping set in
459 	 * cpqary3_attach(),
460 	 * the target mapping algorithm to be used by the driver is decided.
461 	 *
462 	 * If the value of legacy_mapping is set to one, in the case of
463 	 * Logical Drives with holes,
464 	 * Targets will be renumbered by the driver as shown below
465 	 * Below example makes the mapping logic clear.
466 	 *
467 	 * Logical Drive 0 in the HBA -> Target  ID 0 i.e., cXt0dXsx
468 	 * Logical Drive 2 in the HBA ->  Target ID 1 i.e., cXt1dXsX
469 	 * Logical Drive 3 in the HBA ->  Target ID 2 i.e., cXt2dXsX
470 	 *
471 	 * If the value of legacy_mapping is not one, then the Logical
472 	 * Drive numbers will
473 	 * not be renumbered in the case of holes, and the mapping
474 	 * will be done as shown below
475 	 * This will be the default mapping from 1.80 cpqary3 driver.
476 	 *
477 	 * Logical Drive 0  in the HBA -> Target ID 0 i.e. cXt0dXsx
478 	 * Logical Drive 2 in the HBA ->  Target ID 2 i.e. cXt2dXsX
479 	 * Logical Drive 3 in the HBA ->  Target ID 3 i.e. cXt3dXsX
480 	 */
481 
482 
483 	if (cpqary3p->legacy_mapping == 1) {
484 		for (cntr = 0; cntr < log_lun_no; cntr++) {
485 			i = ((cntr < CTLR_SCSI_ID) ?
486 			    cntr : cntr + CPQARY3_TGT_ALIGNMENT);
487 			if (!(cpqary3p->cpqary3_tgtp[i] = (cpqary3_tgt_t *)
488 			    MEM_ZALLOC(sizeof (cpqary3_tgt_t)))) {
489 				cmn_err(CE_WARN, "CPQary3 : Failed to Detect "
490 				    "targets, Memory Allocation Failure");
491 				cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
492 				return (CPQARY3_FAILURE);
493 			}
494 
495 			cpqary3p->cpqary3_tgtp[i]->logical_id =
496 			    rllp->ll_data[cntr].logical_id;
497 
498 			cpqary3p->cpqary3_tgtp[i]->type =
499 			    CPQARY3_TARGET_LOG_VOL;
500 
501 			DTRACE_PROBE2(lvlun_remapped,
502 			    cpqary3_tgt_t *, cpqary3p->cpqary3_tgtp[i],
503 			    rpl_data_t *, &rllp->ll_data[cntr]);
504 		}
505 	} else {
506 		/*
507 		 * Fix for QXCR1000446657: Logical drives are re numbered after
508 		 * deleting a Logical drive.
509 		 * We are using new indexing mechanism to fill the
510 		 * cpqary3_tgtp[],
511 		 * Check given during memory allocation of cpqary3_tgtp
512 		 * elements, so that memory is not re-allocated each time the
513 		 * cpqary3_probe4LVs() is called.
514 		 * Check given while freeing the memory of the cpqary3_tgtp[]
515 		 * elements, when a hole is found in the Logical Drives
516 		 * configured.
517 		 */
518 
519 		/* ensure that the loop will break for cntr = 32 in any case */
520 		for (cntr = 0; ((ld_count < log_lun_no) && (cntr < MAX_LOGDRV));
521 		    cntr++) {
522 			i = ((cntr < CTLR_SCSI_ID) ?
523 			    cntr : cntr + CPQARY3_TGT_ALIGNMENT);
524 			lun_id = (rllp->ll_data[ld_count].logical_id & 0xFFFF);
525 			if (cntr != lun_id) {
526 				if (cpqary3p->cpqary3_tgtp[i]) {
527 					MEM_SFREE(cpqary3p->cpqary3_tgtp[i],
528 					    sizeof (cpqary3_tgt_t));
529 					cpqary3p->cpqary3_tgtp[i] = NULL;
530 				}
531 			} else {
532 				if (cpqary3p->cpqary3_tgtp[i] == NULL &&
533 				    !(cpqary3p->cpqary3_tgtp[i] =
534 				    (cpqary3_tgt_t *)MEM_ZALLOC(
535 				    sizeof (cpqary3_tgt_t)))) {
536 					cmn_err(CE_WARN,
537 					    "CPQary3 : Failed to Detect "
538 					    "targets, Memory Allocation "
539 					    "Failure");
540 					/* Sync Changes */
541 					cpqary3_synccmd_free(cpqary3p,
542 					    cpqary3_cmdpvtp);
543 					/* Sync Changes */
544 					return (CPQARY3_FAILURE);
545 				}
546 				cpqary3p->cpqary3_tgtp[i]->logical_id =
547 				    rllp->ll_data[ld_count].logical_id;
548 				cpqary3p->cpqary3_tgtp[i]->type =
549 				    CPQARY3_TARGET_LOG_VOL;
550 
551 				/*
552 				 * Send "BMIC sense logical drive status
553 				 * command to set the target type to
554 				 * CPQARY3_TARGET_NONE in case of logical
555 				 * drive failure
556 				 */
557 
558 				ld_count++;
559 			}
560 		}
561 
562 	}
563 
564 	/* HPQacucli Changes */
565 	for (; cntr < MAX_LOGDRV; cntr++) {
566 		cpqary3_tgt_t *t;
567 		i = ((cntr < CTLR_SCSI_ID) ?
568 		    cntr : cntr + CPQARY3_TGT_ALIGNMENT);
569 		t = cpqary3p->cpqary3_tgtp[i];
570 		cpqary3p->cpqary3_tgtp[i] = NULL;
571 		if (t) {
572 			MEM_SFREE(t, sizeof (*t));
573 		}
574 	}
575 	/* HPQacucli Changes */
576 
577 	/* Sync Changes */
578 	cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
579 	/* Sync Changes */
580 
581 	return (CPQARY3_SUCCESS);
582 }
583 
584 /*
585  * Function	:  	cpqary3_probe4Tapes
586  * Description	:  	This routine probes for the logical drives
587  *			configured on the HP Smart Array controllers
588  * Called By	:  	cpqary3_probe4targets()
589  * Parameters	:  	per controller
590  * Calls	:  	cpqary3_synccmd_alloc(), cpqary3_synccmd_send()
591  *			cpqary3_synccmd_free()
592  * Return Values:  	None
593  */
594 uint8_t
595 cpqary3_probe4Tapes(cpqary3_t *cpqary3p)
596 {
597 	uint8_t			phy_lun_no;
598 	uint32_t		ii = 0;
599 	uint8_t			cntr = 0;
600 	uint32_t		data_addr_len;
601 	rpl_data_t		*rplp;
602 	CommandList_t		*cmdlistp;
603 	cpqary3_cmdpvt_t	*cpqary3_cmdpvtp;
604 
605 	/*
606 	 * Occupy the Command List
607 	 * Allocate Physically Contigous Memory
608 	 * Update the Command List for Report Logical LUNS (rll) Command
609 	 * This command detects all existing logical drives.
610 	 * Submit and Poll for completion
611 	 */
612 
613 	RETURN_FAILURE_IF_NULL(cpqary3p);
614 
615 	/* Sync Changes */
616 	cpqary3_cmdpvtp = cpqary3_synccmd_alloc(cpqary3p, sizeof (rpl_data_t));
617 	if (cpqary3_cmdpvtp == NULL)
618 		return (CPQARY3_FAILURE);
619 
620 	cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
621 	rplp = (rpl_data_t *)cpqary3_cmdpvtp->driverdata->sg;
622 
623 	/* Sync Changes */
624 
625 	cmdlistp->Header.SGList = 1;
626 	cmdlistp->Header.SGTotal = 1;
627 	cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS;
628 	cmdlistp->Header.LUN.PhysDev.TargetId = 0;
629 	cmdlistp->Header.LUN.PhysDev.Bus = 0;
630 	cmdlistp->Header.LUN.PhysDev.Mode = MASK_PERIPHERIAL_DEV_ADDR;
631 
632 	cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_12;
633 	cmdlistp->Request.Timeout = CISS_NO_TIMEOUT;
634 	cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
635 	cmdlistp->Request.Type.Attribute = CISS_ATTR_ORDERED;
636 	cmdlistp->Request.Type.Direction = CISS_XFER_READ;
637 	cmdlistp->Request.CDB[0] = CISS_OPCODE_RPL;
638 
639 	data_addr_len = sizeof (rpl_data_t);
640 
641 	cmdlistp->Request.CDB[6] = (data_addr_len >> 24) & 0xff;
642 	cmdlistp->Request.CDB[7] = (data_addr_len >> 16) & 0xff;
643 	cmdlistp->Request.CDB[8] = (data_addr_len >> 8) & 0xff;
644 	cmdlistp->Request.CDB[9] = (data_addr_len) & 0xff;
645 
646 	DTRACE_PROBE2(tape_probe_cmd_send,
647 	    CommandList_t *, cmdlistp, cpqary3_cmdpvt_t *, cpqary3_cmdpvtp);
648 
649 	/* PERF */
650 	cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
651 	/* PERF */
652 
653 	/* Sync Changes */
654 
655 	if (cpqary3_synccmd_send(cpqary3p, cpqary3_cmdpvtp, 90000,
656 	    CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
657 		cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
658 		return (CPQARY3_FAILURE);
659 	}
660 
661 	if ((cpqary3_cmdpvtp->cmdlist_memaddr->Header.Tag.drvinfo_n_err ==
662 	    CPQARY3_SYNCCMD_FAILURE) &&
663 	    (cpqary3_cmdpvtp->errorinfop->CommandStatus !=
664 	    CISS_CMD_DATA_UNDERRUN)) {
665 		cmn_err(CE_WARN, "CPQary3 : Probe for physical targets "
666 		    "returned ERROR !");
667 		DTRACE_PROBE1(tape_probe_cmdfail,
668 		    ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop);
669 		cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
670 		return (CPQARY3_FAILURE);
671 	}
672 	/* Sync Changes */
673 
674 	phy_lun_no = ((rplp->lunlist_byte0 +
675 	    (rplp->lunlist_byte1 << 8) +
676 	    (rplp->lunlist_byte2 << 16) +
677 	    (rplp->lunlist_byte3 << 24)) / 8);
678 
679 	/*
680 	 *	Update per target structure with relevant information
681 	 * CPQARY3_TAPE_BASE is 33 because of the following mapping:
682 	 * Target IDs 0-6 	in the OS = Logical Drives 0 - 6 in the HBA
683 	 * Target ID  7 	in the OS = none in the HBA
684 	 * Target IDs 8-32 	in the OS = Logical Drives 7 - 31 in the HBA
685 	 * Target IDs 33 and above are reserved for Tapes and hence we need
686 	 * the alignment.
687 	 */
688 
689 
690 	/*
691 	 * HP Smart Array SAS controllers with Firmware revsion 5.14 or
692 	 * later support
693 	 * 64 Logical drives. So we are checking
694 	 * if the controller is SAS or CISS and then assigning the value of the
695 	 * TAPE BASE accordingly
696 	 */
697 
698 	if (cpqary3p->bddef->bd_flags & SA_BD_SAS) {
699 		ii = 0x41;	/* MAX_LOGDRV + 1 - 64 + 1 */
700 	} else {
701 		ii = 0x21;	/* MAX_LOGDRV + 1 - 32 + 1 */
702 	}
703 
704 	for (cntr = 0; cntr < phy_lun_no; cntr++) {
705 		if (rplp->pl_data[cntr].Mode == CISS_PHYS_MODE) {
706 			if (cpqary3p->cpqary3_tgtp[ii] == NULL &&
707 			    !(cpqary3p->cpqary3_tgtp[ii] =
708 			    (cpqary3_tgt_t *)
709 			    MEM_ZALLOC(sizeof (cpqary3_tgt_t)))) {
710 				cmn_err(CE_WARN, "CPQary3 : Failed to Detect "
711 				    "targets, Memory Allocation Failure");
712 				cpqary3_synccmd_free(cpqary3p,
713 				    cpqary3_cmdpvtp);
714 				return (CPQARY3_FAILURE);
715 			}
716 
717 			bcopy(&(rplp->pl_data[cntr]),
718 			    &(cpqary3p->cpqary3_tgtp[ii]->PhysID),
719 			    sizeof (PhysDevAddr_t));
720 
721 			cpqary3p->cpqary3_tgtp[ii]->type = CPQARY3_TARGET_TAPE;
722 
723 			DTRACE_PROBE1(tape_discovered,
724 			    cpqary3_tgt_t *, cpqary3p->cpqary3_tgtp[ii]);
725 
726 			ii++;
727 		}
728 	}
729 
730 	/* Sync Changes */
731 	cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
732 	/* Sync Changes */
733 
734 	return (CPQARY3_SUCCESS);
735 
736 }
737 
738 /*
739  * Function	:    cpqary3_synccmd_complete
740  * Description	:    This routine processes the completed commands
741  *			using the sync interface and
742  *			initiates any callback that is needed.
743  * Called By	:    cpqary3_transport
744  * Parameters	:    per-command
745  * Calls	:    cpqary3_cmdlist_release, cpqary3_synccmd_cleanup
746  * Return Values:    None
747  */
748 void
749 cpqary3_synccmd_complete(cpqary3_cmdpvt_t *cpqary3_cmdpvtp)
750 {
751 	cpqary3_t	*cpqary3p;
752 
753 	ASSERT(cpqary3_cmdpvtp != NULL);
754 
755 	if (CPQARY3_TIMEOUT == cpqary3_cmdpvtp->cmdpvt_flag) {
756 		cpqary3_cmdlist_release(cpqary3_cmdpvtp, CPQARY3_NO_MUTEX);
757 		return;
758 	}
759 
760 	cpqary3p = cpqary3_cmdpvtp->ctlr;
761 
762 	if (cpqary3_cmdpvtp->cmdpvt_flag == CPQARY3_SYNC_TIMEOUT) {
763 		/*
764 		 * The submitter has abandoned this command, so we
765 		 * have to free the resources here.
766 		 */
767 		mutex_exit(&(cpqary3p->sw_mutex));
768 		cpqary3_synccmd_cleanup(cpqary3_cmdpvtp);
769 		mutex_enter(&(cpqary3p->sw_mutex));
770 	} else {
771 		/* submitter is waiting; wake it up */
772 		cpqary3_cmdpvtp->cmdpvt_flag = 0;
773 
774 		/*
775 		 * Fix for Flush Cache Operation Timed out issue:
776 		 * cv_signal() wakes up only one blocked thread.
777 		 * We need to use cv_broadcast which unblocks
778 		 * all the blocked threads()
779 		 */
780 		cv_broadcast(&(cpqary3p->cv_ioctl_wait));
781 	}
782 }
783