/*
* 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.
*/
#include <sys/sdt.h>
#include "cpqary3.h"
/*
* Local Functions Definitions
*/
uint8_t cpqary3_format_unit(cpqary3_cmdpvt_t *);
static uint8_t cpqary3_probe4LVs(cpqary3_t *);
static uint8_t cpqary3_probe4Tapes(cpqary3_t *);
/*
* Function : cpqary3_probe4targets
* Description : This routine detects all existing logical drives
* and updates per target structure.
* Called By : cpqary3_tgt_init()
* Parameters : per-controller
* Calls : cpqary3_probe4LVs(), cpqary3_probe4Tapes()
* Return Values: SUCCESS/ FAILURE
* [Shall fail only if Memory Constraints exist, the
* controller is defective/does not respond]
*/
uint8_t
cpqary3_probe4targets(cpqary3_t *cpqary3p)
{
uint8_t rv;
rv = cpqary3_probe4LVs(cpqary3p);
if (CPQARY3_FAILURE == rv) {
return (rv);
}
rv = cpqary3_probe4Tapes(cpqary3p);
if (CPQARY3_FAILURE == rv) {
return (rv);
}
return (CPQARY3_SUCCESS);
}
/*
* Function : cpqary3_build_cmdlist
* Description : This routine builds the command list for the specific
* opcode.
* Called By : cpqary3_transport()
* Parameters : cmdlist pvt struct, target id as received by SA.
* Calls : None
* Return Values: SUCCESS : Build is successful
* FAILURE : Build has Failed
*/
uint8_t
cpqary3_build_cmdlist(cpqary3_cmdpvt_t *cpqary3_cmdpvtp, uint32_t tid)
{
int cntr;
cpqary3_t *cpqary3p;
struct buf *bfp;
cpqary3_tgt_t *tgtp;
CommandList_t *cmdlistp;
RETURN_FAILURE_IF_NULL(cpqary3_cmdpvtp);
if (NULL == (cpqary3p = cpqary3_cmdpvtp->ctlr))
return (CPQARY3_FAILURE);
bfp = (struct buf *)cpqary3_cmdpvtp->pvt_pkt->bf;
tgtp = cpqary3p->cpqary3_tgtp[tid];
if (!tgtp) {
return (CPQARY3_FAILURE);
}
cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
/* Update Cmd Header */
cmdlistp->Header.SGList = cpqary3_cmdpvtp->pvt_pkt->cmd_cookiecnt;
cmdlistp->Header.SGTotal = cpqary3_cmdpvtp->pvt_pkt->cmd_cookiecnt;
cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_OSCMD_SUCCESS;
if (tgtp->type == CPQARY3_TARGET_CTLR) {
cmdlistp->Header.LUN.PhysDev.TargetId = 0;
cmdlistp->Header.LUN.PhysDev.Bus = 0;
cmdlistp->Header.LUN.PhysDev.Mode = MASK_PERIPHERIAL_DEV_ADDR;
} else if (tgtp->type == CPQARY3_TARGET_LOG_VOL) {
cmdlistp->Header.LUN.LogDev.VolId = tgtp->logical_id;
cmdlistp->Header.LUN.LogDev.Mode = LOGICAL_VOL_ADDR;
} else if (tgtp->type == CPQARY3_TARGET_TAPE) {
bcopy(&(tgtp->PhysID), &(cmdlistp->Header.LUN.PhysDev),
sizeof (PhysDevAddr_t));
DTRACE_PROBE1(build_cmdlist_tape, CommandList_t *, cmdlistp);
}
/* Cmd Request */
cmdlistp->Request.CDBLen = cpqary3_cmdpvtp->pvt_pkt->cdb_len;
bcopy((caddr_t)cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt->pkt_cdbp,
(caddr_t)cmdlistp->Request.CDB, cpqary3_cmdpvtp->pvt_pkt->cdb_len);
cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
cmdlistp->Request.Type.Attribute = CISS_ATTR_ORDERED;
DTRACE_PROBE2(build_cmdlist_buf, struct buf *, bfp,
CommandList_t *, cmdlistp);
if (bfp && (bfp->b_flags & B_READ))
cmdlistp->Request.Type.Direction = CISS_XFER_READ;
else if (bfp && (bfp->b_flags & B_WRITE))
cmdlistp->Request.Type.Direction = CISS_XFER_WRITE;
else
cmdlistp->Request.Type.Direction = CISS_XFER_NONE;
/*
* Looks like the above Direction is going for a toss in case of
* MSA20(perticularly for 0x0a-write) connected to SMART Array.
* If the above check fails, the below switch should take care.
*/
switch (cmdlistp->Request.CDB[0]) {
case 0x08:
case 0x28:
cmdlistp->Request.Type.Direction = CISS_XFER_READ;
break;
case 0x0A:
case 0x2A:
cmdlistp->Request.Type.Direction = CISS_XFER_WRITE;
break;
}
/*
* NEED to increase this TimeOut value when the concerned
* targets are tape devices(i.e., we need to do it here manually).
*/
cmdlistp->Request.Timeout = 2 *
(cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt->pkt_time);
for (cntr = 0; cntr < cpqary3_cmdpvtp->pvt_pkt->cmd_cookiecnt; cntr++) {
cmdlistp->SG[cntr].Addr =
cpqary3_cmdpvtp->pvt_pkt->
cmd_dmacookies[cntr].dmac_laddress;
cmdlistp->SG[cntr].Len = (uint32_t)
cpqary3_cmdpvtp->pvt_pkt->cmd_dmacookies[cntr].dmac_size;
}
return (CPQARY3_SUCCESS);
}
/*
* Function : cpqary3_send_abortcmd
* Description : Sends the Abort command to abort
* a set of cmds(on a target) or a cmdlist.
* Called By : cpqary3_abort
* Parameters : per controller, target_id, cmdlist to abort
* Calls : cpqary3_synccmd_alloc(), cpqary3_synccmd_send(),
* cpqary3_synccmd_free()
* Return Values: SUCCESS - abort cmd submit is successful.
* FAILURE - Could not submit the abort cmd.
*/
uint8_t
cpqary3_send_abortcmd(cpqary3_t *cpqary3p, uint16_t target_id,
CommandList_t *cmdlist2abortp)
{
CommandList_t *cmdlistp;
cpqary3_tgt_t *cpqtgtp;
cpqary3_tag_t *cpqary3_tagp;
cpqary3_cmdpvt_t *cpqary3_cmdpvtp;
/*
* NOTE : DO NOT perform this operation for cmdlist2abortp.
* It may be NULL
*/
RETURN_FAILURE_IF_NULL(cpqary3p);
if (target_id == CTLR_SCSI_ID)
return (CPQARY3_FAILURE);
cpqtgtp = cpqary3p->cpqary3_tgtp[target_id];
if (!cpqtgtp) {
return (CPQARY3_FAILURE);
}
/*
* Occupy the Command List
* Update the Command List accordingly
* Submit the command and wait for a signal
*/
/* BGB: CVFIX -> Introduced the call to cpqary3_synccmd_alloc */
cpqary3_cmdpvtp = cpqary3_synccmd_alloc(cpqary3p, 0);
if (cpqary3_cmdpvtp == NULL)
return (CPQARY3_FAILURE);
cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
cmdlistp->Header.SGList = 0;
cmdlistp->Header.SGTotal = 0;
cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS;
cmdlistp->Header.LUN.PhysDev.TargetId = 0;
cmdlistp->Header.LUN.PhysDev.Bus = 0;
cmdlistp->Header.LUN.PhysDev.Mode = PERIPHERIAL_DEV_ADDR;
cmdlistp->Request.Type.Type = CISS_TYPE_MSG;
cmdlistp->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
cmdlistp->Request.Type.Direction = CISS_XFER_NONE;
cmdlistp->Request.Timeout = CISS_NO_TIMEOUT;
cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_16;
cmdlistp->Request.CDB[0] = CISS_MSG_ABORT;
if (cmdlist2abortp) { /* Abort this Particular Task */
cmdlistp->Request.CDB[1] = CISS_ABORT_TASK;
cpqary3_tagp = (cpqary3_tag_t *)&cmdlistp->Request.CDB[4];
cpqary3_tagp->drvinfo_n_err =
cmdlist2abortp->Header.Tag.drvinfo_n_err;
cpqary3_tagp->tag_value = cmdlist2abortp->Header.Tag.tag_value;
} else { /* Abort all tasks for this Target */
cmdlistp->Request.CDB[1] = CISS_ABORT_TASKSET;
switch (cpqtgtp->type) {
case CPQARY3_TARGET_LOG_VOL:
cmdlistp->Header.LUN.LogDev.Mode = LOGICAL_VOL_ADDR;
cmdlistp->Header.LUN.LogDev.VolId = cpqtgtp->logical_id;
break;
case CPQARY3_TARGET_TAPE:
bcopy(&(cpqtgtp->PhysID),
&(cmdlistp->Header.LUN.PhysDev),
sizeof (PhysDevAddr_t));
}
}
/* PERF */
cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
/* PERF */
/* BGB: CVFIX -> Introduced a call to cpqary3_synccmd_send */
if (cpqary3_synccmd_send(cpqary3p, cpqary3_cmdpvtp, 30000,
CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
return (CPQARY3_FAILURE);
}
if (cpqary3_cmdpvtp->cmdlist_memaddr->Header.Tag.drvinfo_n_err ==
CPQARY3_SYNCCMD_FAILURE) {
cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
return (CPQARY3_FAILURE);
}
cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
return (CPQARY3_SUCCESS);
}
/*
* Function : cpqary3_fulsh_cache
* Description : This routine flushes the controller cache.
* Called By : cpqary3_detach(), cpqary3_additional_cmd()
* Parameters : per controller
* Calls : cpqary3_synccmd_alloc(), cpqary3_synccmd_send()
* cpqary3_synccmd_free()
* Return Values: None
*/
void
cpqary3_flush_cache(cpqary3_t *cpqary3p)
{
CommandList_t *cmdlistp;
cpqary3_cmdpvt_t *cpqary3_cmdpvtp;
/*
* Occupy the Command List
* Allocate Physically Contigous Memory for the FLUSH CACHE buffer
* Update the Command List accordingly
* Submit the command and wait for a signal
*/
ASSERT(cpqary3p != NULL);
/* grab a command and allocate a dma buffer */
cpqary3_cmdpvtp = cpqary3_synccmd_alloc(cpqary3p,
sizeof (flushcache_buf_t));
if (cpqary3_cmdpvtp == NULL)
return;
cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
cmdlistp->Header.SGList = 1;
cmdlistp->Header.SGTotal = 1;
cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS;
cmdlistp->Header.LUN.PhysDev.TargetId = 0;
cmdlistp->Header.LUN.PhysDev.Bus = 0;
cmdlistp->Header.LUN.PhysDev.Mode = PERIPHERIAL_DEV_ADDR;
cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_16;
cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
cmdlistp->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
cmdlistp->Request.Type.Direction = CISS_XFER_WRITE;
cmdlistp->Request.Timeout = CISS_NO_TIMEOUT;
cmdlistp->Request.CDB[0] = ARRAY_WRITE;
cmdlistp->Request.CDB[6] = CISS_FLUSH_CACHE; /* 0xC2 */
cmdlistp->Request.CDB[8] = 0x02;
/* PERF */
cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
/* PERF */
if (cpqary3_synccmd_send(cpqary3p, cpqary3_cmdpvtp, 90000,
CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
cmn_err(CE_WARN, "CPQary3 %s : Flush Cache Operation"
"Failed, Timeout", cpqary3p->hba_name);
return;
}
cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
}
/*
* Function : cpqary3_probe4LVs
* Description : This routine probes for the logical drives
* configured on the HP Smart Array controllers
* Called By : cpqary3_probe4targets()
* Parameters : per controller
* Calls : cpqary3_synccmd_alloc(), cpqary3_synccmd_send()
* cpqary3_synccmd_free()
* Return Values: None
*/
uint8_t
cpqary3_probe4LVs(cpqary3_t *cpqary3p)
{
ulong_t log_lun_no = 0;
ulong_t lun_id = 0;
ulong_t ld_count = 0;
ulong_t i = 0;
ulong_t cntr = 0;
uint32_t data_addr_len;
rll_data_t *rllp;
CommandList_t *cmdlistp;
cpqary3_cmdpvt_t *cpqary3_cmdpvtp;
/*
* Occupy the Command List
* Allocate Physically Contigous Memory
* Update the Command List for Report Logical LUNS (rll) Command
* This command detects all existing logical drives.
* Submit and Poll for completion
*/
RETURN_FAILURE_IF_NULL(cpqary3p);
/* Sync Changes */
cpqary3_cmdpvtp = cpqary3_synccmd_alloc(cpqary3p, sizeof (rll_data_t));
if (cpqary3_cmdpvtp == NULL)
return (CPQARY3_FAILURE);
cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
rllp = (rll_data_t *)cpqary3_cmdpvtp->driverdata->sg;
cmdlistp->Header.SGList = 1;
cmdlistp->Header.SGTotal = 1;
cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS;
cmdlistp->Header.LUN.PhysDev.Mode = MASK_PERIPHERIAL_DEV_ADDR;
cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_12;
cmdlistp->Request.Timeout = CISS_NO_TIMEOUT;
cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
cmdlistp->Request.Type.Attribute = CISS_ATTR_ORDERED;
cmdlistp->Request.Type.Direction = CISS_XFER_READ;
cmdlistp->Request.CDB[0] = CISS_OPCODE_RLL;
data_addr_len = sizeof (rll_data_t);
cmdlistp->Request.CDB[6] = (data_addr_len >> 24) & 0xff;
cmdlistp->Request.CDB[7] = (data_addr_len >> 16) & 0xff;
cmdlistp->Request.CDB[8] = (data_addr_len >> 8) & 0xff;
cmdlistp->Request.CDB[9] = (data_addr_len) & 0xff;
DTRACE_PROBE2(rll_cmd_send, CommandList_t *, cmdlistp,
cpqary3_cmdpvt_t *, cpqary3_cmdpvtp);
/* PERF */
cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
/* PERF */
if (cpqary3_synccmd_send(cpqary3p, cpqary3_cmdpvtp, 90000,
CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
return (CPQARY3_FAILURE);
}
if ((cpqary3_cmdpvtp->cmdlist_memaddr->Header.Tag.drvinfo_n_err ==
CPQARY3_SYNCCMD_FAILURE) &&
(cpqary3_cmdpvtp->errorinfop->CommandStatus !=
CISS_CMD_DATA_UNDERRUN)) {
cmn_err(CE_WARN, "CPQary3 : Probe for logical targets "
"returned ERROR !");
DTRACE_PROBE1(rll_cmd_fail,
ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop);
cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
return (CPQARY3_FAILURE);
}
/* Sync Changes */
log_lun_no = ((rllp->lunlist_byte0 + (rllp->lunlist_byte1 << 8) +
(rllp->lunlist_byte2 << 16) + (rllp->lunlist_byte3 << 24)) / 8);
DTRACE_PROBE2(rll_cmd_result, rll_data_t *, rllp, ulong_t, log_lun_no);
/*
* The following is to restrict the maximum number of supported logical
* volumes to 32. This is very important as controller support upto 128
* logical volumes and this driver implementation supports only 32.
*/
if (log_lun_no > MAX_LOGDRV) {
log_lun_no = MAX_LOGDRV;
}
cpqary3p->num_of_targets = log_lun_no;
DTRACE_PROBE1(update_lvlun_count, ulong_t, log_lun_no);
/*
* Update per target structure with relevant information
* CPQARY#_TGT_ALLIGNMENT is 1 because of the following mapping:
* Target IDs 0-6 in the OS = Logical Drives 0 - 6 in the HBA
* Target ID 7 in the OS = none in the HBA
* Target IDs 8-32 in the OS = Logical Drives 7 - 31 in the HBA
* Everytime we reference a logical drive with ID > 6, we shall use
* the alignment.
*/
/*
* Depending upon the value of the variable legacy_mapping set in
* cpqary3_attach(),
* the target mapping algorithm to be used by the driver is decided.
*
* If the value of legacy_mapping is set to one, in the case of
* Logical Drives with holes,
* Targets will be renumbered by the driver as shown below
* Below example makes the mapping logic clear.
*
* Logical Drive 0 in the HBA -> Target ID 0 i.e., cXt0dXsx
* Logical Drive 2 in the HBA -> Target ID 1 i.e., cXt1dXsX
* Logical Drive 3 in the HBA -> Target ID 2 i.e., cXt2dXsX
*
* If the value of legacy_mapping is not one, then the Logical
* Drive numbers will
* not be renumbered in the case of holes, and the mapping
* will be done as shown below
* This will be the default mapping from 1.80 cpqary3 driver.
*
* Logical Drive 0 in the HBA -> Target ID 0 i.e. cXt0dXsx
* Logical Drive 2 in the HBA -> Target ID 2 i.e. cXt2dXsX
* Logical Drive 3 in the HBA -> Target ID 3 i.e. cXt3dXsX
*/
if (cpqary3p->legacy_mapping == 1) {
for (cntr = 0; cntr < log_lun_no; cntr++) {
i = ((cntr < CTLR_SCSI_ID) ?
cntr : cntr + CPQARY3_TGT_ALIGNMENT);
if (!(cpqary3p->cpqary3_tgtp[i] = (cpqary3_tgt_t *)
MEM_ZALLOC(sizeof (cpqary3_tgt_t)))) {
cmn_err(CE_WARN, "CPQary3 : Failed to Detect "
"targets, Memory Allocation Failure");
cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
return (CPQARY3_FAILURE);
}
cpqary3p->cpqary3_tgtp[i]->logical_id =
rllp->ll_data[cntr].logical_id;
cpqary3p->cpqary3_tgtp[i]->type =
CPQARY3_TARGET_LOG_VOL;
DTRACE_PROBE2(lvlun_remapped,
cpqary3_tgt_t *, cpqary3p->cpqary3_tgtp[i],
rpl_data_t *, &rllp->ll_data[cntr]);
}
} else {
/*
* Fix for QXCR1000446657: Logical drives are re numbered after
* deleting a Logical drive.
* We are using new indexing mechanism to fill the
* cpqary3_tgtp[],
* Check given during memory allocation of cpqary3_tgtp
* elements, so that memory is not re-allocated each time the
* cpqary3_probe4LVs() is called.
* Check given while freeing the memory of the cpqary3_tgtp[]
* elements, when a hole is found in the Logical Drives
* configured.
*/
/* ensure that the loop will break for cntr = 32 in any case */
for (cntr = 0; ((ld_count < log_lun_no) && (cntr < MAX_LOGDRV));
cntr++) {
i = ((cntr < CTLR_SCSI_ID) ?
cntr : cntr + CPQARY3_TGT_ALIGNMENT);
lun_id = (rllp->ll_data[ld_count].logical_id & 0xFFFF);
if (cntr != lun_id) {
if (cpqary3p->cpqary3_tgtp[i]) {
MEM_SFREE(cpqary3p->cpqary3_tgtp[i],
sizeof (cpqary3_tgt_t));
cpqary3p->cpqary3_tgtp[i] = NULL;
}
} else {
if (cpqary3p->cpqary3_tgtp[i] == NULL &&
!(cpqary3p->cpqary3_tgtp[i] =
(cpqary3_tgt_t *)MEM_ZALLOC(
sizeof (cpqary3_tgt_t)))) {
cmn_err(CE_WARN,
"CPQary3 : Failed to Detect "
"targets, Memory Allocation "
"Failure");
/* Sync Changes */
cpqary3_synccmd_free(cpqary3p,
cpqary3_cmdpvtp);
/* Sync Changes */
return (CPQARY3_FAILURE);
}
cpqary3p->cpqary3_tgtp[i]->logical_id =
rllp->ll_data[ld_count].logical_id;
cpqary3p->cpqary3_tgtp[i]->type =
CPQARY3_TARGET_LOG_VOL;
/*
* Send "BMIC sense logical drive status
* command to set the target type to
* CPQARY3_TARGET_NONE in case of logical
* drive failure
*/
ld_count++;
}
}
}
/* HPQacucli Changes */
for (; cntr < MAX_LOGDRV; cntr++) {
cpqary3_tgt_t *t;
i = ((cntr < CTLR_SCSI_ID) ?
cntr : cntr + CPQARY3_TGT_ALIGNMENT);
t = cpqary3p->cpqary3_tgtp[i];
cpqary3p->cpqary3_tgtp[i] = NULL;
if (t) {
MEM_SFREE(t, sizeof (*t));
}
}
/* HPQacucli Changes */
/* Sync Changes */
cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
/* Sync Changes */
return (CPQARY3_SUCCESS);
}
/*
* Function : cpqary3_probe4Tapes
* Description : This routine probes for the logical drives
* configured on the HP Smart Array controllers
* Called By : cpqary3_probe4targets()
* Parameters : per controller
* Calls : cpqary3_synccmd_alloc(), cpqary3_synccmd_send()
* cpqary3_synccmd_free()
* Return Values: None
*/
uint8_t
cpqary3_probe4Tapes(cpqary3_t *cpqary3p)
{
uint8_t phy_lun_no;
uint32_t ii = 0;
uint8_t cntr = 0;
uint32_t data_addr_len;
rpl_data_t *rplp;
CommandList_t *cmdlistp;
cpqary3_cmdpvt_t *cpqary3_cmdpvtp;
/*
* Occupy the Command List
* Allocate Physically Contigous Memory
* Update the Command List for Report Logical LUNS (rll) Command
* This command detects all existing logical drives.
* Submit and Poll for completion
*/
RETURN_FAILURE_IF_NULL(cpqary3p);
/* Sync Changes */
cpqary3_cmdpvtp = cpqary3_synccmd_alloc(cpqary3p, sizeof (rpl_data_t));
if (cpqary3_cmdpvtp == NULL)
return (CPQARY3_FAILURE);
cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr;
rplp = (rpl_data_t *)cpqary3_cmdpvtp->driverdata->sg;
/* Sync Changes */
cmdlistp->Header.SGList = 1;
cmdlistp->Header.SGTotal = 1;
cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS;
cmdlistp->Header.LUN.PhysDev.TargetId = 0;
cmdlistp->Header.LUN.PhysDev.Bus = 0;
cmdlistp->Header.LUN.PhysDev.Mode = MASK_PERIPHERIAL_DEV_ADDR;
cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_12;
cmdlistp->Request.Timeout = CISS_NO_TIMEOUT;
cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
cmdlistp->Request.Type.Attribute = CISS_ATTR_ORDERED;
cmdlistp->Request.Type.Direction = CISS_XFER_READ;
cmdlistp->Request.CDB[0] = CISS_OPCODE_RPL;
data_addr_len = sizeof (rpl_data_t);
cmdlistp->Request.CDB[6] = (data_addr_len >> 24) & 0xff;
cmdlistp->Request.CDB[7] = (data_addr_len >> 16) & 0xff;
cmdlistp->Request.CDB[8] = (data_addr_len >> 8) & 0xff;
cmdlistp->Request.CDB[9] = (data_addr_len) & 0xff;
DTRACE_PROBE2(tape_probe_cmd_send,
CommandList_t *, cmdlistp, cpqary3_cmdpvt_t *, cpqary3_cmdpvtp);
/* PERF */
cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete;
/* PERF */
/* Sync Changes */
if (cpqary3_synccmd_send(cpqary3p, cpqary3_cmdpvtp, 90000,
CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
return (CPQARY3_FAILURE);
}
if ((cpqary3_cmdpvtp->cmdlist_memaddr->Header.Tag.drvinfo_n_err ==
CPQARY3_SYNCCMD_FAILURE) &&
(cpqary3_cmdpvtp->errorinfop->CommandStatus !=
CISS_CMD_DATA_UNDERRUN)) {
cmn_err(CE_WARN, "CPQary3 : Probe for physical targets "
"returned ERROR !");
DTRACE_PROBE1(tape_probe_cmdfail,
ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop);
cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
return (CPQARY3_FAILURE);
}
/* Sync Changes */
phy_lun_no = ((rplp->lunlist_byte0 +
(rplp->lunlist_byte1 << 8) +
(rplp->lunlist_byte2 << 16) +
(rplp->lunlist_byte3 << 24)) / 8);
/*
* Update per target structure with relevant information
* CPQARY3_TAPE_BASE is 33 because of the following mapping:
* Target IDs 0-6 in the OS = Logical Drives 0 - 6 in the HBA
* Target ID 7 in the OS = none in the HBA
* Target IDs 8-32 in the OS = Logical Drives 7 - 31 in the HBA
* Target IDs 33 and above are reserved for Tapes and hence we need
* the alignment.
*/
/*
* HP Smart Array SAS controllers with Firmware revsion 5.14 or
* later support
* 64 Logical drives. So we are checking
* if the controller is SAS or CISS and then assigning the value of the
* TAPE BASE accordingly
*/
if (cpqary3p->bddef->bd_flags & SA_BD_SAS) {
ii = 0x41; /* MAX_LOGDRV + 1 - 64 + 1 */
} else {
ii = 0x21; /* MAX_LOGDRV + 1 - 32 + 1 */
}
for (cntr = 0; cntr < phy_lun_no; cntr++) {
if (rplp->pl_data[cntr].Mode == CISS_PHYS_MODE) {
if (cpqary3p->cpqary3_tgtp[ii] == NULL &&
!(cpqary3p->cpqary3_tgtp[ii] =
(cpqary3_tgt_t *)
MEM_ZALLOC(sizeof (cpqary3_tgt_t)))) {
cmn_err(CE_WARN, "CPQary3 : Failed to Detect "
"targets, Memory Allocation Failure");
cpqary3_synccmd_free(cpqary3p,
cpqary3_cmdpvtp);
return (CPQARY3_FAILURE);
}
bcopy(&(rplp->pl_data[cntr]),
&(cpqary3p->cpqary3_tgtp[ii]->PhysID),
sizeof (PhysDevAddr_t));
cpqary3p->cpqary3_tgtp[ii]->type = CPQARY3_TARGET_TAPE;
DTRACE_PROBE1(tape_discovered,
cpqary3_tgt_t *, cpqary3p->cpqary3_tgtp[ii]);
ii++;
}
}
/* Sync Changes */
cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp);
/* Sync Changes */
return (CPQARY3_SUCCESS);
}
/*
* Function : cpqary3_synccmd_complete
* Description : This routine processes the completed commands
* using the sync interface and
* initiates any callback that is needed.
* Called By : cpqary3_transport
* Parameters : per-command
* Calls : cpqary3_cmdlist_release, cpqary3_synccmd_cleanup
* Return Values: None
*/
void
cpqary3_synccmd_complete(cpqary3_cmdpvt_t *cpqary3_cmdpvtp)
{
cpqary3_t *cpqary3p;
ASSERT(cpqary3_cmdpvtp != NULL);
if (CPQARY3_TIMEOUT == cpqary3_cmdpvtp->cmdpvt_flag) {
cpqary3_cmdlist_release(cpqary3_cmdpvtp, CPQARY3_NO_MUTEX);
return;
}
cpqary3p = cpqary3_cmdpvtp->ctlr;
if (cpqary3_cmdpvtp->cmdpvt_flag == CPQARY3_SYNC_TIMEOUT) {
/*
* The submitter has abandoned this command, so we
* have to free the resources here.
*/
mutex_exit(&(cpqary3p->sw_mutex));
cpqary3_synccmd_cleanup(cpqary3_cmdpvtp);
mutex_enter(&(cpqary3p->sw_mutex));
} else {
/* submitter is waiting; wake him up */
cpqary3_cmdpvtp->cmdpvt_flag = 0;
/*
* Fix for Flush Cache Operation Timed out issue:
* cv_signal() wakes up only one blocked thread.
* We need to use cv_broadcast which unblocks
* all the blocked threads()
*/
cv_broadcast(&(cpqary3p->cv_ioctl_wait));
}
}