/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
*/
/*
* Supported IOCTLs :
* CPQARY3_IOCTL_DRIVER_INFO - to get driver details
* CPQARY3_IOCTL_CTLR_INFO - to get controller details
* CPQARY3_IOCTL_BMIC_PASS - to pass BMIC commands
* CPQARY3_IOCTL_SCSI_PASS - to pass SCSI commands
*/
#include "cpqary3.h"
/*
* Local Functions Declaration
*/
static int32_t cpqary3_ioctl_send_bmiccmd(cpqary3_t *, cpqary3_bmic_pass_t *,
int);
static void cpqary3_ioctl_fil_bmic(CommandList_t *, cpqary3_bmic_pass_t *);
static void cpqary3_ioctl_fil_bmic_sas(CommandList_t *, cpqary3_bmic_pass_t *);
static int32_t cpqary3_ioctl_send_scsicmd(cpqary3_t *, cpqary3_scsi_pass_t *,
int);
static void cpqary3_ioctl_fil_scsi(CommandList_t *, cpqary3_scsi_pass_t *);
/*
* Global Variables Definitions
*/
cpqary3_driver_info_t gdriver_info = {0};
/* Function Definitions */
/*
* Function : cpqary3_ioctl_driver_info
* Description : This routine will get major/ minor versions, Number of
* controllers detected & MAX Number of controllers
* supported
* Called By : cpqary3_ioctl
* Parameters : ioctl_reqp - address of the parameter sent from
* the application
* cpqary3p - address of the PerController structure
* mode - mode which comes from application
* Return Values: EFAULT on Failure, 0 on SUCCESS
*/
int32_t
cpqary3_ioctl_driver_info(uintptr_t ioctl_reqp, int mode)
{
cpqary3_ioctl_request_t *request;
request = (cpqary3_ioctl_request_t *)
MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t));
if (NULL == request)
return (FAILURE);
/*
* First let us copyin the ioctl_reqp user buffer to request(kernel)
* memory. This is very much recomended before we access any of the
* fields.
*/
if (ddi_copyin((void *)ioctl_reqp, (void *)request,
sizeof (cpqary3_ioctl_request_t), mode)) {
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (EFAULT);
}
/*
* Fill up the global structure "gdriver_info" memory.
* Fill this structure with available info, which will be copied
* back later
*/
(void) strcpy(gdriver_info.name, "cpqary3");
gdriver_info.version.minor = CPQARY3_MINOR_REV_NO;
gdriver_info.version.major = CPQARY3_MAJOR_REV_NO;
gdriver_info.version.dd = CPQARY3_REV_MONTH;
gdriver_info.version.mm = CPQARY3_REV_DATE;
gdriver_info.version.yyyy = CPQARY3_REV_YEAR;
gdriver_info.max_num_ctlr = MAX_CTLRS;
/*
* First Copy out the driver_info structure
*/
if (ddi_copyout((void *)&gdriver_info, (void *)(uintptr_t)request->argp,
sizeof (cpqary3_driver_info_t), mode)) {
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (EFAULT);
}
/*
* Copy out the request structure back
*/
if (ddi_copyout((void *)request, (void *)ioctl_reqp,
sizeof (cpqary3_ioctl_request_t), mode)) {
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (EFAULT);
}
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
/*
* Everything looks fine. So return SUCCESS
*/
return (SUCCESS);
}
/*
* Function : cpqary3_ioctl_ctlr_info
* Description : This routine will get the controller related info, like
* board-id, subsystem-id, num of logical drives,
* slot number
* Called By : cpqary3_ioctl
* Parameters : ioctl_reqp - address of the parameter sent form the
* application
* cpqary3p - address of the PerController structure
* mode - mode which comes from application
* Return Values: EFAULT on Failure, 0 on SUCCESS
*/
int32_t
cpqary3_ioctl_ctlr_info(uintptr_t ioctl_reqp, cpqary3_t *cpqary3p, int mode)
{
cpqary3_ioctl_request_t *request;
cpqary3_ctlr_info_t *ctlr_info;
request = (cpqary3_ioctl_request_t *)
MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t));
if (NULL == request)
return (FAILURE);
/*
* First let us copyin the buffer to kernel memory. This is very much
* recomended before we access any of the fields.
*/
if (ddi_copyin((void *) ioctl_reqp, (void *)request,
sizeof (cpqary3_ioctl_request_t), mode)) {
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (EFAULT);
}
ctlr_info = (cpqary3_ctlr_info_t *)
MEM_ZALLOC(sizeof (cpqary3_ctlr_info_t));
if (NULL == ctlr_info) {
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (FAILURE);
}
/*
* in the driver, board_id is actually subsystem_id
*/
ctlr_info->subsystem_id = cpqary3p->board_id;
ctlr_info->bus = cpqary3p->bus;
ctlr_info->dev = cpqary3p->dev;
ctlr_info->fun = cpqary3p->fun;
ctlr_info->num_of_tgts = cpqary3p->num_of_targets;
ctlr_info->controller_instance = cpqary3p->instance;
/*
* TODO: ctlr_info.slot_num has to be implemented
* state & board_id fields are kept for future implementation i
* if required!
*/
/*
* First Copy out the ctlr_info structure
*/
if (ddi_copyout((void *)ctlr_info, (void *)(uintptr_t)request->argp,
sizeof (cpqary3_ctlr_info_t), mode)) {
MEM_SFREE(ctlr_info, sizeof (cpqary3_ctlr_info_t));
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (EFAULT);
}
/*
* Copy out the request structure back
*/
if (ddi_copyout((void *)request, (void *)ioctl_reqp,
sizeof (cpqary3_ioctl_request_t), mode)) {
MEM_SFREE(ctlr_info, sizeof (cpqary3_ctlr_info_t));
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (EFAULT);
}
MEM_SFREE(ctlr_info, sizeof (cpqary3_ctlr_info_t));
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
/*
* Everything looks fine. So return SUCCESS
*/
return (SUCCESS);
}
/*
* Function : cpqary3_ioctl_bmic_pass
* Description : This routine will pass the BMIC commands to controller
* Called By : cpqary3_ioctl
* Parameters : ioctl_reqp - address of the parameter sent from the
* application
* cpqary3p - address of the PerController structure
* mode - mode which comes directly from application
* Return Values: EFAULT on Failure, 0 on SUCCESS
*/
int32_t
cpqary3_ioctl_bmic_pass(uintptr_t ioctl_reqp, cpqary3_t *cpqary3p, int mode)
{
cpqary3_ioctl_request_t *request;
cpqary3_bmic_pass_t *bmic_pass;
int32_t retval = SUCCESS;
request = (cpqary3_ioctl_request_t *)
MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t));
if (NULL == request)
return (FAILURE);
/*
* First let us copyin the ioctl_reqp(user) buffer to request(kernel)
* memory. This is very much recommended before we access any of the
* fields.
*/
if (ddi_copyin((void *)ioctl_reqp, (void *)request,
sizeof (cpqary3_ioctl_request_t), mode)) {
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (EFAULT);
}
bmic_pass = (cpqary3_bmic_pass_t *)
MEM_ZALLOC(sizeof (cpqary3_bmic_pass_t));
if (NULL == bmic_pass) {
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (FAILURE);
}
/*
* Copy in "cpqary3_bmic_pass_t" structure from argp member
* of ioctl_reqp.
*/
if (ddi_copyin((void *)(uintptr_t)request->argp, (void *)bmic_pass,
sizeof (cpqary3_bmic_pass_t), mode)) {
MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t));
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (EFAULT);
}
/*
* Get the free command list, fill in the bmic command and send it
* to the controller. This will return 0 on success.
*/
retval = cpqary3_ioctl_send_bmiccmd(cpqary3p, bmic_pass, mode);
/*
* Now copy the bmic_pass (kernel) to the user argp
*/
if (ddi_copyout((void *) bmic_pass, (void *)(uintptr_t)request->argp,
sizeof (cpqary3_bmic_pass_t), mode)) {
MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t));
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
retval = EFAULT; /* copyout failed */
}
/*
* Now copy the request(kernel) to ioctl_reqp(user)
*/
if (ddi_copyout((void *) request, (void *)ioctl_reqp,
sizeof (cpqary3_ioctl_request_t), mode)) {
MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t));
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
retval = EFAULT;
}
MEM_SFREE(bmic_pass, sizeof (cpqary3_bmic_pass_t));
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (retval);
}
/*
* Function : cpqary3_ioctl_send_bmiccmd
* Description : This routine will get the free command,
* allocate memory and send it to controller.
* Called By : cpqary3_ioctl_bmic_pass
* Parameters : cpqary3_t - PerController structure
* cpqary3_bmic_pass_t - bmic structure
* mode - mode value sent from application
* Return Values: 0 on success
* FAILURE, EFAULT, ETIMEOUT based on the failure
*/
uint32_t cpqary3_ioctl_wait_ms = 30000;
static int32_t
cpqary3_ioctl_send_bmiccmd(cpqary3_t *cpqary3p,
cpqary3_bmic_pass_t *bmic_pass, int mode)
{
cpqary3_cmdpvt_t *memp = NULL;
CommandList_t *cmdlist = NULL;
int8_t *databuf = NULL;
uint8_t retval = 0;
/* allocate a command with a dma buffer */
memp = cpqary3_synccmd_alloc(cpqary3p, bmic_pass->buf_len);
if (memp == NULL)
return (FAILURE);
/* Get the databuf when buf_len is greater than zero */
if (bmic_pass->buf_len > 0) {
databuf = memp->driverdata->sg;
}
cmdlist = memp->cmdlist_memaddr;
/*
* If io_direction is CPQARY3_SCSI_OUT, we have to copy user buffer
* to databuf
*/
if (bmic_pass->io_direction == CPQARY3_SCSI_OUT) {
/* Do a copyin when buf_len is greater than zero */
if (bmic_pass->buf_len > 0) {
if (ddi_copyin((void*)(uintptr_t)(bmic_pass->buf),
(void*)databuf, bmic_pass->buf_len, mode)) {
cpqary3_synccmd_free(cpqary3p, memp);
return (EFAULT);
}
}
}
/*
* Now fill the command as per the BMIC
*/
if (cpqary3p->bddef->bd_flags & SA_BD_SAS) {
cpqary3_ioctl_fil_bmic_sas(cmdlist, bmic_pass);
} else {
cpqary3_ioctl_fil_bmic(cmdlist, bmic_pass);
}
/* PERF */
memp->complete = cpqary3_synccmd_complete;
/* PERF */
/* send command to controller and wait for a reply */
if (cpqary3_synccmd_send(cpqary3p, memp, cpqary3_ioctl_wait_ms,
CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
cpqary3_synccmd_free(cpqary3p, memp);
return (ETIMEDOUT);
}
/*
* Now the command is completed and copy the buffers back
* First copy the buffer databuf to bmic_pass.buf
* which is used as a buffer before passing the command to the
* controller.
*/
if (bmic_pass->io_direction == CPQARY3_SCSI_IN) {
/* Do a copyout when buf_len is greater than zero */
if (bmic_pass->buf_len > 0) {
if (ddi_copyout((void *)databuf,
(void *)(uintptr_t)bmic_pass->buf,
bmic_pass->buf_len, mode)) {
retval = EFAULT;
}
}
}
/*
* This is case where the command completes with error,
* Then tag would have set its 1st(10) bit.
*/
if (cmdlist->Header.Tag.drvinfo_n_err == CPQARY3_SYNCCMD_FAILURE) {
bmic_pass->err_status = 1;
bcopy((caddr_t)memp->errorinfop, &bmic_pass->err_info,
sizeof (ErrorInfo_t));
switch (memp->errorinfop->CommandStatus) {
case CISS_CMD_DATA_OVERRUN :
case CISS_CMD_DATA_UNDERRUN :
case CISS_CMD_SUCCESS :
case CISS_CMD_TARGET_STATUS :
retval = SUCCESS;
break;
default :
retval = EIO;
break;
}
}
cpqary3_synccmd_free(cpqary3p, memp);
return (retval);
}
/*
* Function : cpqary3_ioctl_fil_bmic
* Description : This routine will fill the cmdlist with BMIC details
* Called By : cpqary3_ioctl_send_bmiccmd
* Parameters : cmdlist - command packet
* bmic_pass - bmic structure
* Return Values: void
*/
static void
cpqary3_ioctl_fil_bmic(CommandList_t *cmdlist,
cpqary3_bmic_pass_t *bmic_pass)
{
cmdlist->Header.SGTotal = 1;
cmdlist->Header.SGList = 1;
cmdlist->Request.CDBLen = bmic_pass->cmd_len;
cmdlist->Request.Timeout = bmic_pass->timeout;
cmdlist->Request.Type.Type = CISS_TYPE_CMD;
cmdlist->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
switch (bmic_pass->io_direction) {
case CPQARY3_SCSI_OUT:
cmdlist->Request.Type.Direction = CISS_XFER_WRITE;
break;
case CPQARY3_SCSI_IN:
cmdlist->Request.Type.Direction = CISS_XFER_READ;
break;
case CPQARY3_NODATA_XFER:
cmdlist->Request.Type.Direction = CISS_XFER_NONE;
break;
default:
cmdlist->Request.Type.Direction = CISS_XFER_RSVD;
break;
}
cmdlist ->Request.CDB[0] =
(bmic_pass->io_direction == CPQARY3_SCSI_IN) ? 0x26: 0x27;
cmdlist ->Request.CDB[1] = bmic_pass->unit_number; /* Unit Number */
/*
* BMIC Detail - bytes 2[MSB] to 5[LSB]
*/
cmdlist->Request.CDB[2] = (bmic_pass->blk_number >> 24) & 0xff;
cmdlist->Request.CDB[3] = (bmic_pass->blk_number >> 16) & 0xff;
cmdlist->Request.CDB[4] = (bmic_pass->blk_number >> 8) & 0xff;
cmdlist->Request.CDB[5] = bmic_pass->blk_number;
cmdlist->Request.CDB[6] = bmic_pass->cmd; /* BMIC Command */
/* Transfer Length - bytes 7[MSB] to 8[LSB] */
cmdlist->Request.CDB[7] = (bmic_pass->buf_len >> 8) & 0xff;
cmdlist->Request.CDB[8] = bmic_pass->buf_len & 0xff;
cmdlist->Request.CDB[9] = 0x00; /* Reserved */
/*
* Copy the Lun address from the request
*/
bcopy(&bmic_pass->lun_addr[0], &(cmdlist->Header.LUN),
sizeof (LUNAddr_t));
cmdlist->SG[0].Len = bmic_pass->buf_len;
}
/*
* Function : cpqary3_ioctl_scsi_pass
* Description : This routine will pass the SCSI commands to controller
* Called By : cpqary3_ioctl
* Parameters : ioctl_reqp - address of the parameter sent
* from the application
* cpqary3p - Addess of the percontroller stucture
* mode - mode which comes directly from application
* Return Values: EFAULT on Failure, 0 on SUCCESS
*/
int32_t
cpqary3_ioctl_scsi_pass(uintptr_t ioctl_reqp, cpqary3_t *cpqary3p, int mode)
{
cpqary3_ioctl_request_t *request;
cpqary3_scsi_pass_t *scsi_pass;
int32_t retval = SUCCESS;
request = (cpqary3_ioctl_request_t *)
MEM_ZALLOC(sizeof (cpqary3_ioctl_request_t));
if (NULL == request)
return (FAILURE);
/*
* First let us copyin the ioctl_reqp(user) buffer to request(kernel)
* memory. * This is very much recommended before we access any of
* the fields.
*/
if (ddi_copyin((void *)ioctl_reqp, (void *)request,
sizeof (cpqary3_ioctl_request_t), mode)) {
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (EFAULT);
}
scsi_pass = (cpqary3_scsi_pass_t *)
MEM_ZALLOC(sizeof (cpqary3_scsi_pass_t));
if (NULL == scsi_pass) {
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (FAILURE);
}
/*
* Copy in "cpqary3_scsi_pass_t" structure from argp member
* of ioctl_reqp.
*/
if (ddi_copyin((void *)(uintptr_t)request->argp, (void *)scsi_pass,
sizeof (cpqary3_scsi_pass_t), mode)) {
MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t));
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (EFAULT);
}
/*
* Get the free command list, fill in the scsi command and send it
* to the controller. This will return 0 on success.
*/
retval = cpqary3_ioctl_send_scsicmd(cpqary3p, scsi_pass, mode);
/*
* Now copy the scsi_pass (kernel) to the user argp
*/
if (ddi_copyout((void *)scsi_pass, (void *)(uintptr_t)request->argp,
sizeof (cpqary3_scsi_pass_t), mode)) {
MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t));
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
retval = EFAULT; /* copyout failed */
}
/*
* Now copy the request(kernel) to ioctl_reqp(user)
*/
if (ddi_copyout((void *)request, (void *)ioctl_reqp,
sizeof (cpqary3_ioctl_request_t), mode)) {
MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t));
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
retval = EFAULT;
}
MEM_SFREE(scsi_pass, sizeof (cpqary3_scsi_pass_t));
MEM_SFREE(request, sizeof (cpqary3_ioctl_request_t));
return (retval);
}
/*
* Function : cpqary3_ioctl_send_scsiccmd
* Description : This routine will pass the SCSI commands to controller
* Called By : cpqary3_ioctl_scsi_pass
* Parameters : cpqary3_t - PerController structure,
* cpqary3_scsi_pass_t - scsi parameter
* mode - sent from the application
* Return Values: 0 on success
* FAILURE, EFAULT, ETIMEOUT based on the failure
*/
static int32_t
cpqary3_ioctl_send_scsicmd(cpqary3_t *cpqary3p,
cpqary3_scsi_pass_t *scsi_pass, int mode)
{
cpqary3_cmdpvt_t *memp = NULL;
CommandList_t *cmdlist = NULL;
int8_t *databuf = NULL;
uint8_t retval = 0;
NoeBuffer *evt;
uint16_t drive = 0;
/* allocate a command with a dma buffer */
memp = cpqary3_synccmd_alloc(cpqary3p, scsi_pass->buf_len);
if (memp == NULL)
return (FAILURE);
/* Get the databuf when buf_len is greater than zero */
if (scsi_pass->buf_len > 0) {
databuf = memp->driverdata->sg;
}
cmdlist = memp->cmdlist_memaddr;
if (scsi_pass->io_direction == CPQARY3_SCSI_OUT) {
/* Do a copyin when buf_len is greater than zero */
if (scsi_pass->buf_len > 0) {
if (ddi_copyin((void*)(uintptr_t)(scsi_pass->buf),
(void*)databuf, scsi_pass->buf_len, mode)) {
cpqary3_synccmd_free(cpqary3p, memp);
return (EFAULT);
}
}
}
/*
* Fill the scsi command
*/
cpqary3_ioctl_fil_scsi(cmdlist, scsi_pass);
/* PERF */
memp->complete = cpqary3_synccmd_complete;
/* PERF */
/* send command to controller and wait for a reply */
if (cpqary3_synccmd_send(cpqary3p, memp, cpqary3_ioctl_wait_ms,
CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
cpqary3_synccmd_free(cpqary3p, memp);
return (ETIMEDOUT);
}
/*
* If the command sent is NOE
* if the event class is CLASS_LOGICAL_DRIVE
* if the subcalls code is zero and if detail change is zero
* if the event specific data[3] is either 1 or 2 ie., if
* if the logical drive is failed set the target type to
* CPQARY3_TARGET_NONE
*/
/* NOE */
if (cpqary3p->noe_support == 0 &&
cmdlist->Request.CDB[0] == 0x26 &&
cmdlist->Request.CDB[6] == BMIC_NOTIFY_ON_EVENT) {
evt = (NoeBuffer*)MEM2DRVPVT(memp)->sg;
if (evt->event_class_code == CLASS_LOGICAL_DRIVE &&
evt->event_subclass_code == SUB_CLASS_STATUS &&
evt->event_detail_code == DETAIL_CHANGE &&
evt->event_specific_data[3] == 1) {
/* LINTED: alignment */
drive = *(uint16_t *)(&evt->event_specific_data[0]);
drive = ((drive < CTLR_SCSI_ID) ?
drive : drive + CPQARY3_TGT_ALIGNMENT);
if (cpqary3p && cpqary3p->cpqary3_tgtp[drive]) {
cpqary3p->cpqary3_tgtp[drive]->type =
CPQARY3_TARGET_NONE;
}
}
}
/*
* Now the command is completed and copy the buffers back
* First copy the buffer databuf to scsi_pass->buf
* which is used as a buffer before passing the command to the
* controller.
*/
if (scsi_pass->io_direction == CPQARY3_SCSI_IN) {
if (scsi_pass->buf_len > 0) {
if (ddi_copyout((void *)databuf,
(void *)(uintptr_t)scsi_pass->buf,
scsi_pass->buf_len, mode)) {
retval = EFAULT;
}
}
}
/*
* This is case where the command completes with error,
* Then tag would have set its 1st(10) bit.
*/
if (cmdlist->Header.Tag.drvinfo_n_err == CPQARY3_SYNCCMD_FAILURE) {
scsi_pass->err_status = 1;
bcopy((caddr_t)memp->errorinfop, &scsi_pass->err_info,
sizeof (ErrorInfo_t));
switch (memp->errorinfop->CommandStatus) {
case CISS_CMD_DATA_OVERRUN:
case CISS_CMD_DATA_UNDERRUN:
case CISS_CMD_SUCCESS:
case CISS_CMD_TARGET_STATUS:
retval = SUCCESS;
break;
default:
retval = EIO;
break;
}
}
cpqary3_synccmd_free(cpqary3p, memp);
return (retval);
}
/*
* Function : cpqary3_ioctl_fil_scsi_
* Description : This routine will fill the cmdlist with SCSI CDB
* Called By : cpqary3_ioctl_send_scsicmd
* Parameters : cmdlist - command packet
* cpqary3_scsi_pass_t - scsi parameter
* Return Values: void
*/
static void
cpqary3_ioctl_fil_scsi(CommandList_t *cmdlist,
cpqary3_scsi_pass_t *scsi_pass)
{
cmdlist->Header.SGTotal = 1;
cmdlist->Header.SGList = 1;
cmdlist->Request.CDBLen = scsi_pass->cdb_len;
cmdlist->Request.Timeout = scsi_pass->timeout;
cmdlist->Request.Type.Type = CISS_TYPE_CMD;
cmdlist->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
switch (scsi_pass->io_direction) {
case CPQARY3_SCSI_OUT:
cmdlist->Request.Type.Direction = CISS_XFER_WRITE;
break;
case CPQARY3_SCSI_IN:
cmdlist->Request.Type.Direction = CISS_XFER_READ;
break;
case CPQARY3_NODATA_XFER:
cmdlist->Request.Type.Direction = CISS_XFER_NONE;
break;
default:
cmdlist->Request.Type.Direction = CISS_XFER_RSVD;
break;
}
/*
* Copy the SCSI CDB as is
*/
bcopy(&scsi_pass->cdb[0], &cmdlist->Request.CDB[0],
scsi_pass->cdb_len);
/*
* Copy the Lun address from the request
*/
bcopy(&scsi_pass->lun_addr[0], &(cmdlist->Header.LUN),
sizeof (LUNAddr_t));
cmdlist->SG[0].Len = scsi_pass->buf_len;
}
/*
* Function : cpqary3_ioctl_fil_bmic_sas
* Description : This routine will fill the cmdlist with BMIC details
* Called By : cpqary3_ioctl_send_bmiccmd
* Parameters : cmdlist - command packet
* bmic_pass - bmic structure
* Return Values: void
*/
static void
cpqary3_ioctl_fil_bmic_sas(CommandList_t *cmdlist,
cpqary3_bmic_pass_t *bmic_pass)
{
cmdlist->Header.SGTotal = 1;
cmdlist->Header.SGList = 1;
cmdlist->Request.CDBLen = bmic_pass->cmd_len;
cmdlist->Request.Timeout = bmic_pass->timeout;
cmdlist->Request.Type.Type = CISS_TYPE_CMD;
cmdlist->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
switch (bmic_pass->io_direction) {
case CPQARY3_SCSI_OUT:
cmdlist->Request.Type.Direction = CISS_XFER_WRITE;
break;
case CPQARY3_SCSI_IN:
cmdlist->Request.Type.Direction = CISS_XFER_READ;
break;
case CPQARY3_NODATA_XFER:
cmdlist->Request.Type.Direction = CISS_XFER_NONE;
break;
default:
cmdlist->Request.Type.Direction = CISS_XFER_RSVD;
break;
}
cmdlist->Request.CDB[0] =
(bmic_pass->io_direction == CPQARY3_SCSI_IN) ? 0x26: 0x27;
cmdlist->Request.CDB[1] = bmic_pass->unit_number; /* Unit Number */
/*
* BMIC Detail - bytes 2[MSB] to 5[LSB]
*/
cmdlist->Request.CDB[2] = (bmic_pass->blk_number >> 24) & 0xff;
cmdlist->Request.CDB[3] = (bmic_pass->blk_number >> 16) & 0xff;
cmdlist->Request.CDB[4] = (bmic_pass->blk_number >> 8) & 0xff;
cmdlist->Request.CDB[5] = bmic_pass->blk_number;
cmdlist->Request.CDB[6] = bmic_pass->cmd; /* BMIC Command */
/* Transfer Length - bytes 7[MSB] to 8[LSB] */
cmdlist->Request.CDB[7] = (bmic_pass->buf_len >> 8) & 0xff;
cmdlist->Request.CDB[8] = bmic_pass->buf_len & 0xff;
cmdlist->Request.CDB[9] = 0x00; /* Reserved */
/* Update CDB[2] = LSB bmix_index and CDB[9] = MSB bmic_index */
switch (bmic_pass->cmd) {
case HPSAS_ID_PHYSICAL_DRIVE:
case HPSAS_TAPE_INQUIRY:
case HPSAS_SENSE_MP_STAT:
case HPSAS_SET_MP_THRESHOLD:
case HPSAS_MP_PARAM_CONTROL:
case HPSAS_SENSE_DRV_ERR_LOG:
case HPSAS_SET_MP_VALUE:
cmdlist -> Request.CDB[2] = bmic_pass->bmic_index & 0xff;
cmdlist -> Request.CDB[9] = (bmic_pass->bmic_index >>8) & 0xff;
break;
case HPSAS_ID_LOG_DRIVE:
case HPSAS_SENSE_LOG_DRIVE:
case HPSAS_READ:
case HPSAS_WRITE:
case HPSAS_WRITE_THROUGH:
case HPSAS_SENSE_CONFIG:
case HPSAS_SET_CONFIG:
case HPSAS_BYPASS_VOL_STATE:
case HPSAS_CHANGE_CONFIG:
case HPSAS_SENSE_ORIG_CONFIG:
case HPSAS_LABEL_LOG_DRIVE:
/* Unit Number MSB */
cmdlist->Request.CDB[9] = (bmic_pass->unit_number >> 8) & 0xff;
break;
default:
break;
}
/*
* Copy the Lun address from the request
*/
bcopy(&bmic_pass->lun_addr[0], &(cmdlist->Header.LUN),
sizeof (LUNAddr_t));
cmdlist->SG[0].Len = bmic_pass->buf_len;
}