#include "ghd.h"
static struct scsi_pkt *ghd_pktalloc(ccc_t *cccp, struct scsi_address *ap,
int cmdlen, int statuslen, int tgtlen,
int (*callback)(), caddr_t arg, int ccblen);
#define ROUNDUP(x) (((x) + 0x07) & ~0x07)
#define GW_PADDED_LENGTH ROUNDUP(sizeof (gcmd_t))
typedef struct gcmd_padded_wrapper {
union {
gcmd_t gw_gcmd;
char gw_pad[GW_PADDED_LENGTH];
} gwrap;
} gwrap_t;
void
ghd_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pktp)
{
gcmd_t *gcmdp = PKTP2GCMDP(pktp);
int status;
if (gcmdp->cmd_dma_handle) {
status = ddi_dma_sync(gcmdp->cmd_dma_handle, 0, 0,
(gcmdp->cmd_dma_flags & DDI_DMA_READ) ?
DDI_DMA_SYNC_FORCPU : DDI_DMA_SYNC_FORDEV);
if (status != DDI_SUCCESS) {
cmn_err(CE_WARN, "ghd_tran_sync_pkt() fail\n");
}
}
}
static struct scsi_pkt *
ghd_pktalloc(ccc_t *cccp,
struct scsi_address *ap,
int cmdlen,
int statuslen,
int tgtlen,
int (*callback)(),
caddr_t arg,
int ccblen)
{
gtgt_t *gtgtp = ADDR2GTGTP(ap);
struct scsi_pkt *pktp;
gcmd_t *gcmdp;
gwrap_t *gwp;
int gwrap_len;
gwrap_len = sizeof (gwrap_t) + ROUNDUP(ccblen);
pktp = scsi_hba_pkt_alloc(cccp->ccc_hba_dip, ap, cmdlen, statuslen,
tgtlen, gwrap_len, callback, arg);
if (pktp == NULL) {
return (NULL);
}
gwp = (gwrap_t *)(pktp->pkt_ha_private);
gcmdp = &gwp->gwrap.gw_gcmd;
ASSERT((caddr_t)gwp == (caddr_t)gcmdp);
GHD_GCMD_INIT(gcmdp, (void *)(gwp + 1), gtgtp);
gcmdp->cmd_pktp = pktp;
if (!(*cccp->ccc_ccballoc)(gtgtp, gcmdp, cmdlen, statuslen, tgtlen,
ccblen)) {
scsi_hba_pkt_free(ap, pktp);
return (NULL);
}
return (pktp);
}
void
ghd_pktfree(ccc_t *cccp,
struct scsi_address *ap,
struct scsi_pkt *pktp)
{
GDBG_PKT(("ghd_pktfree: cccp 0x%p ap 0x%p pktp 0x%p\n",
(void *)cccp, (void *)ap, (void *)pktp));
(*cccp->ccc_ccbfree)(PKTP2GCMDP(pktp));
scsi_hba_pkt_free(ap, pktp);
}
struct scsi_pkt *
ghd_tran_init_pkt_attr(ccc_t *cccp,
struct scsi_address *ap,
struct scsi_pkt *pktp,
struct buf *bp,
int cmdlen,
int statuslen,
int tgtlen,
int flags,
int (*callback)(),
caddr_t arg,
int ccblen,
ddi_dma_attr_t *sg_attrp)
{
gcmd_t *gcmdp;
int new_pkt;
uint_t xfercount;
ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
if (pktp == NULL) {
pktp = ghd_pktalloc(cccp, ap, cmdlen, statuslen, tgtlen,
callback, arg, ccblen);
if (pktp == NULL)
return (NULL);
new_pkt = TRUE;
} else {
new_pkt = FALSE;
}
gcmdp = PKTP2GCMDP(pktp);
GDBG_PKT(("ghd_tran_init_pkt_attr: gcmdp 0x%p dma_handle 0x%p\n",
(void *)gcmdp, (void *)gcmdp->cmd_dma_handle));
if (cmdlen && gcmdp->cmd_dma_handle) {
ghd_dmafree_attr(gcmdp);
}
GDBG_PKT(("ghd_tran_init_pkt: gcmdp 0x%p bp 0x%p limp 0x%p\n",
(void *)gcmdp, (void *)bp, (void *)sg_attrp));
if (bp && bp->b_bcount && sg_attrp) {
int dma_flags;
if (bp->b_flags & B_READ)
dma_flags = DDI_DMA_READ;
else
dma_flags = DDI_DMA_WRITE;
if (flags & PKT_CONSISTENT)
dma_flags |= DDI_DMA_CONSISTENT;
if (flags & PKT_DMA_PARTIAL)
dma_flags |= DDI_DMA_PARTIAL;
if (gcmdp->cmd_dma_handle == NULL) {
if (!ghd_dma_buf_bind_attr(cccp, gcmdp, bp, dma_flags,
callback, arg, sg_attrp)) {
if (new_pkt)
ghd_pktfree(cccp, ap, pktp);
return (NULL);
}
}
if (!ghd_dmaget_attr(cccp, gcmdp,
bp->b_bcount - gcmdp->cmd_totxfer,
sg_attrp->dma_attr_sgllen, &xfercount)) {
if (new_pkt)
ghd_pktfree(cccp, ap, pktp);
return (NULL);
}
pktp->pkt_resid = bp->b_bcount - gcmdp->cmd_totxfer;
} else {
pktp->pkt_resid = 0;
}
return (pktp);
}