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
cpqary3_probe4targets(cpqary3_t * cpqary3p)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
cpqary3_build_cmdlist(cpqary3_cmdpvt_t * cpqary3_cmdpvtp,uint32_t tid)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
cpqary3_send_abortcmd(cpqary3_t * cpqary3p,uint16_t target_id,CommandList_t * cmdlist2abortp)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
cpqary3_flush_cache(cpqary3_t * cpqary3p)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
cpqary3_probe4LVs(cpqary3_t * cpqary3p)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
cpqary3_probe4Tapes(cpqary3_t * cpqary3p)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
cpqary3_synccmd_complete(cpqary3_cmdpvt_t * cpqary3_cmdpvtp)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