/*
* 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
*/
/*
* Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
*/
#include "cpqary3.h"
/*
* Local Functions Definitions
*/
struct scsi_device *);
static int cpqary3_tgt_probe(struct scsi_device *, int (*)());
static int cpqary3_reset(struct scsi_address *, int);
static int cpqary3_getcap(struct scsi_address *, char *, int);
static int cpqary3_setcap(struct scsi_address *, char *, int, int);
struct buf *, int, int (*)());
caddr_t);
void cpqary3_oscmd_complete(cpqary3_cmdpvt_t *);
/*
* External Variable Declarations
*/
extern ddi_dma_attr_t cpqary3_dma_attr;
/*
* Function : cpqary3_init_hbatran
* Description : This routine initializes the transport vector in the
* SCSA architecture for entry ponts in this driver.
* Called By : cpqary3_attach()
* Parameters : per_controller
* Calls : None
* Return Values: None
*/
void
{
/*
* Memory for the transport vector has been allocated by now.
* initialize all the entry points in this vector
*/
/* Target Driver Instance Initialization */
/* Resource Allocation */
/* Command Transport */
/* Capability Management */
/* Abort and Reset */
}
/*
* Function : cpqary3_tgt_init ()
* Description : This routine validates the target ID.
* Called By : cpqary3_init_hbatran()
* Parameters : HBA-instance, target instance, transport vector,
* scsi-device structure
* Calls : cpqary3_detect_target_geometry(),
* cpqary3_probe4targets()
* Return Values: DDI_SUCCESS : A Target exists at this ID.
* DDI_FAILURE : No such target exists.
*/
/* ARGSUSED */
static int
{
/* HPQacucli Changes */
(ctlr->num_of_targets > 0)) {
(void) cpqary3_detect_target_geometry(ctlr);
}
/* HPQacucli Changes */
/*
* Validate the Target ID
* Validate Lun --Ver1.10--
* If not a valid target id, return FAILURE.
* Derieve the per-controller
*/
return (DDI_FAILURE);
}
/*
* Check to see if a target structure corrresponding to this
* target Id exists.(support only for Logical Drives and Controller)
* if target exists, update target flags, return SUCCESS
* is target does not exist, return FAILURE
*/
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* Function : cpqary3_tgt_probe()
* Description : This routine probes into the Target Details.
* Called By : cpqary3_init_hbatran()
* Parameters : scsi-device structure, calling function if any
* Calls : None
* Return Values: value returned by scsi_hba_probe()
*/
static int
{
#ifdef CPQARY3_DEBUG
int status;
#endif
/*
* Probe for the presence of the target, using the scsi_hba_probe().
* It inturn issues the SCSI inquiry command that is serviced by our
* driver
*/
/* HPQacucli Changes */
(ctlr->num_of_targets > 0)) {
(void) cpqary3_detect_target_geometry(ctlr);
}
/* HPQacucli Changes */
#ifdef CPQARY3_DEBUG
/* Comment the previous line of code */
status);
return (status);
#endif
}
/*
* Function : cpqary3_init_pkt
* Description : This routine allocates resources for a SCSI packet.
* Called By : cpqary3_init_pkt()
* Parameters : SCSI address, SCSI packet, buffer, CDB length,
* SCB length, driver private length, flags modifier,
* callback function, arguement for the callback function
* Calls : cpqary3_dma_alloc(), cpqary3_dma_move()
* Return Values: allocated SCSI packet / NULL
*/
/* ARGSUSED */
static struct scsi_pkt *
{
/*
* If the SCSI packet is NULL, allocate frresh resources to it.
* Else, get the next available resources for the same
*/
if (!scsi_pktp) {
if (!scsi_pktp)
return (NULL);
/*
* Store the CDB length and sense data length in the
* pkt private
*/
/*
* Initialize to NULL all the fields of scsi_pktp, except
* pkt_scbp, pkt_cdbp, pkt_ha_private and pkt_private members.
*/
scsi_pktp->pkt_statistics = 0;
scsi_pktp->pkt_reason = 0;
if (flags & PKT_CONSISTENT)
if (flags & PKT_DMA_PARTIAL)
} else {
}
/*
* packet
* If first time allocation for this SCSI packet, allocate fresh DMA
* Else, move the already allocated DMA resources
*/
if (new_scsi_pktp)
}
} else {
if (CPQARY3_FAILURE ==
}
}
}
return (scsi_pktp);
}
/*
* Function : cpqary3_dma_alloc()
* Description : This routine services requests for memory (dynamic)
* as and when required by the OS.
* Called By : cpqary3_init_pkt()
* Parameters : per-controller, SCSI packet, buffer, flag modifier,
* callback function
* Calls : None
* Return Values: SUCCESS / FAILURE
*/
static int
{
uint32_t i = 0;
/*
* Record the direction of the data transfer, so that it
* can be used in appropriate synchronization during cpqary3_sync_pkt()
*/
} else {
}
if (flags & PKT_CONSISTENT) {
}
if (flags & PKT_DMA_PARTIAL) {
}
/* SG */
/* SG */
/*
* DMA resources are allocated thru a 2 step protocol :
* - allocate a DMA handle
* - bind the buffer to the handle
* If both the steps succeed, we have succeeded in allocating resources
*/
&cpqary3_pktp->cmd_dmahandle))) {
switch (retvalue) {
case DDI_DMA_NORESOURCES:
/*
* No Resources are available to be allocated
*/
break;
case DDI_DMA_BADATTR:
/*
* The attributes stated in our DMA attribute
* structure is such that potential DMA resources can
* not be allocated.
*/
"AllocHandle Failed BadAttr\n");
break;
default:
/*
* There is no other possible return value
*/
"CPQary3: dma_alloc: Unexpected Return Value %x "
"From call to Allocate DMA Handle \n", retvalue);
break;
}
return (CPQARY3_FAILURE);
}
switch (retvalue) {
case DDI_DMA_PARTIAL_MAP :
case DDI_DMA_MAPPED :
if (DDI_DMA_PARTIAL_MAP == retvalue) {
"windows number failed");
}
&cpqary3_pktp->cmd_dmacookies[0],
"DMA Window Failed");
}
} else {
cpqary3_pktp->cmd_dma_len = 0;
cpqary3_pktp->cmd_dma_offset = 0;
}
cpqary3_pktp->cmd_dmacount = 0;
i = 0;
for (;;) {
/* SG */
/* Check Out for Limits */
i == cpqary3_pktp->cmd_ncookies)
break;
/* SG */
&cpqary3_pktp->cmd_dmacookies[i]);
}
cpqary3_pktp->cmd_cookie = i;
cpqary3_pktp->cmd_cookiecnt = i;
return (CPQARY3_SUCCESS);
case DDI_DMA_NORESOURCES:
break;
case DDI_DMA_NOMAPPING:
break;
case DDI_DMA_TOOBIG:
break;
case DDI_DMA_INUSE:
"is using the DMA handle");
default:
"returned from Call to Bind Buffer "
"to Handle : 0x%X", i);
}
return (CPQARY3_FAILURE);
}
/*
* Function : cpqary3_dma_move()
* Description : This routine gets the next DMA window.
* Called By : cpqary3_init_pkt()
* Parameters : per-controller, SCSI packet, buffer
* Calls : None
* Return Values: SUCCESS / FAILURE
*/
static int
{
uint32_t i = 0;
/*
* If there are no more cookies remaining in this window,
* must move to the next window first.
*/
/* For small pkts, leave things where they are */
return (CPQARY3_SUCCESS);
/* Shall not be able to move if last window */
return (CPQARY3_FAILURE);
&cpqary3_pktp->cmd_dmacookies[0],
return (CPQARY3_FAILURE);
cpqary3_pktp->cmd_cookie = 0;
} else {
/* Still more cookies in this window - get the next one */
&cpqary3_pktp->cmd_dmacookies[0]);
}
/* Get remaining cookies in this window, up to our maximum */
for (;;) {
/* SG */
/* no. of DATA SEGMENTS */
break;
/* SG */
&cpqary3_pktp->cmd_dmacookies[i]);
}
cpqary3_pktp->cmd_cookiecnt = i;
return (CPQARY3_SUCCESS);
}
/*
* Function : cpqary3_transport()
* Description : This routine services requests from the OS that are
* directed towards the targets.(any SCSI command)
* Called By : kernel
* Parameters : SCSI address, SCSI packet, buffer
* Calls : cpqary3_build_iop, cpqary3_add2submitted
* Return Values: TRAN_ACCEPT : The driver accepts the command.
* TRAN_BUSY : Required resources not available
* at the moment.
* TRAN_FATAL_ERROR: A target no longer exists.
*/
static int
{
if (!tgtp)
return (TRAN_FATAL_ERROR);
return (TRAN_FATAL_ERROR);
return (TRAN_ACCEPT);
/*
* Attempt to occupy a free command memory block
* If not successful, return TRAN_BUSY
* Else, build the Command
* Submit it to the controller
* If NO_INTR flag is set, wait for the completion of the command and
* when the command completes, update packet values appropriately and
* return TRAN_ACCEPT.
* Make an entry in the submitted Q
* return TRAN_ACCEPT
*/
return (TRAN_BUSY);
}
/* SG */
/* SG */
/* PERF */
/* PERF */
case CPQARY3_SUCCESS :
}
/* CONTROLLER_LOCKUP */
return (TRAN_FATAL_ERROR);
}
/* CONTROLLER_LOCKUP */
break;
case CPQARY3_FAILURE :
return (TRAN_FATAL_ERROR);
default: /* Never occurs */
return (TRAN_FATAL_ERROR);
}
return (TRAN_ACCEPT);
}
/*
* Function : cpqary3_dmafree
* Description : This routine de-allocates previously allocated
* DMA resources.
* Called By : kernel
* Parameters : SCSI address, SCSI packet
* Calls : None
* Return Values: None
*/
/* ARGSUSED */
static void
{
/*
* If any DMA was succesfully attempted earlier, free all allocated
* resources
*/
if (!cpqary3_pktp->cmd_dmahandle) {
return;
}
}
}
/*
* Function : cpqary3_dma_sync
* Description : This routine synchronizes the CPU's / HBA's view of
* the data associated with the pkt, typically by calling
* ddi_dma_sync().
* Called By : kernel
* Parameters : SCSI address, SCSI packet
* Calls : None
* Return Values: None
*/
/* ARGSUSED */
static void
{
/*
* Check whether DMA was attempted successfully earlier
* If yes and
* if the command flags is write, then synchronise the device else
* synchronise the CPU
*/
}
}
/*
* Function : cpqary3_destroy_pkt
* Description : This routine de-allocates previously allocated
* resources for the SCSI packet.
* Called By : kernel
* Parameters : SCSI address, SCSI packet
* Calls : None
* Return Values: None
*/
static void
{
/*
* Deallocate DMA Resources, if allocated.
* Free the SCSI Packet.
*/
if (!cpqary3_pktp->cmd_dmahandle) {
} else {
(void) ddi_dma_unbind_handle(
}
}
}
/*
* Function : cpqary3_reset
* Called By : kernel
* Parameters : SCSI address, reset level required
* Calls : None
* Return Values: SUCCESS
*/
/* ARGSUSED */
static int
{
/*
* Fix for Crash seen during RAID 0 Drive removal -
* just return CPQARY3_SUCCESS on reset request
*/
return (CPQARY3_SUCCESS);
}
/*
* Function : cpqary3_abort()
* Description : This routine aborts a particular command or all commands
* directed towards a target.
* Called By : kernel
* Parameters : SCSI address, SCSI packet
* Calls : None
* Return Values: SUCCESS / FAILURE
* [ abort of concernd command(s) was a success or
* a failure. ]
*/
static int
{
/*
* If SCSI packet exists, abort that particular command.
* Else, abort all existing commands to the target
* In either of the cases, we shall have to wait after the abort
* functions are called to return the status.
*/
if (!scsi_pktp) {
(CommandList_t *)NULL));
} else {
}
}
/*
* Function : cpqary3_getcap
* Description : This routine is called to get the current value of a
* capability.(SCSI transport capability)
* Called By : kernel
* Parameters : SCSI address, capability identifier, target(s) affected
* Calls : None
* Return Values: current value of capability / -1 (if unsupported)
*/
static int
{
int index;
/*
* If requested Capability is not supported, return -1.
*/
return (CAP_NOT_DEFINED);
/*
* Getting capability for a particulat target is supported
* the generic form of tran_getcap() is unsupported(for all targets)
* If directed towards a particular target, return current capability.
*/
if (tgtonly == 0) { /* all targets */
return (CAP_NOT_DEFINED);
}
switch (index) {
case SCSI_CAP_DMA_MAX:
return ((int)cpqary3_dma_attr.dma_attr_maxxfer);
case SCSI_CAP_DISCONNECT:
case SCSI_CAP_SYNCHRONOUS:
case SCSI_CAP_WIDE_XFER:
case SCSI_CAP_ARQ:
case SCSI_CAP_INITIATOR_ID:
return (CTLR_SCSI_ID);
case SCSI_CAP_UNTAGGED_QING:
return (1);
case SCSI_CAP_TAGGED_QING:
return (1);
case SCSI_CAP_SECTOR_SIZE:
return (cpqary3_dma_attr.dma_attr_granular);
case SCSI_CAP_TOTAL_SECTORS:
return (CAP_NOT_DEFINED);
case SCSI_CAP_GEOMETRY:
return (cpqary3_target_geometry(sa));
return (0);
default:
return (CAP_NOT_DEFINED);
}
}
/*
* Function : cpqary3_setcap
* Description : This routine is called to set the current value of a
* capability.(SCSI transport capability)
* Called By : kernel
* Parameters : SCSI address, capability identifier,
* new capability value, target(s) affected
* Calls : None
* Return Values: SUCCESS / FAILURE / -1 (if capability is unsupported)
*/
/* ARGSUSED */
static int
{
int index;
/*
* If requested Capability is not supported, return -1.
*/
return (retstatus);
/*
* Setting capability for a particulat target is supported
* the generic form of tran_setcap() is unsupported(for all targets)
* If directed towards a particular target, set & return current
* capability.
*/
if (!tgtonly) {
return (retstatus);
}
switch (index) {
case SCSI_CAP_DMA_MAX:
return (CAP_CHG_NOT_ALLOWED);
case SCSI_CAP_DISCONNECT:
return (CAP_CHG_NOT_ALLOWED);
case SCSI_CAP_SYNCHRONOUS:
return (CAP_CHG_NOT_ALLOWED);
case SCSI_CAP_WIDE_XFER:
return (CAP_CHG_NOT_ALLOWED);
case SCSI_CAP_ARQ:
return (1);
case SCSI_CAP_INITIATOR_ID:
return (CAP_CHG_NOT_ALLOWED);
case SCSI_CAP_UNTAGGED_QING:
return (1);
case SCSI_CAP_TAGGED_QING:
return (1);
case SCSI_CAP_SECTOR_SIZE:
return (CAP_CHG_NOT_ALLOWED);
case SCSI_CAP_TOTAL_SECTORS:
return (CAP_CHG_NOT_ALLOWED);
case SCSI_CAP_GEOMETRY:
return (CAP_CHG_NOT_ALLOWED);
return (CAP_CHG_NOT_ALLOWED);
default:
return (CAP_NOT_DEFINED);
}
}
/*
* Function : cpqary3_handle_flag_nointr
* Description : This routine is called to handle submission and
* subsequently poll for the completion of a command,
* when its FLAG_NOINTR bit is set.
* Called By : cpqary3_transport()
* Parameters : command private structure, SCSI packet
* Calls : cpqary3_intr_onoff, cpqary3_retrieve,
* cpqary3_submit, cpqary3_poll
* Return Values: TRAN_ACCEPT
*/
static int
{
uint32_t i;
/*
* Before sumitting this command, ensure all commands pending
* with the controller are completed.
*/
for (;;) {
for (i = 0; i < no_cmds; i++) {
if ((cpqary3_cmdpvtp->cmdlist_memaddr->
CPQARY3_TIMEOUT)) {
continue;
}
} else {
if (cpqary3_cmdpvtp->cmdpvt_flag ==
continue;
}
}
}
/* NOE */
break;
}
}
while ((simple_tag =
if ((simple_tag >>
"CPQary3 : HBA returned "
"Spurious Tag");
return (CPQARY3_FAILURE);
}
}
} else {
drv_usecwait(1000);
}
}
} else {
break;
}
}
return (TRAN_FATAL_ERROR);
}
return (TRAN_ACCEPT);
} else {
}
return (TRAN_ACCEPT);
}
}
/*
* Function : cpqary3_poll
* Description : This routine polls for the completion of a command.
* Called By : cpqary3_handle_flag_nointr
* Parameters : per controller, tag of the command to be polled
* Calls : cpqary3_poll_retrieve
* Return Values: TRAN_ACCEPT
*/
static int
{
/*
* POLL for the completion of the said command
* Since, we had ensured that controller is empty, we need not
* check for the complete Retrieved Q.
* However, we just check the Retrieved Q and complete all
* commands in it, inclusive of the polled command.
* if the polled command is completed, send back a success.
*/
for (;;) { /* this function is called with both the locks held */
ii++;
if (ii > 120000)
return (CPQARY3_FAILURE);
drv_usecwait(500);
continue;
}
break;
}
return (CPQARY3_SUCCESS);
}
static int
{
/* LINTED: alignment */
case 0x35: /* Synchronize Cache */
scsi_pktp->pkt_statistics = 0;
}
return (1);
case 0x04: /* Format Unit */
"device If this option is selected from the format utility "
"do not continue further. Please refer to cpqary3 driver "
"man pages for details.");
return (0);
case SCSI_LOG_SENSE:
case SCSI_MODE_SELECT:
arqstat->sts_rqpkt_resid = 0;
arqstat->sts_rqpkt_statistics = 0;
}
return (1);
}
return (0);
}
/* PERF */
/*
* Function : cpqary3_oscmd_complete
* Description : This routine processes the
* completed OS commands and
* initiates any callback that is needed.
* Called By : cpqary3_transport
* Parameters : per-command
* Calls : cpqary3_ioctl_send_bmiccmd,
* cpqary3_ioctl_send_scsicmd,
* cpqary3_send_abortcmd, cpqary3_flush_cache,
* cpqary3_probe4LVs,
* cpqary3_probe4Tapes, cpqary3_synccmd_complete,
* cpqary3_detect_target_geometry,
* cpqary3_detect_target_geometry
* Return Values: None
*/
void
{
return;
}
scsi_pktp->pkt_statistics = 0;
FLAG_NOINTR) {
} else {
}
}
return;
} else {
}
switch (errorinfop->CommandStatus) {
case CISS_CMD_DATA_OVERRUN :
break;
case CISS_CMD_INVALID :
break;
case CISS_CMD_PROTOCOL_ERR :
break;
case CISS_CMD_HARDWARE_ERR:
case CISS_CMD_CONNECTION_LOST:
break;
case CISS_CMD_ABORTED:
break;
case CISS_CMD_ABORT_FAILED:
break;
case CISS_CMD_TIMEOUT:
break;
case CISS_CMD_DATA_UNDERRUN: /* Significant ONLY for Read & Write */
if (cpqary3_is_scsi_read_write(scsi_pktp)) {
scsi_pktp->pkt_statistics = 0;
break;
}
/* FALLTHROUGH */
case CISS_CMD_SUCCESS:
case CISS_CMD_TARGET_STATUS:
scsi_pktp->pkt_statistics = 0;
break;
default: /* Should never Occur !!! */
break;
}
/*
* if ever a command completes with a CHECK CONDITION or a
* COMMAND_TERMINATED SCSI status, Update the sense data.
* NOTE : The CISS_CMD_INVALID command status would always result in a
* CHECK CONDITION and hence reach this part of the code.
*/
if (errorinfop->SenseLen) {
/* LINTED: alignment */
} else {
}
sizeof (struct scsi_status));
arq_statusp->sts_rqpkt_resid = 0;
}
}
} else {
}
}
}
static uint8_t
{
/*
* In the scsi packet structure, the first byte is the SCSI Command
* OpCode. We check to see if it is any one of the SCSI Read or Write
* opcodes.
*/
case SCSI_READ_6:
case SCSI_READ_10:
case SCSI_READ_12:
case SCSI_WRITE_6:
case SCSI_WRITE_10:
case SCSI_WRITE_12:
return (1);
default:
return (0);
}
}