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
  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
 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
 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
 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
 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
 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
 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
 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
 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 }