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 /*
17 * Supported IOCTLs :
18 * CPQARY3_IOCTL_DRIVER_INFO - to get driver details
19 * CPQARY3_IOCTL_CTLR_INFO - to get controller details
20 * CPQARY3_IOCTL_BMIC_PASS - to pass BMIC commands
21 * CPQARY3_IOCTL_SCSI_PASS - to pass SCSI commands
22 */
23
24 #include "cpqary3.h"
25
26 /*
27 * Local Functions Declaration
28 */
29
30 static int32_t cpqary3_ioctl_send_bmiccmd(cpqary3_t *, cpqary3_bmic_pass_t *,
31 int);
32 static void cpqary3_ioctl_fil_bmic(CommandList_t *, cpqary3_bmic_pass_t *);
33 static void cpqary3_ioctl_fil_bmic_sas(CommandList_t *, cpqary3_bmic_pass_t *);
34 static int32_t cpqary3_ioctl_send_scsicmd(cpqary3_t *, cpqary3_scsi_pass_t *,
35 int);
36 static void cpqary3_ioctl_fil_scsi(CommandList_t *, cpqary3_scsi_pass_t *);
37
38 /*
39 * Global Variables Definitions
40 */
41
42 cpqary3_driver_info_t gdriver_info = {0};
43
44 /* Function Definitions */
45
46 /*
47 * Function : cpqary3_ioctl_driver_info
48 * Description : This routine will get major/ minor versions, Number of
49 * controllers detected & MAX Number of controllers
50 * supported
51 * Called By : cpqary3_ioctl
52 * Parameters : ioctl_reqp - address of the parameter sent from
53 * the application
54 * cpqary3p - address of the PerController structure
55 * mode - mode which comes from application
56 * Return Values: EFAULT on Failure, 0 on SUCCESS
57 */
58 int32_t
cpqary3_ioctl_driver_info(uintptr_t ioctl_reqp,int mode)59 cpqary3_ioctl_driver_info(uintptr_t ioctl_reqp, int mode)
60 {
61 cpqary3_ioctl_request_t *request;
62
63 request = (cpqary3_ioctl_request_t *)
64 MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t));
65
66 if (NULL == request)
67 return (FAILURE);
68
69 /*
70 * First let us copyin the ioctl_reqp user buffer to request(kernel)
71 * memory. This is very much recomended before we access any of the
72 * fields.
73 */
74 if (ddi_copyin((void *)ioctl_reqp, (void *)request,
75 sizeof (cpqary3_ioctl_request_t), mode)) {
76 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
77 return (EFAULT);
78 }
79
80 /*
81 * Fill up the global structure "gdriver_info" memory.
82 * Fill this structure with available info, which will be copied
83 * back later
84 */
85
86 (void) strcpy(gdriver_info.name, "cpqary3");
87 gdriver_info.version.minor = CPQARY3_MINOR_REV_NO;
88 gdriver_info.version.major = CPQARY3_MAJOR_REV_NO;
89 gdriver_info.version.dd = CPQARY3_REV_MONTH;
90 gdriver_info.version.mm = CPQARY3_REV_DATE;
91 gdriver_info.version.yyyy = CPQARY3_REV_YEAR;
92 gdriver_info.max_num_ctlr = MAX_CTLRS;
93
94 /*
95 * First Copy out the driver_info structure
96 */
97
98 if (ddi_copyout((void *)&gdriver_info, (void *)(uintptr_t)request->argp,
99 sizeof (cpqary3_driver_info_t), mode)) {
100 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
101 return (EFAULT);
102 }
103
104 /*
105 * Copy out the request structure back
106 */
107
108 if (ddi_copyout((void *)request, (void *)ioctl_reqp,
109 sizeof (cpqary3_ioctl_request_t), mode)) {
110 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
111 return (EFAULT);
112 }
113
114 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
115
116 /*
117 * Everything looks fine. So return SUCCESS
118 */
119
120 return (SUCCESS);
121 }
122
123 /*
124 * Function : cpqary3_ioctl_ctlr_info
125 * Description : This routine will get the controller related info, like
126 * board-id, subsystem-id, num of logical drives,
127 * slot number
128 * Called By : cpqary3_ioctl
129 * Parameters : ioctl_reqp - address of the parameter sent form the
130 * application
131 * cpqary3p - address of the PerController structure
132 * mode - mode which comes from application
133 * Return Values: EFAULT on Failure, 0 on SUCCESS
134 */
135 int32_t
cpqary3_ioctl_ctlr_info(uintptr_t ioctl_reqp,cpqary3_t * cpqary3p,int mode)136 cpqary3_ioctl_ctlr_info(uintptr_t ioctl_reqp, cpqary3_t *cpqary3p, int mode)
137 {
138 cpqary3_ioctl_request_t *request;
139 cpqary3_ctlr_info_t *ctlr_info;
140
141 request = (cpqary3_ioctl_request_t *)
142 MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t));
143
144 if (NULL == request)
145 return (FAILURE);
146
147 /*
148 * First let us copyin the buffer to kernel memory. This is very much
149 * recomended before we access any of the fields.
150 */
151
152 if (ddi_copyin((void *) ioctl_reqp, (void *)request,
153 sizeof (cpqary3_ioctl_request_t), mode)) {
154 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
155 return (EFAULT);
156 }
157
158 ctlr_info = (cpqary3_ctlr_info_t *)
159 MEM_ZALLOC(sizeof (cpqary3_ctlr_info_t));
160
161 if (NULL == ctlr_info) {
162 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
163 return (FAILURE);
164 }
165
166 /*
167 * in the driver, board_id is actually subsystem_id
168 */
169
170 ctlr_info->subsystem_id = cpqary3p->board_id;
171 ctlr_info->bus = cpqary3p->bus;
172 ctlr_info->dev = cpqary3p->dev;
173 ctlr_info->fun = cpqary3p->fun;
174 ctlr_info->num_of_tgts = cpqary3p->num_of_targets;
175 ctlr_info->controller_instance = cpqary3p->instance;
176
177 /*
178 * TODO: ctlr_info.slot_num has to be implemented
179 * state & board_id fields are kept for future implementation i
180 * if required!
181 */
182
183 /*
184 * First Copy out the ctlr_info structure
185 */
186
187 if (ddi_copyout((void *)ctlr_info, (void *)(uintptr_t)request->argp,
188 sizeof (cpqary3_ctlr_info_t), mode)) {
189 MEM_SFREE(ctlr_info, sizeof (cpqary3_ctlr_info_t));
190 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
191 return (EFAULT);
192 }
193
194 /*
195 * Copy out the request structure back
196 */
197
198 if (ddi_copyout((void *)request, (void *)ioctl_reqp,
199 sizeof (cpqary3_ioctl_request_t), mode)) {
200 MEM_SFREE(ctlr_info, sizeof (cpqary3_ctlr_info_t));
201 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
202 return (EFAULT);
203 }
204
205 MEM_SFREE(ctlr_info, sizeof (cpqary3_ctlr_info_t));
206 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
207
208 /*
209 * Everything looks fine. So return SUCCESS
210 */
211
212 return (SUCCESS);
213 }
214
215 /*
216 * Function : cpqary3_ioctl_bmic_pass
217 * Description : This routine will pass the BMIC commands to controller
218 * Called By : cpqary3_ioctl
219 * Parameters : ioctl_reqp - address of the parameter sent from the
220 * application
221 * cpqary3p - address of the PerController structure
222 * mode - mode which comes directly from application
223 * Return Values: EFAULT on Failure, 0 on SUCCESS
224 */
225 int32_t
cpqary3_ioctl_bmic_pass(uintptr_t ioctl_reqp,cpqary3_t * cpqary3p,int mode)226 cpqary3_ioctl_bmic_pass(uintptr_t ioctl_reqp, cpqary3_t *cpqary3p, int mode)
227 {
228 cpqary3_ioctl_request_t *request;
229 cpqary3_bmic_pass_t *bmic_pass;
230 int32_t retval = SUCCESS;
231
232 request = (cpqary3_ioctl_request_t *)
233 MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t));
234
235 if (NULL == request)
236 return (FAILURE);
237
238 /*
239 * First let us copyin the ioctl_reqp(user) buffer to request(kernel)
240 * memory. This is very much recommended before we access any of the
241 * fields.
242 */
243
244 if (ddi_copyin((void *)ioctl_reqp, (void *)request,
245 sizeof (cpqary3_ioctl_request_t), mode)) {
246 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
247 return (EFAULT);
248 }
249
250 bmic_pass = (cpqary3_bmic_pass_t *)
251 MEM_ZALLOC(sizeof (cpqary3_bmic_pass_t));
252
253 if (NULL == bmic_pass) {
254 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
255 return (FAILURE);
256 }
257
258 /*
259 * Copy in "cpqary3_bmic_pass_t" structure from argp member
260 * of ioctl_reqp.
261 */
262
263 if (ddi_copyin((void *)(uintptr_t)request->argp, (void *)bmic_pass,
264 sizeof (cpqary3_bmic_pass_t), mode)) {
265 MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t));
266 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
267 return (EFAULT);
268 }
269
270 /*
271 * Get the free command list, fill in the bmic command and send it
272 * to the controller. This will return 0 on success.
273 */
274
275 retval = cpqary3_ioctl_send_bmiccmd(cpqary3p, bmic_pass, mode);
276
277 /*
278 * Now copy the bmic_pass (kernel) to the user argp
279 */
280
281 if (ddi_copyout((void *) bmic_pass, (void *)(uintptr_t)request->argp,
282 sizeof (cpqary3_bmic_pass_t), mode)) {
283 MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t));
284 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
285 retval = EFAULT; /* copyout failed */
286 }
287
288 /*
289 * Now copy the request(kernel) to ioctl_reqp(user)
290 */
291
292 if (ddi_copyout((void *) request, (void *)ioctl_reqp,
293 sizeof (cpqary3_ioctl_request_t), mode)) {
294 MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t));
295 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
296 retval = EFAULT;
297 }
298
299 MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t));
300 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
301
302 return (retval);
303 }
304
305 /*
306 * Function : cpqary3_ioctl_send_bmiccmd
307 * Description : This routine will get the free command,
308 * allocate memory and send it to controller.
309 * Called By : cpqary3_ioctl_bmic_pass
310 * Parameters : cpqary3_t - PerController structure
311 * cpqary3_bmic_pass_t - bmic structure
312 * mode - mode value sent from application
313 * Return Values: 0 on success
314 * FAILURE, EFAULT, ETIMEOUT based on the failure
315 */
316
317 uint32_t cpqary3_ioctl_wait_ms = 30000;
318
319 static int32_t
cpqary3_ioctl_send_bmiccmd(cpqary3_t * cpqary3p,cpqary3_bmic_pass_t * bmic_pass,int mode)320 cpqary3_ioctl_send_bmiccmd(cpqary3_t *cpqary3p,
321 cpqary3_bmic_pass_t *bmic_pass, int mode)
322 {
323 cpqary3_cmdpvt_t *memp = NULL;
324 CommandList_t *cmdlist = NULL;
325 int8_t *databuf = NULL;
326 uint8_t retval = 0;
327
328 /* allocate a command with a dma buffer */
329 memp = cpqary3_synccmd_alloc(cpqary3p, bmic_pass->buf_len);
330 if (memp == NULL)
331 return (FAILURE);
332
333 /* Get the databuf when buf_len is greater than zero */
334 if (bmic_pass->buf_len > 0) {
335 databuf = memp->driverdata->sg;
336 }
337
338 cmdlist = memp->cmdlist_memaddr;
339
340 /*
341 * If io_direction is CPQARY3_SCSI_OUT, we have to copy user buffer
342 * to databuf
343 */
344
345 if (bmic_pass->io_direction == CPQARY3_SCSI_OUT) {
346 /* Do a copyin when buf_len is greater than zero */
347 if (bmic_pass->buf_len > 0) {
348 if (ddi_copyin((void*)(uintptr_t)(bmic_pass->buf),
349 (void*)databuf, bmic_pass->buf_len, mode)) {
350 cpqary3_synccmd_free(cpqary3p, memp);
351 return (EFAULT);
352 }
353 }
354 }
355
356 /*
357 * Now fill the command as per the BMIC
358 */
359 if (cpqary3p->bddef->bd_flags & SA_BD_SAS) {
360 cpqary3_ioctl_fil_bmic_sas(cmdlist, bmic_pass);
361 } else {
362 cpqary3_ioctl_fil_bmic(cmdlist, bmic_pass);
363 }
364
365
366 /* PERF */
367
368 memp->complete = cpqary3_synccmd_complete;
369
370 /* PERF */
371
372 /* send command to controller and wait for a reply */
373 if (cpqary3_synccmd_send(cpqary3p, memp, cpqary3_ioctl_wait_ms,
374 CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
375 cpqary3_synccmd_free(cpqary3p, memp);
376 return (ETIMEDOUT);
377 }
378
379 /*
380 * Now the command is completed and copy the buffers back
381 * First copy the buffer databuf to bmic_pass.buf
382 * which is used as a buffer before passing the command to the
383 * controller.
384 */
385
386 if (bmic_pass->io_direction == CPQARY3_SCSI_IN) {
387 /* Do a copyout when buf_len is greater than zero */
388 if (bmic_pass->buf_len > 0) {
389 if (ddi_copyout((void *)databuf,
390 (void *)(uintptr_t)bmic_pass->buf,
391 bmic_pass->buf_len, mode)) {
392 retval = EFAULT;
393 }
394 }
395 }
396
397 /*
398 * This is case where the command completes with error,
399 * Then tag would have set its 1st(10) bit.
400 */
401
402 if (cmdlist->Header.Tag.drvinfo_n_err == CPQARY3_SYNCCMD_FAILURE) {
403 bmic_pass->err_status = 1;
404 bcopy((caddr_t)memp->errorinfop, &bmic_pass->err_info,
405 sizeof (ErrorInfo_t));
406 switch (memp->errorinfop->CommandStatus) {
407 case CISS_CMD_DATA_OVERRUN :
408 case CISS_CMD_DATA_UNDERRUN :
409 case CISS_CMD_SUCCESS :
410 case CISS_CMD_TARGET_STATUS :
411 retval = SUCCESS;
412 break;
413 default :
414 retval = EIO;
415 break;
416 }
417 }
418
419 cpqary3_synccmd_free(cpqary3p, memp);
420
421 return (retval);
422 }
423
424 /*
425 * Function : cpqary3_ioctl_fil_bmic
426 * Description : This routine will fill the cmdlist with BMIC details
427 * Called By : cpqary3_ioctl_send_bmiccmd
428 * Parameters : cmdlist - command packet
429 * bmic_pass - bmic structure
430 * Return Values: void
431 */
432 static void
cpqary3_ioctl_fil_bmic(CommandList_t * cmdlist,cpqary3_bmic_pass_t * bmic_pass)433 cpqary3_ioctl_fil_bmic(CommandList_t *cmdlist,
434 cpqary3_bmic_pass_t *bmic_pass)
435 {
436 cmdlist->Header.SGTotal = 1;
437 cmdlist->Header.SGList = 1;
438 cmdlist->Request.CDBLen = bmic_pass->cmd_len;
439 cmdlist->Request.Timeout = bmic_pass->timeout;
440 cmdlist->Request.Type.Type = CISS_TYPE_CMD;
441 cmdlist->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
442
443 switch (bmic_pass->io_direction) {
444 case CPQARY3_SCSI_OUT:
445 cmdlist->Request.Type.Direction = CISS_XFER_WRITE;
446 break;
447 case CPQARY3_SCSI_IN:
448 cmdlist->Request.Type.Direction = CISS_XFER_READ;
449 break;
450 case CPQARY3_NODATA_XFER:
451 cmdlist->Request.Type.Direction = CISS_XFER_NONE;
452 break;
453 default:
454 cmdlist->Request.Type.Direction = CISS_XFER_RSVD;
455 break;
456 }
457
458 cmdlist ->Request.CDB[0] =
459 (bmic_pass->io_direction == CPQARY3_SCSI_IN) ? 0x26: 0x27;
460 cmdlist ->Request.CDB[1] = bmic_pass->unit_number; /* Unit Number */
461
462 /*
463 * BMIC Detail - bytes 2[MSB] to 5[LSB]
464 */
465
466 cmdlist->Request.CDB[2] = (bmic_pass->blk_number >> 24) & 0xff;
467 cmdlist->Request.CDB[3] = (bmic_pass->blk_number >> 16) & 0xff;
468 cmdlist->Request.CDB[4] = (bmic_pass->blk_number >> 8) & 0xff;
469 cmdlist->Request.CDB[5] = bmic_pass->blk_number;
470
471 cmdlist->Request.CDB[6] = bmic_pass->cmd; /* BMIC Command */
472
473 /* Transfer Length - bytes 7[MSB] to 8[LSB] */
474
475 cmdlist->Request.CDB[7] = (bmic_pass->buf_len >> 8) & 0xff;
476 cmdlist->Request.CDB[8] = bmic_pass->buf_len & 0xff;
477 cmdlist->Request.CDB[9] = 0x00; /* Reserved */
478
479 /*
480 * Copy the Lun address from the request
481 */
482
483 bcopy(&bmic_pass->lun_addr[0], &(cmdlist->Header.LUN),
484 sizeof (LUNAddr_t));
485 cmdlist->SG[0].Len = bmic_pass->buf_len;
486 }
487
488 /*
489 * Function : cpqary3_ioctl_scsi_pass
490 * Description : This routine will pass the SCSI commands to controller
491 * Called By : cpqary3_ioctl
492 * Parameters : ioctl_reqp - address of the parameter sent
493 * from the application
494 * cpqary3p - Addess of the percontroller stucture
495 * mode - mode which comes directly from application
496 * Return Values: EFAULT on Failure, 0 on SUCCESS
497 */
498 int32_t
cpqary3_ioctl_scsi_pass(uintptr_t ioctl_reqp,cpqary3_t * cpqary3p,int mode)499 cpqary3_ioctl_scsi_pass(uintptr_t ioctl_reqp, cpqary3_t *cpqary3p, int mode)
500 {
501 cpqary3_ioctl_request_t *request;
502 cpqary3_scsi_pass_t *scsi_pass;
503 int32_t retval = SUCCESS;
504
505 request = (cpqary3_ioctl_request_t *)
506 MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t));
507
508 if (NULL == request)
509 return (FAILURE);
510
511 /*
512 * First let us copyin the ioctl_reqp(user) buffer to request(kernel)
513 * memory. * This is very much recommended before we access any of
514 * the fields.
515 */
516
517 if (ddi_copyin((void *)ioctl_reqp, (void *)request,
518 sizeof (cpqary3_ioctl_request_t), mode)) {
519 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
520 return (EFAULT);
521 }
522
523 scsi_pass = (cpqary3_scsi_pass_t *)
524 MEM_ZALLOC(sizeof (cpqary3_scsi_pass_t));
525
526 if (NULL == scsi_pass) {
527 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
528 return (FAILURE);
529 }
530
531 /*
532 * Copy in "cpqary3_scsi_pass_t" structure from argp member
533 * of ioctl_reqp.
534 */
535
536 if (ddi_copyin((void *)(uintptr_t)request->argp, (void *)scsi_pass,
537 sizeof (cpqary3_scsi_pass_t), mode)) {
538 MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t));
539 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
540 return (EFAULT);
541 }
542
543 /*
544 * Get the free command list, fill in the scsi command and send it
545 * to the controller. This will return 0 on success.
546 */
547
548 retval = cpqary3_ioctl_send_scsicmd(cpqary3p, scsi_pass, mode);
549
550 /*
551 * Now copy the scsi_pass (kernel) to the user argp
552 */
553
554 if (ddi_copyout((void *)scsi_pass, (void *)(uintptr_t)request->argp,
555 sizeof (cpqary3_scsi_pass_t), mode)) {
556 MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t));
557 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
558 retval = EFAULT; /* copyout failed */
559 }
560
561 /*
562 * Now copy the request(kernel) to ioctl_reqp(user)
563 */
564
565 if (ddi_copyout((void *)request, (void *)ioctl_reqp,
566 sizeof (cpqary3_ioctl_request_t), mode)) {
567 MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t));
568 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
569 retval = EFAULT;
570 }
571
572 MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t));
573 MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
574
575 return (retval);
576 }
577
578 /*
579 * Function : cpqary3_ioctl_send_scsiccmd
580 * Description : This routine will pass the SCSI commands to controller
581 * Called By : cpqary3_ioctl_scsi_pass
582 * Parameters : cpqary3_t - PerController structure,
583 * cpqary3_scsi_pass_t - scsi parameter
584 * mode - sent from the application
585 * Return Values: 0 on success
586 * FAILURE, EFAULT, ETIMEOUT based on the failure
587 */
588 static int32_t
cpqary3_ioctl_send_scsicmd(cpqary3_t * cpqary3p,cpqary3_scsi_pass_t * scsi_pass,int mode)589 cpqary3_ioctl_send_scsicmd(cpqary3_t *cpqary3p,
590 cpqary3_scsi_pass_t *scsi_pass, int mode)
591 {
592 cpqary3_cmdpvt_t *memp = NULL;
593 CommandList_t *cmdlist = NULL;
594 int8_t *databuf = NULL;
595 uint8_t retval = 0;
596 NoeBuffer *evt;
597 uint16_t drive = 0;
598
599 /* allocate a command with a dma buffer */
600 memp = cpqary3_synccmd_alloc(cpqary3p, scsi_pass->buf_len);
601 if (memp == NULL)
602 return (FAILURE);
603
604 /* Get the databuf when buf_len is greater than zero */
605 if (scsi_pass->buf_len > 0) {
606 databuf = memp->driverdata->sg;
607 }
608
609 cmdlist = memp->cmdlist_memaddr;
610
611 if (scsi_pass->io_direction == CPQARY3_SCSI_OUT) {
612 /* Do a copyin when buf_len is greater than zero */
613 if (scsi_pass->buf_len > 0) {
614 if (ddi_copyin((void*)(uintptr_t)(scsi_pass->buf),
615 (void*)databuf, scsi_pass->buf_len, mode)) {
616 cpqary3_synccmd_free(cpqary3p, memp);
617 return (EFAULT);
618 }
619 }
620 }
621
622 /*
623 * Fill the scsi command
624 */
625 cpqary3_ioctl_fil_scsi(cmdlist, scsi_pass);
626
627 /* PERF */
628 memp->complete = cpqary3_synccmd_complete;
629 /* PERF */
630
631 /* send command to controller and wait for a reply */
632 if (cpqary3_synccmd_send(cpqary3p, memp, cpqary3_ioctl_wait_ms,
633 CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
634 cpqary3_synccmd_free(cpqary3p, memp);
635 return (ETIMEDOUT);
636 }
637
638 /*
639 * If the command sent is NOE
640 * if the event class is CLASS_LOGICAL_DRIVE
641 * if the subcalls code is zero and if detail change is zero
642 * if the event specific data[3] is either 1 or 2 ie., if
643 * if the logical drive is failed set the target type to
644 * CPQARY3_TARGET_NONE
645 */
646
647 /* NOE */
648 if (cpqary3p->noe_support == 0 &&
649 cmdlist->Request.CDB[0] == 0x26 &&
650 cmdlist->Request.CDB[6] == BMIC_NOTIFY_ON_EVENT) {
651
652 evt = (NoeBuffer*)MEM2DRVPVT(memp)->sg;
653
654 if (evt->event_class_code == CLASS_LOGICAL_DRIVE &&
655 evt->event_subclass_code == SUB_CLASS_STATUS &&
656 evt->event_detail_code == DETAIL_CHANGE &&
657 evt->event_specific_data[3] == 1) {
658 /* LINTED: alignment */
659 drive = *(uint16_t *)(&evt->event_specific_data[0]);
660 drive = ((drive < CTLR_SCSI_ID) ?
661 drive : drive + CPQARY3_TGT_ALIGNMENT);
662
663 if (cpqary3p && cpqary3p->cpqary3_tgtp[drive]) {
664 cpqary3p->cpqary3_tgtp[drive]->type =
665 CPQARY3_TARGET_NONE;
666 }
667 }
668 }
669
670 /*
671 * Now the command is completed and copy the buffers back
672 * First copy the buffer databuf to scsi_pass->buf
673 * which is used as a buffer before passing the command to the
674 * controller.
675 */
676
677 if (scsi_pass->io_direction == CPQARY3_SCSI_IN) {
678 if (scsi_pass->buf_len > 0) {
679 if (ddi_copyout((void *)databuf,
680 (void *)(uintptr_t)scsi_pass->buf,
681 scsi_pass->buf_len, mode)) {
682 retval = EFAULT;
683 }
684 }
685 }
686
687 /*
688 * This is case where the command completes with error,
689 * Then tag would have set its 1st(10) bit.
690 */
691
692 if (cmdlist->Header.Tag.drvinfo_n_err == CPQARY3_SYNCCMD_FAILURE) {
693 scsi_pass->err_status = 1;
694 bcopy((caddr_t)memp->errorinfop, &scsi_pass->err_info,
695 sizeof (ErrorInfo_t));
696 switch (memp->errorinfop->CommandStatus) {
697 case CISS_CMD_DATA_OVERRUN:
698 case CISS_CMD_DATA_UNDERRUN:
699 case CISS_CMD_SUCCESS:
700 case CISS_CMD_TARGET_STATUS:
701 retval = SUCCESS;
702 break;
703 default:
704 retval = EIO;
705 break;
706 }
707 }
708
709 cpqary3_synccmd_free(cpqary3p, memp);
710
711 return (retval);
712 }
713
714 /*
715 * Function : cpqary3_ioctl_fil_scsi_
716 * Description : This routine will fill the cmdlist with SCSI CDB
717 * Called By : cpqary3_ioctl_send_scsicmd
718 * Parameters : cmdlist - command packet
719 * cpqary3_scsi_pass_t - scsi parameter
720 * Return Values: void
721 */
722 static void
cpqary3_ioctl_fil_scsi(CommandList_t * cmdlist,cpqary3_scsi_pass_t * scsi_pass)723 cpqary3_ioctl_fil_scsi(CommandList_t *cmdlist,
724 cpqary3_scsi_pass_t *scsi_pass)
725 {
726 cmdlist->Header.SGTotal = 1;
727 cmdlist->Header.SGList = 1;
728 cmdlist->Request.CDBLen = scsi_pass->cdb_len;
729 cmdlist->Request.Timeout = scsi_pass->timeout;
730 cmdlist->Request.Type.Type = CISS_TYPE_CMD;
731 cmdlist->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
732
733 switch (scsi_pass->io_direction) {
734 case CPQARY3_SCSI_OUT:
735 cmdlist->Request.Type.Direction = CISS_XFER_WRITE;
736 break;
737 case CPQARY3_SCSI_IN:
738 cmdlist->Request.Type.Direction = CISS_XFER_READ;
739 break;
740 case CPQARY3_NODATA_XFER:
741 cmdlist->Request.Type.Direction = CISS_XFER_NONE;
742 break;
743 default:
744 cmdlist->Request.Type.Direction = CISS_XFER_RSVD;
745 break;
746 }
747
748 /*
749 * Copy the SCSI CDB as is
750 */
751
752 bcopy(&scsi_pass->cdb[0], &cmdlist->Request.CDB[0],
753 scsi_pass->cdb_len);
754
755 /*
756 * Copy the Lun address from the request
757 */
758
759 bcopy(&scsi_pass->lun_addr[0], &(cmdlist->Header.LUN),
760 sizeof (LUNAddr_t));
761
762 cmdlist->SG[0].Len = scsi_pass->buf_len;
763 }
764
765 /*
766 * Function : cpqary3_ioctl_fil_bmic_sas
767 * Description : This routine will fill the cmdlist with BMIC details
768 * Called By : cpqary3_ioctl_send_bmiccmd
769 * Parameters : cmdlist - command packet
770 * bmic_pass - bmic structure
771 * Return Values: void
772 */
773 static void
cpqary3_ioctl_fil_bmic_sas(CommandList_t * cmdlist,cpqary3_bmic_pass_t * bmic_pass)774 cpqary3_ioctl_fil_bmic_sas(CommandList_t *cmdlist,
775 cpqary3_bmic_pass_t *bmic_pass)
776 {
777 cmdlist->Header.SGTotal = 1;
778 cmdlist->Header.SGList = 1;
779 cmdlist->Request.CDBLen = bmic_pass->cmd_len;
780 cmdlist->Request.Timeout = bmic_pass->timeout;
781 cmdlist->Request.Type.Type = CISS_TYPE_CMD;
782 cmdlist->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
783
784 switch (bmic_pass->io_direction) {
785 case CPQARY3_SCSI_OUT:
786 cmdlist->Request.Type.Direction = CISS_XFER_WRITE;
787 break;
788 case CPQARY3_SCSI_IN:
789 cmdlist->Request.Type.Direction = CISS_XFER_READ;
790 break;
791 case CPQARY3_NODATA_XFER:
792 cmdlist->Request.Type.Direction = CISS_XFER_NONE;
793 break;
794 default:
795 cmdlist->Request.Type.Direction = CISS_XFER_RSVD;
796 break;
797 }
798
799 cmdlist->Request.CDB[0] =
800 (bmic_pass->io_direction == CPQARY3_SCSI_IN) ? 0x26: 0x27;
801 cmdlist->Request.CDB[1] = bmic_pass->unit_number; /* Unit Number */
802
803 /*
804 * BMIC Detail - bytes 2[MSB] to 5[LSB]
805 */
806
807 cmdlist->Request.CDB[2] = (bmic_pass->blk_number >> 24) & 0xff;
808 cmdlist->Request.CDB[3] = (bmic_pass->blk_number >> 16) & 0xff;
809 cmdlist->Request.CDB[4] = (bmic_pass->blk_number >> 8) & 0xff;
810 cmdlist->Request.CDB[5] = bmic_pass->blk_number;
811
812 cmdlist->Request.CDB[6] = bmic_pass->cmd; /* BMIC Command */
813
814 /* Transfer Length - bytes 7[MSB] to 8[LSB] */
815
816 cmdlist->Request.CDB[7] = (bmic_pass->buf_len >> 8) & 0xff;
817 cmdlist->Request.CDB[8] = bmic_pass->buf_len & 0xff;
818 cmdlist->Request.CDB[9] = 0x00; /* Reserved */
819
820 /* Update CDB[2] = LSB bmix_index and CDB[9] = MSB bmic_index */
821 switch (bmic_pass->cmd) {
822 case HPSAS_ID_PHYSICAL_DRIVE:
823 case HPSAS_TAPE_INQUIRY:
824 case HPSAS_SENSE_MP_STAT:
825 case HPSAS_SET_MP_THRESHOLD:
826 case HPSAS_MP_PARAM_CONTROL:
827 case HPSAS_SENSE_DRV_ERR_LOG:
828 case HPSAS_SET_MP_VALUE:
829 cmdlist -> Request.CDB[2] = bmic_pass->bmic_index & 0xff;
830 cmdlist -> Request.CDB[9] = (bmic_pass->bmic_index >>8) & 0xff;
831 break;
832
833 case HPSAS_ID_LOG_DRIVE:
834 case HPSAS_SENSE_LOG_DRIVE:
835 case HPSAS_READ:
836 case HPSAS_WRITE:
837 case HPSAS_WRITE_THROUGH:
838 case HPSAS_SENSE_CONFIG:
839 case HPSAS_SET_CONFIG:
840 case HPSAS_BYPASS_VOL_STATE:
841 case HPSAS_CHANGE_CONFIG:
842 case HPSAS_SENSE_ORIG_CONFIG:
843 case HPSAS_LABEL_LOG_DRIVE:
844 /* Unit Number MSB */
845 cmdlist->Request.CDB[9] = (bmic_pass->unit_number >> 8) & 0xff;
846 break;
847
848 default:
849 break;
850 }
851
852
853 /*
854 * Copy the Lun address from the request
855 */
856
857 bcopy(&bmic_pass->lun_addr[0], &(cmdlist->Header.LUN),
858 sizeof (LUNAddr_t));
859
860 cmdlist->SG[0].Len = bmic_pass->buf_len;
861 }
862