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