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