#include <sys/types.h>
#include "ata_common.h"
#include "atapi.h"
static int atapi_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
scsi_hba_tran_t *hba_tran, struct scsi_device *sd);
static int atapi_tran_tgt_probe(struct scsi_device *sd, int (*callback)(void));
static void atapi_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
scsi_hba_tran_t *hba_tran, struct scsi_device *sd);
static int atapi_tran_abort(struct scsi_address *ap, struct scsi_pkt *spktp);
static int atapi_tran_reset(struct scsi_address *ap, int level);
static int atapi_tran_getcap(struct scsi_address *ap, char *capstr, int whom);
static int atapi_tran_setcap(struct scsi_address *ap, char *capstr,
int value, int whom);
static struct scsi_pkt *atapi_tran_init_pkt(struct scsi_address *ap,
struct scsi_pkt *spktp, struct buf *bp, int cmdlen, int statuslen,
int tgtlen, int flags, int (*callback)(caddr_t), caddr_t arg);
static void atapi_tran_destroy_pkt(struct scsi_address *ap,
struct scsi_pkt *spktp);
static void atapi_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *spktp);
static void atapi_tran_sync_pkt(struct scsi_address *ap,
struct scsi_pkt *spktp);
static int atapi_tran_start(struct scsi_address *ap, struct scsi_pkt *spktp);
static void atapi_complete(ata_drv_t *ata_drvp, ata_pkt_t *ata_pktp,
int do_callback);
static int atapi_id_update(ata_ctl_t *ata_ctlp, ata_drv_t *ata_drvp,
ata_pkt_t *ata_pktp);
#if 0
static ddi_dma_lim_t atapi_dma_limits = {
0,
0xffffffffU,
0,
1,
DMA_UNIT_8,
0,
(uint_t)DMALIM_VER0,
0xffffffffU,
0xffffffffU,
1,
1,
0xffffffffU
};
#endif
static int atapi_use_static_geometry = TRUE;
static int atapi_arq_enable = TRUE;
int
atapi_attach(ata_ctl_t *ata_ctlp)
{
dev_info_t *dip = ata_ctlp->ac_dip;
scsi_hba_tran_t *tran;
ADBG_TRACE(("atapi_init entered\n"));
tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
if (tran == NULL) {
ADBG_WARN(("atapi_init: scsi_hba_tran_alloc failed\n"));
goto errout;
}
ata_ctlp->ac_atapi_tran = tran;
ata_ctlp->ac_flags |= AC_SCSI_HBA_TRAN_ALLOC;
tran->tran_hba_private = ata_ctlp;
tran->tran_tgt_private = NULL;
tran->tran_tgt_init = atapi_tran_tgt_init;
tran->tran_tgt_probe = atapi_tran_tgt_probe;
tran->tran_tgt_free = atapi_tran_tgt_free;
tran->tran_start = atapi_tran_start;
tran->tran_reset = atapi_tran_reset;
tran->tran_abort = atapi_tran_abort;
tran->tran_getcap = atapi_tran_getcap;
tran->tran_setcap = atapi_tran_setcap;
tran->tran_init_pkt = atapi_tran_init_pkt;
tran->tran_destroy_pkt = atapi_tran_destroy_pkt;
tran->tran_dmafree = atapi_tran_dmafree;
tran->tran_sync_pkt = atapi_tran_sync_pkt;
if (scsi_hba_attach_setup(ata_ctlp->ac_dip, &ata_pciide_dma_attr, tran,
SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) {
ADBG_WARN(("atapi_init: scsi_hba_attach_setup failed\n"));
goto errout;
}
ata_ctlp->ac_flags |= AC_SCSI_HBA_ATTACH;
return (TRUE);
errout:
atapi_detach(ata_ctlp);
return (FALSE);
}
void
atapi_detach(
ata_ctl_t *ata_ctlp)
{
ADBG_TRACE(("atapi_detach entered\n"));
if (ata_ctlp->ac_flags & AC_SCSI_HBA_ATTACH)
(void) scsi_hba_detach(ata_ctlp->ac_dip);
if (ata_ctlp->ac_flags & AC_SCSI_HBA_TRAN_ALLOC)
scsi_hba_tran_free(ata_ctlp->ac_atapi_tran);
}
int
atapi_init_drive(
ata_drv_t *ata_drvp)
{
ata_ctl_t *ata_ctlp = ata_drvp->ad_ctlp;
ADBG_TRACE(("atapi_init_drive entered\n"));
(void) atapi_id_update(ata_ctlp, ata_drvp, NULL);
switch (ata_drvp->ad_id.ai_config & ATAPI_ID_CFG_PKT_SZ) {
case ATAPI_ID_CFG_PKT_12B:
ata_drvp->ad_cdb_len = 12;
break;
case ATAPI_ID_CFG_PKT_16B:
ata_drvp->ad_cdb_len = 16;
break;
default:
ADBG_WARN(("atapi_init_drive: bad pkt size support\n"));
return (FALSE);
}
if ((ata_drvp->ad_id.ai_config & ATAPI_ID_CFG_DRQ_TYPE) !=
ATAPI_ID_CFG_DRQ_INTR)
ata_drvp->ad_flags |= AD_NO_CDB_INTR;
if (ata_set_dma_mode(ata_ctlp, ata_drvp) == TRUE) {
(void) atapi_id_update(ata_ctlp, ata_drvp, NULL);
}
return (TRUE);
}
void
atapi_uninit_drive(
ata_drv_t *ata_drvp)
{
ADBG_TRACE(("atapi_uninit_drive entered\n"));
}
int
atapi_id(
ddi_acc_handle_t io_hdl1,
caddr_t ioaddr1,
ddi_acc_handle_t io_hdl2,
caddr_t ioaddr2,
struct ata_id *ata_idp)
{
int rc;
ADBG_TRACE(("atapi_id entered\n"));
rc = ata_id_common(ATC_ID_PACKET_DEVICE, FALSE, io_hdl1, ioaddr1,
io_hdl2, ioaddr2, ata_idp);
if (!rc)
return (FALSE);
if ((ata_idp->ai_config & ATAC_ATAPI_TYPE_MASK) != ATAC_ATAPI_TYPE)
return (FALSE);
return (TRUE);
}
int
atapi_signature(
ddi_acc_handle_t io_hdl,
caddr_t ioaddr)
{
int rc = FALSE;
ADBG_TRACE(("atapi_signature entered\n"));
if (ddi_get8(io_hdl, (uchar_t *)ioaddr + AT_HCYL) == ATAPI_SIG_HI &&
ddi_get8(io_hdl, (uchar_t *)ioaddr + AT_LCYL) != ATAPI_SIG_LO)
rc = TRUE;
ddi_put8(io_hdl, (uchar_t *)ioaddr + AT_HCYL, 0);
ddi_put8(io_hdl, (uchar_t *)ioaddr + AT_LCYL, 0);
return (rc);
}
static int
atapi_tran_tgt_init(
dev_info_t *hba_dip,
dev_info_t *tgt_dip,
scsi_hba_tran_t *hba_tran,
struct scsi_device *sd)
{
gtgt_t *gtgtp;
ata_ctl_t *ata_ctlp;
ata_tgt_t *ata_tgtp;
ata_drv_t *ata_drvp;
struct scsi_address *ap;
int rc = DDI_SUCCESS;
ADBG_TRACE(("atapi_tran_tgt_init entered\n"));
ata_ctlp = TRAN2CTL(hba_tran);
ap = &sd->sd_address;
ata_drvp = CTL2DRV(ata_ctlp, ap->a_target, ap->a_lun);
if (!ata_prop_create(tgt_dip, ata_drvp, "atapi")) {
return (DDI_FAILURE);
}
gtgtp = ghd_target_init(hba_dip, tgt_dip, &ata_ctlp->ac_ccc,
sizeof (ata_tgt_t), ata_ctlp,
ap->a_target, ap->a_lun);
hba_tran->tran_tgt_private = gtgtp;
ata_tgtp = GTGTP2ATATGTP(gtgtp);
ata_tgtp->at_drvp = ata_drvp;
ata_tgtp->at_dma_attr = ata_pciide_dma_attr;
ata_tgtp->at_dma_attr.dma_attr_maxxfer =
ata_ctlp->ac_max_transfer << SCTRSHFT;
return (rc);
}
static int
atapi_tran_tgt_probe(struct scsi_device *sd, int (*callback)(void))
{
ADBG_TRACE(("atapi_tran_tgt_probe entered\n"));
return (scsi_hba_probe(sd, callback));
}
static void
atapi_tran_tgt_free(
dev_info_t *hba_dip,
dev_info_t *tgt_dip,
scsi_hba_tran_t *hba_tran,
struct scsi_device *sd)
{
ADBG_TRACE(("atapi_tran_tgt_free entered\n"));
ghd_target_free(hba_dip, tgt_dip, &TRAN2ATAP(hba_tran)->ac_ccc,
TRAN2GTGTP(hba_tran));
hba_tran->tran_tgt_private = NULL;
}
static int
atapi_tran_abort(
struct scsi_address *ap,
struct scsi_pkt *spktp)
{
ADBG_TRACE(("atapi_tran_abort entered\n"));
if (spktp) {
return (ghd_tran_abort(&ADDR2CTL(ap)->ac_ccc, PKTP2GCMDP(spktp),
ADDR2GTGTP(ap), NULL));
}
return (ghd_tran_abort_lun(&ADDR2CTL(ap)->ac_ccc, ADDR2GTGTP(ap),
NULL));
}
static int
atapi_tran_reset(
struct scsi_address *ap,
int level)
{
ADBG_TRACE(("atapi_tran_reset entered\n"));
if (level == RESET_TARGET)
return (ghd_tran_reset_target(&ADDR2CTL(ap)->ac_ccc,
ADDR2GTGTP(ap), NULL));
if (level == RESET_ALL)
return (ghd_tran_reset_bus(&ADDR2CTL(ap)->ac_ccc,
ADDR2GTGTP(ap), NULL));
return (FALSE);
}
static int
atapi_tran_setcap(
struct scsi_address *ap,
char *capstr,
int value,
int whom)
{
gtgt_t *gtgtp = ADDR2GTGTP(ap);
ata_tgt_t *tgtp = GTGTP2ATATGTP(gtgtp);
ADBG_TRACE(("atapi_tran_setcap entered\n"));
switch (scsi_hba_lookup_capstr(capstr)) {
case SCSI_CAP_SECTOR_SIZE:
tgtp->at_dma_attr.dma_attr_granular = (uint_t)value;
return (TRUE);
case SCSI_CAP_ARQ:
if (whom) {
tgtp->at_arq = value;
return (TRUE);
}
break;
case SCSI_CAP_TOTAL_SECTORS:
tgtp->at_total_sectors = value;
return (TRUE);
}
return (FALSE);
}
static int
atapi_tran_getcap(
struct scsi_address *ap,
char *capstr,
int whom)
{
struct ata_id ata_id;
struct ata_id *ata_idp;
ata_ctl_t *ata_ctlp;
ata_drv_t *ata_drvp;
gtgt_t *gtgtp;
int rval = -1;
ADBG_TRACE(("atapi_tran_getcap entered\n"));
if (capstr == NULL || whom == 0)
return (-1);
ata_ctlp = ADDR2CTL(ap);
switch (scsi_hba_lookup_capstr(capstr)) {
case SCSI_CAP_ARQ:
rval = TRUE;
break;
case SCSI_CAP_INITIATOR_ID:
rval = 7;
break;
case SCSI_CAP_DMA_MAX:
rval = 4096 * (ATA_DMA_NSEGS - 1);
break;
case SCSI_CAP_GEOMETRY:
if (atapi_use_static_geometry) {
rval = ATAPI_HEADS << 16 | ATAPI_SECTORS_PER_TRK;
break;
}
ata_drvp = CTL2DRV(ata_ctlp, ap->a_target, ap->a_lun);
gtgtp = ADDR2GTGTP(ap);
if (!ata_queue_cmd(atapi_id_update, &ata_id, ata_ctlp,
ata_drvp, gtgtp)) {
ADBG_TRACE(("atapi_tran_getcap geometry failed"));
return (0);
}
ata_idp = &ata_drvp->ad_id;
*ata_idp = ata_id;
switch ((ata_idp->ai_config >> 8) & 0xf) {
case DTYPE_RODIRECT:
rval = ATAPI_HEADS << 16 | ATAPI_SECTORS_PER_TRK;
break;
case DTYPE_DIRECT:
case DTYPE_OPTICAL:
rval = (ata_idp->ai_curheads << 16) |
ata_idp->ai_cursectrk;
break;
default:
rval = 0;
}
break;
}
return (rval);
}
static struct scsi_pkt *
atapi_tran_init_pkt(
struct scsi_address *ap,
struct scsi_pkt *spktp,
struct buf *bp,
int cmdlen,
int statuslen,
int tgtlen,
int flags,
int (*callback)(caddr_t),
caddr_t arg)
{
gtgt_t *gtgtp = ADDR2GTGTP(ap);
ata_tgt_t *ata_tgtp = GTGTP2ATATGTP(gtgtp);
ata_ctl_t *ata_ctlp = ADDR2CTL(ap);
ata_pkt_t *ata_pktp;
struct scsi_pkt *new_spktp;
ddi_dma_attr_t *sg_attrp;
int bytes;
ADBG_TRACE(("atapi_tran_init_pkt entered\n"));
sg_attrp = NULL;
if (bp == NULL) {
goto skip_dma_setup;
}
if (bp->b_bcount == 0) {
goto skip_dma_setup;
}
if ((GTGTP2ATADRVP(ADDR2GTGTP(ap))->ad_pciide_dma == ATA_DMA_OFF)) {
goto skip_dma_setup;
}
if (ata_dma_disabled)
goto skip_dma_setup;
if (((bp->b_flags & B_PAGEIO) == 0) &&
((uintptr_t)bp->b_un.b_addr) & PCIIDE_PRDE_ADDR_MASK) {
goto skip_dma_setup;
}
if (bp->b_bcount & 1) {
goto skip_dma_setup;
}
sg_attrp = &ata_tgtp->at_dma_attr;
skip_dma_setup:
new_spktp = ghd_tran_init_pkt_attr(&ata_ctlp->ac_ccc, ap, spktp, bp,
cmdlen, statuslen, tgtlen, flags,
callback, arg, sizeof (ata_pkt_t), sg_attrp);
if (new_spktp == NULL)
return (NULL);
ata_pktp = SPKT2APKT(new_spktp);
ata_pktp->ap_cdbp = new_spktp->pkt_cdbp;
if (statuslen > 255) {
statuslen = sizeof (struct scsi_arq_status);
}
ata_pktp->ap_statuslen = (uchar_t)statuslen;
if (spktp)
ata_pktp->ap_flags &= ~(AP_READ | AP_WRITE);
if (atapi_arq_enable == TRUE &&
ata_tgtp->at_arq == TRUE &&
ata_pktp->ap_statuslen >= sizeof (struct scsi_arq_status)) {
ADBG_TRACE(("atapi_tran_init_pkt ARQ\n"));
ata_pktp->ap_scbp =
(struct scsi_arq_status *)new_spktp->pkt_scbp;
ata_pktp->ap_flags |= AP_ARQ_ON_ERROR;
}
ata_pktp->ap_sec = 0;
ata_pktp->ap_count = 0;
if (ata_pktp->ap_sg_cnt) {
ASSERT(bp != NULL);
if (bp->b_flags & B_READ) {
ata_pktp->ap_flags |= AP_READ;
} else {
ata_pktp->ap_flags |= AP_WRITE;
}
ata_pktp->ap_pciide_dma = TRUE;
ata_pktp->ap_hicyl = 0;
ata_pktp->ap_lwcyl = 0;
return (new_spktp);
}
ata_pktp->ap_pciide_dma = FALSE;
if (bp && bp->b_bcount) {
if (cmdlen) {
bp_mapin(bp);
ata_pktp->ap_baddr = bp->b_un.b_addr;
ata_pktp->ap_bcount = 0;
ata_pktp->ap_boffset = 0;
}
ASSERT(ata_pktp->ap_baddr != NULL);
if (bp->b_flags & B_READ) {
ata_pktp->ap_flags |= AP_READ;
} else {
ata_pktp->ap_flags |= AP_WRITE;
}
if (GTGTP2ATADRVP(ADDR2GTGTP(ap))->ad_flags & AD_1SECTOR) {
size_t resid;
size_t tmp;
ata_pktp->ap_boffset += ata_pktp->ap_bcount;
resid = bp->b_bcount - ata_pktp->ap_boffset;
tmp = MIN(2048, resid);
ata_pktp->ap_bcount = tmp;
new_spktp->pkt_resid = resid - tmp;
} else {
ata_pktp->ap_bcount = bp->b_bcount;
new_spktp->pkt_resid = 0;
}
} else {
ata_pktp->ap_baddr = NULL;
ata_pktp->ap_bcount = 0;
ata_pktp->ap_boffset = 0;
}
bytes = min(ata_pktp->ap_bcount, ATAPI_MAX_BYTES_PER_DRQ);
ata_pktp->ap_hicyl = (uchar_t)(bytes >> 8);
ata_pktp->ap_lwcyl = (uchar_t)bytes;
return (new_spktp);
}
int
atapi_ccballoc(
gtgt_t *gtgtp,
gcmd_t *gcmdp,
int cmdlen,
int statuslen,
int tgtlen,
int ccblen)
{
ata_drv_t *ata_drvp = GTGTP2ATADRVP(gtgtp);
ata_pkt_t *ata_pktp = GCMD2APKT(gcmdp);
ADBG_TRACE(("atapi_ccballoc entered\n"));
ata_pktp->ap_gcmdp = gcmdp;
if (cmdlen > ata_drvp->ad_cdb_len) {
ADBG_WARN(("atapi_ccballoc: SCSI CDB too large!\n"));
return (FALSE);
}
ata_pktp->ap_cdb_len = (uchar_t)cmdlen;
ata_pktp->ap_cdb_pad =
((unsigned)(ata_drvp->ad_cdb_len - cmdlen)) >> 1;
ata_pktp->ap_start = atapi_fsm_start;
ata_pktp->ap_intr = atapi_fsm_intr;
ata_pktp->ap_complete = atapi_complete;
ata_pktp->ap_flags = AP_ATAPI;
ata_pktp->ap_hd = ata_drvp->ad_drive_bits;
ata_pktp->ap_cmd = ATC_PACKET;
return (TRUE);
}
static void
atapi_tran_destroy_pkt(
struct scsi_address *ap,
struct scsi_pkt *spktp)
{
gcmd_t *gcmdp = PKTP2GCMDP(spktp);
ADBG_TRACE(("atapi_tran_destroy_pkt entered\n"));
if (gcmdp->cmd_dma_handle != NULL) {
ghd_dmafree_attr(gcmdp);
}
ghd_pktfree(&ADDR2CTL(ap)->ac_ccc, ap, spktp);
}
void
atapi_ccbfree(
gcmd_t *gcmdp)
{
ADBG_TRACE(("atapi_ccbfree entered\n"));
}
static void
atapi_tran_dmafree(
struct scsi_address *ap,
struct scsi_pkt *spktp)
{
gcmd_t *gcmdp = PKTP2GCMDP(spktp);
ADBG_TRACE(("atapi_tran_dmafree entered\n"));
if (gcmdp->cmd_dma_handle != NULL) {
ghd_dmafree_attr(gcmdp);
}
}
static void
atapi_tran_sync_pkt(
struct scsi_address *ap,
struct scsi_pkt *spktp)
{
ADBG_TRACE(("atapi_tran_sync_pkt entered\n"));
if (PKTP2GCMDP(spktp)->cmd_dma_handle != NULL) {
ghd_tran_sync_pkt(ap, spktp);
}
}
static int
atapi_tran_start(
struct scsi_address *ap,
struct scsi_pkt *spktp)
{
ata_pkt_t *ata_pktp = SPKT2APKT(spktp);
ata_drv_t *ata_drvp = APKT2DRV(ata_pktp);
ata_ctl_t *ata_ctlp = ata_drvp->ad_ctlp;
gcmd_t *gcmdp = APKT2GCMD(ata_pktp);
int polled = FALSE;
int rc;
ADBG_TRACE(("atapi_tran_start entered\n"));
ata_pktp->ap_v_addr = ata_pktp->ap_baddr + ata_pktp->ap_boffset;
ata_pktp->ap_resid = ata_pktp->ap_bcount;
ata_pktp->ap_flags &= (AP_ATAPI | AP_READ | AP_WRITE | AP_ARQ_ON_ERROR);
spktp->pkt_reason = 0;
spktp->pkt_state = 0;
spktp->pkt_statistics = 0;
if (spktp->pkt_flags & FLAG_NOINTR) {
polled = TRUE;
}
#ifdef ___just_ignore_unsupported_flags___
if (spktp->pkt_flags & (FLAG_HTAG|FLAG_OTAG|FLAG_STAG)) {
spktp->pkt_reason = CMD_TRAN_ERR;
return (TRAN_BADPKT);
}
#endif
rc = ghd_transport(&ata_ctlp->ac_ccc, gcmdp, gcmdp->cmd_gtgtp,
spktp->pkt_time, polled, NULL);
if (rc != TRAN_ACCEPT)
return (rc);
return (rc);
}
static void
atapi_complete(
ata_drv_t *ata_drvp,
ata_pkt_t *ata_pktp,
int do_callback)
{
struct scsi_pkt *spktp = APKT2SPKT(ata_pktp);
struct scsi_status *scsi_stat = (struct scsi_status *)spktp->pkt_scbp;
ADBG_TRACE(("atapi_complete entered\n"));
ADBG_TRANSPORT(("atapi_complete: pkt = 0x%p\n", ata_pktp));
spktp->pkt_resid = ata_pktp->ap_resid;
if (ata_pktp->ap_flags & AP_SENT_CMD) {
spktp->pkt_state |=
STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD;
}
if (ata_pktp->ap_flags & AP_XFERRED_DATA) {
spktp->pkt_state |= STATE_XFERRED_DATA;
}
if (ata_pktp->ap_flags & AP_GOT_STATUS) {
spktp->pkt_state |= STATE_GOT_STATUS;
}
if (ata_pktp->ap_flags & AP_TRAN_ERROR) {
spktp->pkt_reason = CMD_TRAN_ERR;
} else if (ata_pktp->ap_flags & AP_BUS_RESET) {
spktp->pkt_reason = CMD_RESET;
spktp->pkt_statistics |= STAT_BUS_RESET;
} else if (ata_pktp->ap_flags & AP_DEV_RESET) {
spktp->pkt_reason = CMD_RESET;
spktp->pkt_statistics |= STAT_DEV_RESET;
} else if (ata_pktp->ap_flags & AP_ABORT) {
spktp->pkt_reason = CMD_ABORTED;
spktp->pkt_statistics |= STAT_ABORTED;
} else if (ata_pktp->ap_flags & AP_TIMEOUT) {
spktp->pkt_reason = CMD_TIMEOUT;
spktp->pkt_statistics |= STAT_TIMEOUT;
} else {
spktp->pkt_reason = CMD_CMPLT;
}
if (ata_pktp->ap_flags & AP_ERROR)
scsi_stat->sts_chk = 1;
else
scsi_stat->sts_chk = 0;
if (ata_pktp->ap_flags & AP_ARQ_ERROR) {
ADBG_ARQ(("atapi_complete ARQ error 0x%p\n", ata_pktp));
spktp->pkt_reason = CMD_TRAN_ERR;
} else if (ata_pktp->ap_flags & AP_ARQ_OKAY) {
static struct scsi_status zero_scsi_status = { 0 };
struct scsi_arq_status *arqp;
ADBG_ARQ(("atapi_complete ARQ okay 0x%p\n", ata_pktp));
spktp->pkt_state |= STATE_ARQ_DONE;
arqp = ata_pktp->ap_scbp;
arqp->sts_rqpkt_reason = CMD_CMPLT;
arqp->sts_rqpkt_state = STATE_XFERRED_DATA;
arqp->sts_rqpkt_status = zero_scsi_status;
arqp->sts_rqpkt_resid = 0;
arqp->sts_rqpkt_statistics = 0;
}
ADBG_TRANSPORT(("atapi_complete: reason = 0x%x stats = 0x%x "
"sts_chk = %d\n", spktp->pkt_reason, spktp->pkt_statistics,
scsi_stat->sts_chk));
if (do_callback && (spktp->pkt_comp))
(*spktp->pkt_comp)(spktp);
}
static int
atapi_id_update(
ata_ctl_t *ata_ctlp,
ata_drv_t *ata_drvp,
ata_pkt_t *ata_pktp)
{
ddi_acc_handle_t io_hdl1 = ata_ctlp->ac_iohandle1;
caddr_t ioaddr1 = ata_ctlp->ac_ioaddr1;
ddi_acc_handle_t io_hdl2 = ata_ctlp->ac_iohandle2;
caddr_t ioaddr2 = ata_ctlp->ac_ioaddr2;
struct ata_id *aidp;
int rc;
ddi_put8(io_hdl1, (uchar_t *)ioaddr1 + AT_DRVHD,
ata_drvp->ad_drive_bits);
ata_nsecwait(400);
if (!ata_wait(io_hdl2, ioaddr2, ATS_DRDY, ATS_BSY, 5 * 1000000)) {
ADBG_ERROR(("atapi_id_update: select failed\n"));
if (ata_pktp != NULL)
ata_pktp->ap_flags |= AP_ERROR;
return (ATA_FSM_RC_FINI);
}
if (ata_pktp != NULL)
aidp = (struct ata_id *)ata_pktp->ap_v_addr;
else
aidp = &ata_drvp->ad_id;
rc = atapi_id(ata_ctlp->ac_iohandle1, ata_ctlp->ac_ioaddr1,
ata_ctlp->ac_iohandle2, ata_ctlp->ac_ioaddr2, aidp);
if (rc) {
swab(aidp->ai_drvser, aidp->ai_drvser,
sizeof (aidp->ai_drvser));
swab(aidp->ai_fw, aidp->ai_fw,
sizeof (aidp->ai_fw));
swab(aidp->ai_model, aidp->ai_model,
sizeof (aidp->ai_model));
}
if (ata_pktp == NULL)
return (ATA_FSM_RC_FINI);
if (!rc) {
ata_pktp->ap_flags |= AP_ERROR;
} else {
ata_pktp->ap_flags |= AP_XFERRED_DATA;
}
return (ATA_FSM_RC_FINI);
}
void
atapi_init_arq(
ata_ctl_t *ata_ctlp)
{
ata_pkt_t *arq_pktp = ata_ctlp->ac_arq_pktp;
arq_pktp->ap_cdbp = ata_ctlp->ac_arq_cdb;
arq_pktp->ap_cdb_len = sizeof (ata_ctlp->ac_arq_cdb);
arq_pktp->ap_start = atapi_fsm_start;
arq_pktp->ap_intr = atapi_fsm_intr;
arq_pktp->ap_complete = atapi_complete;
arq_pktp->ap_flags = AP_ATAPI;
arq_pktp->ap_cmd = ATC_PACKET;
ata_ctlp->ac_arq_cdb[0] = SCMD_REQUEST_SENSE;
}
void
atapi_reset_dma_mode(ata_drv_t *ata_drvp, int need_wait)
{
ata_ctl_t *ata_ctlp = ata_drvp->ad_ctlp;
if (need_wait == TRUE)
drv_usecwait(5 * 100000);
ata_reset_dma_mode(ata_drvp);
(void) atapi_id_update(ata_ctlp, ata_drvp, NULL);
}