/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "ata_common.h"
#include "ata_disk.h"
#include "atapi.h"
#include "ata_blacklist.h"
#include "sil3xxx.h"
/*
* Solaris Entry Points.
*/
void *a, void *v);
/*
* GHD Entry points
*/
/*
* Local Function Prototypes
*/
int *DoneFlgp);
struct ata_id *ata_id_bufp);
dev_info_t *tdip);
static void ata_init_pm(dev_info_t *);
static int ata_suspend(dev_info_t *);
static int ata_resume(dev_info_t *);
static int ata_power(dev_info_t *, int, int);
static int ata_is_pci(dev_info_t *);
/*
* Local static data
*/
static void *ata_state;
/*
* Use local or framework power management
*/
#ifdef ATA_USE_AUTOPM
#else
#define ATA_BUSY_COMPONENT(d, c)
#define ATA_IDLE_COMPONENT(d, c)
#endif
/*
* number of seconds to wait during various operations
*/
/*
* Change this for SFF-8070i support. Currently SFF-8070i is
* using a field in the IDENTIFY PACKET DEVICE response which
* already seems to be in use by some vendor's drives. I suspect
* SFF will either move their laslun field or provide a reliable
* way to validate it.
*/
/*
* set this to disable all DMA requests
*/
/*
* set this to TRUE to enable storing the IDENTIFY DEVICE result in the
* "ata" or "atapi" property.
*/
/*
* set this to TRUE to enable logging device-capability data
*/
/*
* DMA selection message pointers
*/
char *ata_cntrl_DMA_sel_msg;
char *ata_dev_DMA_sel_msg;
/*
* bus nexus operations
*/
/* ARGSUSED */
static int
{
return (ENXIO);
return (0);
}
/*
* The purpose of this function is to pass the ioaddress of the controller
* to the caller, specifically used for upgrade from pre-pciide
* to pciide nodes
*/
/* ARGSUSED */
static int
{
long len;
return (ENXIO);
if (len <= 0)
return (0);
}
int
{
int instance;
int i;
int rc;
int flush_okay;
if (cmd != DDI_RESET_FORCE)
return (0);
if (!ata_ctlp)
return (0);
/*
* reset ATA drives and flush the write cache of any drives
*/
flush_okay = TRUE;
for (i = 0; i < ATA_MAXTARG; i++) {
continue;
/* Don't revert to defaults for certain IBM drives */
/* Enable revert to defaults when reset */
ATSF_ENA_REVPOD, 0);
}
/*
* skip flush cache if device type is cdrom
*
* notes: the structure definitions for ata_drvp->ad_id are
* defined for the ATA IDENTIFY_DEVICE, but if AD_ATAPI is set
* the struct holds data for the ATAPI IDENTIFY_PACKET_DEVICE
*/
/*
*/
ADBG_WARN(("ata_flush_cache %s\n",
if (!rc)
flush_okay = FALSE;
}
/*
* do something else if flush cache not supported
*/
}
/*
* just busy wait if any drive doesn't support FLUSH CACHE
*/
if (!flush_okay)
return (0);
}
/*
* quiesce(9E) entry point.
*
* This function is called when the system is single-threaded at high
* PIL with preemption disabled. Therefore, this function must not be
* blocked.
*
* This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
* DDI_FAILURE indicates an error condition and should almost never happen.
*/
int
{
#ifdef ATA_DEBUG
/*
* Turn off debugging
*/
ata_debug = 0;
#endif
}
ata_open, /* open */
nulldev, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
ata_read, /* read */
nodev, /* write */
nodev, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* chpoll */
ddi_prop_op, /* prop_op */
NULL, /* stream info */
D_MP, /* driver compatibility flag */
CB_REV, /* cb_ops revision */
nodev, /* aread */
nodev /* awrite */
};
DEVO_REV, /* devo_rev, */
0, /* refcnt */
ddi_getinfo_1to1, /* info */
nulldev, /* identify */
NULL, /* probe */
ata_attach, /* attach */
ata_detach, /* detach */
ata_devo_reset, /* reset */
&ata_cb_ops, /* driver operations */
NULL, /* bus operations */
ata_power, /* power */
ata_quiesce /* quiesce */
};
/* driver loadable module wrapper */
&mod_driverops, /* Type of module. This one is a driver */
"ATA AT-bus attachment disk controller Driver", /* module name */
&ata_ops, /* driver ops */
};
};
#ifdef ATA_DEBUG
/* | ADBG_FLAG_ARQ */
/* | ADBG_FLAG_INIT */
/* | ADBG_FLAG_TRACE */
/* | ADBG_FLAG_TRANSPORT */
/* | ADBG_FLAG_WARN */
;
#endif
int
_init(void)
{
int err;
#ifdef ATA_DEBUG
if (ata_debug_init)
debug_enter("\nATA _INIT\n");
#endif
return (err);
return (err);
}
/* save pointer to SCSA provided bus_ops struct */
/* make a copy of SCSA bus_ops */
/*
* Modify our bus_ops to call our routines. Our implementation
* accordingly.
*/
/* patch our bus_ops into the dev_ops struct */
}
/*
* Initialize the per driver timer info.
*/
return (err);
}
int
_fini(void)
{
int err;
}
return (err);
}
int
{
}
/*
*
* driver attach entry point
*
*/
static int
{
int atapi_count = 0;
int disk_count = 0;
ADBG_TRACE(("ata_attach entered\n"));
#ifdef ATA_DEBUG
if (ata_debug_attach)
debug_enter("\nATA_ATTACH\n\n");
#endif
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
return (ata_resume(dip));
default:
return (DDI_FAILURE);
}
/* initialize controller */
goto errout;
/* initialize drives */
continue;
if (first_drvp == NULL)
atapi_count++;
} else {
disk_count++;
lastlun = 0;
}
/*
* LUN support is currently disabled. Check with SFF-8070i
* before enabling.
*/
if (!ata_enable_atapi_luns)
lastlun = 0;
/* Initialize higher LUNs, if there are any */
if ((ata_drvp =
}
}
}
if ((atapi_count == 0) && (disk_count == 0)) {
ADBG_WARN(("ata_attach: no drives detected\n"));
goto errout1;
}
/*
* Always make certain that a valid drive is selected so
* that routines which poll the status register don't get
* confused by non-existent drives.
*/
ata_nsecwait(400);
/*
* make certain the drive selected
*/
0, ATS_BSY, 5000000)) {
ADBG_ERROR(("ata_attach: select failed\n"));
}
/*
* one drive of that type.
*/
if (atapi_count) {
if (!atapi_attach(ata_ctlp))
goto errout1;
}
if (disk_count) {
if (!ata_disk_attach(ata_ctlp))
goto errout1;
}
/*
* make certain the interrupt and error latches are clear
*/
DDI_PSEUDO, 0) != DDI_SUCCESS) {
goto errout1;
}
(void) ata_pciide_status_clear(ata_ctlp);
}
/*
* enable the interrupt handler and drop the mutex
*/
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
/* driver detach entry point */
static int
{
int instance;
int i;
int j;
ADBG_TRACE(("ata_detach entered\n"));
switch (cmd) {
case DDI_DETACH:
break;
case DDI_SUSPEND:
return (ata_suspend(dip));
default:
return (DDI_FAILURE);
}
if (!ata_ctlp)
return (DDI_SUCCESS);
if (ata_ctlp->ac_pm_support) {
ATA_BUSY_COMPONENT(dip, 0);
DDI_SUCCESS) {
ATA_IDLE_COMPONENT(dip, 0);
return (DDI_FAILURE);
}
}
}
/* destroy ata module */
/* destroy atapi module */
/* destroy drives */
for (i = 0; i < ATA_MAXTARG; i++) {
for (j = 0; j < ATA_MAXLUN; j++) {
}
}
if (ata_ctlp->ac_iohandle1)
if (ata_ctlp->ac_iohandle2)
if (ata_ctlp->ac_bmhandle)
/* destroy controller */
return (DDI_SUCCESS);
}
/*
* Nexus driver bus_ctl entry point
*/
/*ARGSUSED*/
static int
dev_info_t *d,
dev_info_t *r,
void *a,
void *v)
{
int target_type;
int rc;
char *bufp;
ADBG_TRACE(("ata_bus_ctl entered\n"));
switch (o) {
case DDI_CTLOPS_SIDDEV:
return (DDI_FAILURE);
case DDI_CTLOPS_IOMIN:
/*
* Since we use PIO, we return a minimum I/O size of
* one byte. This will need to be updated when we
* implement DMA support
*/
*((int *)v) = 1;
return (DDI_SUCCESS);
case DDI_CTLOPS_DMAPMAPC:
case DDI_CTLOPS_REPORTINT:
case DDI_CTLOPS_REGSIZE:
case DDI_CTLOPS_NREGS:
case DDI_CTLOPS_SLAVEONLY:
case DDI_CTLOPS_AFFINITY:
case DDI_CTLOPS_POKE:
case DDI_CTLOPS_PEEK:
/* These ops shouldn't be called by a target driver */
ADBG_ERROR(("ata_bus_ctl: %s%d: invalid op (%d) from %s%d\n",
ddi_driver_name(d), ddi_get_instance(d), o,
ddi_driver_name(r), ddi_get_instance(r)));
return (DDI_FAILURE);
case DDI_CTLOPS_REPORTDEV:
case DDI_CTLOPS_INITCHILD:
case DDI_CTLOPS_UNINITCHILD:
/* these require special handling below */
break;
default:
return (ddi_ctlops(d, r, o, a, v));
}
/* get targets dip */
if (o == DDI_CTLOPS_INITCHILD || o == DDI_CTLOPS_UNINITCHILD)
tdip = (dev_info_t *)a;
else
tdip = r;
/*
* XXX - Get class of target
* Before the "class" entry in a conf file becomes
* a real property, we use an additional property
* tentatively called "class_prop". We will require that
* new classes (ie. direct) export "class_prop".
* SCSA target drivers will not have this property, so
* no property implies SCSA.
*/
else {
ADBG_WARN(("ata_bus_ctl: invalid target class %s\n",
bufp));
return (DDI_FAILURE);
}
} else {
}
if (o == DDI_CTLOPS_INITCHILD) {
int targ;
int lun;
int drive_type;
char *disk_prop;
char *class_prop;
ADBG_WARN(("ata_bus_ctl: failed to find ctl struct\n"));
return (DDI_FAILURE);
}
/* get (target,lun) of child device */
"target", -1);
if (targ == -1) {
ADBG_WARN(("ata_bus_ctl: failed to get targ num\n"));
return (DDI_FAILURE);
}
"lun", 0);
return (DDI_FAILURE);
}
return (DDI_FAILURE); /* no drive */
/* get type of device */
else
/*
* Check for special handling when child driver is
* cmdk (which morphs to the correct interface)
*/
if ((target_type == ATA_DEV_DISK) &&
(target_type != drive_type))
return (DDI_FAILURE);
if (drive_type == ATA_DEV_ATAPI) {
class_prop = "scsi";
} else {
disk_prop = "dadk";
class_prop = "dada";
ADBG_WARN(("ata_bus_ctl: failed to "
"create disk prop\n"));
return (DDI_FAILURE);
}
}
ADBG_WARN(("ata_bus_ctl: failed to "
"create class prop\n"));
return (DDI_FAILURE);
}
}
/* Check that target class matches the device */
if (target_type != drive_type)
return (DDI_FAILURE);
/* save pointer to drive struct for ata_disk_bus_ctl */
/*
* Determine whether to enable DMA support for this drive. This
* check is deferred to this point so that the various dma
* properties could reside on the devinfo node should finer
* grained dma control be required.
*/
}
}
if (target_type == ATA_DEV_ATAPI) {
} else {
rc = ata_disk_bus_ctl(d, r, o, a, v);
}
return (rc);
}
/*
*
* GHD ccc_hba_complete callback
*
*/
/* ARGSUSED */
static void
void *hba_handle,
int do_callback)
{
ADBG_TRACE(("ata_hba_complete entered\n"));
if (ata_pktp->ap_complete)
}
/* GHD ccc_timeout_func callback */
/* ARGSUSED */
static int
void *hba_handle,
int calltype)
{
ADBG_TRACE(("ata_timeout_func entered\n"));
else
switch (action) {
case GACTION_EARLY_ABORT:
/* abort before request was started */
}
return (TRUE);
case GACTION_EARLY_TIMEOUT:
/* timeout before request was started */
}
return (TRUE);
case GACTION_RESET_TARGET:
/*
* Reset a device is not supported. Resetting a specific
* device can't be done at all to an ATA device and if
* you send a RESET to an ATAPI device you have to
* reset the whole bus to make certain both devices
* on the bus stay in sync regarding which device is
* the currently selected one.
*/
return (FALSE);
case GACTION_RESET_BUS:
/*
* Issue bus reset and reinitialize both drives.
* But only if this is a timed-out request. Target
* driver reset requests are ignored because ATA
* and ATAPI devices shouldn't be gratuitously reset.
* Also disable DMA if it is a CF device.
*/
break;
return (ata_reset_bus(ata_ctlp));
default:
break;
}
return (FALSE);
}
/*
*
* Initialize controller's soft-state structure
*
*/
static ata_ctl_t *
{
int instance;
ADBG_TRACE(("ata_init_controller entered\n"));
/* allocate controller structure */
ADBG_WARN(("ata_init_controller: soft_state_zalloc failed\n"));
return (NULL);
}
ADBG_WARN(("ata_init_controller: failed to find "
"controller struct\n"));
return (NULL);
}
/*
* initialize per-controller data
*/
/*
* map the device registers
*/
return (NULL);
}
ADBG_INIT(("ata_init_controller: ioaddr1 = 0x%p, ioaddr2 = 0x%p\n",
/*
* Do ARQ setup
*/
/*
* Do PCI-IDE setup
*/
/*
* port addresses associated with ioaddr1
*/
/*
* port addresses associated with ioaddr2
*/
/*
* If AC_BSY_WAIT needs to be set for laptops that do
* drop after a resume.
*/
/*
* get max transfer size, default to 256 sectors
*/
/*
* Get the standby timer value
*/
/*
*/
return (NULL);
}
addr1);
return (NULL);
}
}
/* Init controller specific stuff */
(void) ata_spec_init_controller(dip);
/*
* initialize GHD
*/
&ata_timer_conf, NULL)) {
return (NULL);
}
return (ata_ctlp);
}
/* destroy a controller */
static void
{
int instance;
ADBG_TRACE(("ata_destroy_controller entered\n"));
return;
/* destroy ghd */
/* free the pciide buffer (if any) */
/* destroy controller struct */
}
/*
*
* initialize a drive
*
*/
static ata_drv_t *
{
int drive_type;
int i;
int valid_version = 0;
ADBG_TRACE(("ata_init_drive entered, targ = %d, lun = %d\n",
/* check if device already exists */
return (ata_drvp);
/* allocate new device structure */
/*
* set up drive struct
*/
/*
* Add the LUN for SFF-8070i support
*/
/*
* get drive type, side effect is to collect
* IDENTIFY DRIVE data
*/
aidp);
switch (drive_type) {
case ATA_DEV_NONE:
/* no drive found */
goto errout;
case ATA_DEV_ATAPI:
break;
case ATA_DEV_DISK:
break;
}
/*
* swap bytes of all text fields
*/
}
/*
* Check if this drive has the Single Sector bug
*/
else
else
/* Check if this drive has the "revert to defaults" bug */
/* Dump the drive info */
buf[i] = '\0';
ATAPRT(("?\t%s device at targ %d, lun %d lastlun 0x%x\n",
for (i = 14; i >= 2; i--) {
valid_version = i;
break;
}
}
ATAPRT((
aidp->ai_minorversion));
}
if (ata_capability_data) {
ATAPRT(("?\t\tstat %x, err %x\n",
ATAPRT(("?\t\tcfg 0x%x, cap 0x%x\n",
/*
* Be aware that ATA-6 and later drives may not provide valid
* geometry information and other obsoleted info.
* Select what is printed based on supported ATA model (skip
*/
/*
* Supported version less then ATA-6
*/
aidp->ai_sectors));
}
ATAPRT(("?\t\tmult1 0x%x, mult2 0x%x\n",
ATAPRT((
"?\t\tpiomode 0x%x, dmamode 0x%x, advpiomode 0x%x\n",
aidp->ai_advpiomode));
} else {
ATAPRT(("?\t\tadvpiomode 0x%x\n",
aidp->ai_advpiomode));
}
ATAPRT(("?\t\tminpio %d, minpioflow %d\n",
aidp->ai_minpioflow));
ATAPRT(("?\t\tdwdma 0x%x, ultradma 0x%x\n",
aidp->ai_ultradma));
} else {
ATAPRT(("?\t\tdwdma 0x%x\n",
aidp->ai_dworddma));
}
}
if (!atapi_init_drive(ata_drvp))
goto errout;
} else {
if (!ata_disk_init_drive(ata_drvp))
goto errout;
}
/*
* store pointer in controller struct
*/
/*
* lock the drive's current settings in case I have to
* reset the drive due to some sort of error
*/
return (ata_drvp);
return (NULL);
}
/* destroy a drive */
static void
{
#if 0
#endif
ADBG_TRACE(("ata_uninit_drive entered\n"));
#if 0
/*
* DON'T DO THIS. disabling interrupts floats the IRQ line
* which generates spurious interrupts
*/
/*
* Select the correct drive
*/
ata_nsecwait(400);
/*
* Disable interrupts from the drive
*/
#endif
/* interface specific clean-ups */
/* free drive struct */
}
/*
* ata_drive_type()
*
* The timeout values and exact sequence of checking is critical
* especially for atapi device detection, and should not be changed lightly.
*
*/
static int
struct ata_id *ata_id_bufp)
{
ADBG_TRACE(("ata_drive_type entered\n"));
/*
* select the appropriate drive and LUN
*/
ata_nsecwait(400);
/*
* make certain the drive is selected, and wait for not busy
*/
5 * 1000000);
return (ATA_DEV_NONE);
}
return (ATA_DEV_DISK);
/*
* No disk, check for atapi unit.
*/
#ifndef ATA_DISABLE_ATAPI_1_7
/*
* Check for old (but prevalent) atapi 1.7B
* spec device, the only known example is the
* NEC CDR-260 (not 260R which is (mostly) ATAPI 1.2
* compliant). This device has no signature
* and requires conversion from hex to BCD
* for some scsi audio commands.
*/
return (ATA_DEV_ATAPI);
}
#endif
return (ATA_DEV_NONE);
}
return (ATA_DEV_ATAPI);
}
return (ATA_DEV_NONE);
}
/*
* nsec-granularity time delay function
*/
void
{
extern int tsc_gethrtime_initted;
if (tsc_gethrtime_initted) {
SMT_PAUSE();
}
} else {
}
}
/*
* Wait for a register of a controller to achieve a specific state.
* To return normally, all the bits in the first sub-mask must be ON,
* all the bits in the second sub-mask must be OFF.
* If timeout_usec microseconds pass without the controller achieving
* the desired bit configuration, we return TRUE, else FALSE.
*/
int
{
do {
return (TRUE);
return (FALSE);
}
/*
*
* This is a slightly more complicated version that checks
* for error conditions and bails-out rather than looping
* until the timeout expires
*/
int
{
do {
/*
* check for expected condition
*/
return (TRUE);
/*
* check for error conditions
*/
(val & failure_offbits2) == 0) {
return (FALSE);
}
(val & failure_offbits3) == 0) {
return (FALSE);
}
return (FALSE);
}
/*
*
* low level routine for ata_disk_id() and atapi_id()
*
*/
int
int expect_drdy,
{
ADBG_TRACE(("ata_id_common entered\n"));
/*
* clear the features register
*/
/*
* Disable interrupts from the device. When the ata
* hardware is sharing its interrupt with another
* device, the shared interrupt might have already been
* unmasked in the interrupt controller and
* triggering ata device interrupts will result in an
* interrupt storm and a hung system.
*/
/*
* issue IDENTIFY DEVICE or IDENTIFY PACKET DEVICE command
*/
/* wait for the busy bit to settle */
ata_nsecwait(400);
/*
* read alternate status and check for conditions which
* may indicate the drive is not present, to prevent getting
* stuck in ata_wait3() below.
*/
/*
* 0x0, 0x7f, or ATS_DF can happen when no drive is present
*/
/* invalid status, can't be an ATA or ATAPI device */
return (FALSE);
}
/*
* According to the ATA specification, some drives may have
* to read the media to complete this command. We need to
* make sure we give them enough time to respond.
*/
/*
* read the status byte and clear the pending interrupt
*/
/*
* this happens if there's no drive present
*/
/* invalid status, can't be an ATA or ATAPI device */
return (FALSE);
}
ADBG_ERROR(("ata_id_common: BUSY status 0x%x error 0x%x\n",
return (FALSE);
}
return (FALSE);
}
/*
* Give the drive another second to assert DRQ. Some older
* drives de-assert BSY before asserting DRQ. Bail out
* immediately if the status becomes 0x7f, which is invalid
* value. It can happen when no drive is present.
*/
ADBG_WARN(("ata_id_common: "
"!DRQ status 0x%x error 0x%x\n",
return (FALSE);
}
}
/*
* transfer the data
*/
/* wait for the busy bit to settle */
ata_nsecwait(400);
/*
* Wait for the drive to recognize I've read all the data.
* Some drives have been observed to take as much as 3msec to
* deassert DRQ after reading the data; allow 1 sec just in case.
*
* Note: some non-compliant ATAPI drives (e.g., NEC Multispin 6V,
* CDR-1350A) don't assert DRDY. If we've made it this far we can
* safely ignore the DRDY bit since the ATAPI Packet command
* actually doesn't require it to ever be asserted.
*
* Bail out immediately if the status becomes 0x7f, which is invalid
* value. It can happen when no drive is present.
*
*/
ADBG_WARN(("ata_id_common: bad status 0x%x error 0x%x\n",
return (FALSE);
}
/*
* Check to see if the command aborted. This happens if
* an IDENTIFY DEVICE command is issued to an ATAPI PACKET device,
* or if an IDENTIFY PACKET DEVICE command is issued to an ATA
* (non-PACKET) device.
*/
ADBG_WARN(("ata_id_common: status 0x%x error 0x%x \n",
return (FALSE);
}
return (TRUE);
}
/*
* Low level routine to issue a non-data command and busy wait for
* the completion status.
*/
int
int expect_drdy,
int silent,
{
/* select the drive */
ata_nsecwait(400);
/* make certain the drive selected */
ADBG_ERROR(("ata_command: select failed "
"DRDY 0x%x CMD 0x%x F 0x%x N 0x%x "
"S 0x%x H 0x%x CL 0x%x CH 0x%x\n",
return (FALSE);
}
/*
* set all the regs
*/
/* send the command */
/* wait for the busy bit to settle */
ata_nsecwait(400);
/* wait for not busy */
ADBG_ERROR(("ata_command: BSY too long!"
"DRDY 0x%x CMD 0x%x F 0x%x N 0x%x "
"S 0x%x H 0x%x CL 0x%x CH 0x%x\n",
return (FALSE);
}
/*
* wait for DRDY before continuing
*/
/* read status to clear IRQ, and check for error */
return (TRUE);
if (!silent) {
ADBG_ERROR(("ata_command status 0x%x error 0x%x "
"DRDY 0x%x CMD 0x%x F 0x%x N 0x%x "
"S 0x%x H 0x%x CL 0x%x CH 0x%x\n",
}
return (FALSE);
}
/*
*
* Issue a SET FEATURES command
*
*/
int
{
int rc;
/* feature, count, sector, head, cyl_low, cyl_hi */
if (rc) {
return (TRUE);
}
return (FALSE);
}
/*
*
* Issue a FLUSH CACHE command
*
*/
static int
{
/* this command is optional so fail silently */
ATC_FLUSH_CACHE, 0, 0, 0, 0, 0, 0));
}
/*
* ata_setup_ioaddr()
*
* Map the device registers and return the handles.
*
* If this is a ISA-ATA controller then only two handles are
* initialized and returned.
*
* If this is a PCI-IDE controller than a third handle (for the
* PCI-IDE Bus Mastering registers) is initialized and returned.
*
*/
static int
{
int rnumber;
int rc;
/*
* Make certain the controller is enabled and its regs are map-able
*
*/
ADBG_INIT(("ata_setup_ioaddr(1): rc %d regsize %lld\n",
return (FALSE);
}
ADBG_INIT(("ata_setup_ioaddr(2): rc %d regsize %lld\n",
return (FALSE);
}
/*
* setup the device attribute structure for little-endian,
* strict ordering access.
*/
/*
* Determine whether this is a ISA, PNP-ISA, or PCI-IDE device
*/
/* it's PNP-ISA, skip over the extra reg tuple */
rnumber = 1;
goto not_pciide;
}
/* else, it's ISA or PCI-IDE, check further */
rnumber = 0;
if (!ata_is_pci(dip)) {
/*
* If it's not a PCI-IDE, there are only two reg tuples
* and the first one contains the I/O base (170 or 1f0)
* rather than the controller instance number.
*/
ADBG_TRACE(("ata_setup_ioaddr !pci-ide\n"));
goto not_pciide;
}
/*
* Map the correct half of the PCI-IDE Bus Master registers.
* There's a single BAR that maps these registers for both
* controller's in a dual-controller chip and it's upto my
* parent nexus, pciide, to adjust which (based on my instance
* number) half this call maps.
*/
ADBG_INIT(("ata_setup_ioaddr(3): rc %d regsize %lld\n",
goto not_pciide;
}
if (rc != DDI_SUCCESS) {
/* map failed, try to use in non-pci-ide mode */
ADBG_WARN(("ata_setup_ioaddr bus master map failed, rc=0x%x\n",
rc));
}
/*
* map the lower command block registers
*/
handle1p);
if (rc != DDI_SUCCESS) {
goto out1;
}
/*
* If the controller is being used in compatibility mode
* will specify zeros for the I/O ports for the PCI
* instance.
*/
if (*addr1p == 0) {
ADBG_TRACE(("ata_setup_ioaddr ioaddr1 0\n"));
goto out2;
}
/*
* map the upper control block registers
*/
handle2p);
if (rc == DDI_SUCCESS)
return (TRUE);
out2:
}
out1:
}
return (FALSE);
}
/*
*
* Currently, the only supported controllers are ones which
* support the SFF-8038 Bus Mastering spec.
*
* Check the parent node's IEEE 1275 class-code property to
* determine if it's an PCI-IDE instance which supports SFF-8038
* Bus Mastering. It's perfectly valid to have a PCI-IDE controller
* that doesn't do Bus Mastering. In that case, my interrupt handler
* only uses the interrupt latch bit in PCI-IDE status register.
* The assumption is that the programming interface byte of the
* class-code property reflects the bus master DMA capability of
* the controller.
*
* Whether the drive support supports the DMA option still needs
* to be checked later. Each individual request also has to be
* checked for alignment and size to decide whether to use the
* DMA transfer mode.
*/
static void
{
ata_cntrl_DMA_sel_msg = "cntrl not Bus Master DMA capable";
return;
}
/*
* check if it's a known bogus PCI-IDE chip
*/
ADBG_WARN(("ata_setup_ioaddr pci-ide blacklist\n"));
ata_cntrl_DMA_sel_msg = "cntrl blacklisted";
return;
}
}
/*
* check for a PCI-IDE chip with a broken DMA engine
*/
"cntrl blacklisted/DMA engine broken";
return;
}
/*
* Check the Programming Interface register to determine
* if this device supports PCI-IDE Bus Mastering. Some PCI-IDE
* devices don't support Bus Mastering or DMA.
* Since we are dealing with pre-qualified pci-ide controller,
* check programming interface byte only.
*/
DDI_PROP_DONTPASS, "class-code", 0);
"cntrl not Bus Master DMA capable";
return;
}
/*
* Avoid doing DMA on "simplex" chips which share hardware
* between channels
*/
/*
* Some motherboards have CSB5's that are wired "to emulate CSB4 mode".
* In such a mode, the simplex bit is asserted, but in fact testing
* on such a motherboard has shown that the devices are not simplex
* -- DMA can be used on both channels concurrently with no special
* considerations. For chips like this, we have the ATA_BL_NO_SIMPLEX
* flag set to indicate that the value of the simplex bit can be
* ignored.
*/
if (status & PCIIDE_BMISX_SIMPLEX) {
} else {
/*
* By default,use DMA on channel 0 and PIO on channel
* 1. This can be switched by setting
* ata-simplex-dma-channel to:
* 0 DMA on channel 0 (default without this
* property)
* 1 DMA on channel 1
* any other value: DMA off on both channels.
*/
if (simplex_dma_channel == channel) {
"controller. DMA on channel"
" %d PIO on channel %d",
} else {
"simplex controller";
}
}
return;
}
}
}
/*
* It's a compatible PCI-IDE Bus Mastering controller,
*/
else {
ata_cntrl_DMA_sel_msg = "unable to init DMA S/G list";
}
}
/*
*
* Determine whether to enable DMA support for this drive.
* The controller and the drive both have to support DMA.
* The controller's capabilities were already checked in
* ata_init_pciide(), now just check the drive's capabilities.
*
*/
static int
{
int ata_options;
"controller is not Bus Master capable";
return (ATA_DMA_OFF);
}
0, "ata-options", 0);
if (!(ata_options & ATA_OPTIONS_DMA)) {
/*
* Either the ata-options property was not found or
* DMA is not enabled by this property
*/
"disabled by \"ata-options\" property";
return (ATA_DMA_OFF);
}
ata_dev_DMA_sel_msg = "device not DMA capable; blacklisted";
return (ATA_DMA_OFF);
}
/*
* DMA mode is mandatory on ATA-3 (or newer) drives but is
* optional on ATA-2 (or older) drives.
*
* On ATA-2 drives the ai_majorversion word will probably
* be 0xffff or 0x0000, check the (now obsolete) DMA bit in
* the capabilities word instead. The order of these tests
* is important since an ATA-3 drive doesn't have to set
* the DMA bit in the capabilities word.
*
*/
ata_dev_DMA_sel_msg = "device not DMA capable";
return (ATA_DMA_OFF);
}
/*
* Disable DMA for ATAPI devices on controllers known to
* have trouble with ATAPI DMA
*/
"controller incapable of DMA for ATAPI device";
return (ATA_DMA_OFF);
}
}
0, "ata-dma-enabled", TRUE);
0, "ata-disk-dma-enabled", TRUE);
0, "atapi-cd-dma-enabled", FALSE);
0, "atapi-other-dma-enabled", TRUE);
"DMA disabled by \"ata-dma-enabled\" property");
ata_dev_DMA_sel_msg = "disabled by prop ata-dma-enabled";
return (ATA_DMA_OFF);
}
"disabled. Control with \"atapi-cd-dma-enabled\""
" property";
return (ATA_DMA_OFF);
}
"disabled by \"ata-disk-dma-enabled\" property";
return (ATA_DMA_OFF);
}
"disabled by \"atapi-other-dma-enabled\" property";
return (ATA_DMA_OFF);
}
return (ATA_DMA_ON);
}
/*
* this compare routine squeezes out extra blanks and
* returns TRUE if p1 matches the leftmost substring of p2
*/
static int
char *p1,
char *p2,
int cnt)
{
for (;;) {
/*
* skip over any extra blanks in both strings
*/
p1++;
p2++;
cnt--;
}
/*
* compare the two strings
*/
break;
p1++;
p2++;
cnt--;
}
}
/* return TRUE if both strings ended at same point */
}
/*
* Per PSARC/1997/281 create variant="atapi" property (if necessary)
* on the target's dev_info node. Currently, the sd target driver
* is the only driver which refers to this property.
*
* If the flag ata_id_debug is set also create the
* the "ata" or "atapi" property on the target's dev_info node
*
*/
int
char *name)
{
int rc;
"variant", name);
if (rc != DDI_PROP_SUCCESS)
return (FALSE);
}
if (!ata_id_debug)
return (TRUE);
if (rc != DDI_PROP_SUCCESS) {
}
return (TRUE);
}
/* *********************************************************************** */
/* *********************************************************************** */
/* *********************************************************************** */
/*
* This state machine doesn't implement the ATAPI Optional Overlap
* feature. You need that feature to efficiently support ATAPI
* tape drives. See the 1394-ATA Tailgate spec (D97107), Figure 24,
* for an example of how to add the necessary additional NextActions
* and NextStates to this FSM and the atapi_fsm, in order to support
* the Overlap Feature.
*/
/* --------------------- next action --------------------- | - current - */
/* start0 --- start1 ---- intr ------ fini --- reset --- */
};
/* --------------------- next state --------------------- | - current - */
/* start0 --- start1 ---- intr ------ fini --- reset --- */
};
static int
int *DoneFlgp)
{
int rc;
/*
* Set the controller's new state
*/
switch (action) {
case AC_BUSY:
return (ATA_FSM_RC_BUSY);
case AC_NADA:
return (ATA_FSM_RC_OKAY);
case AC_START:
if (rc == ATA_FSM_RC_BUSY) {
/* the request didn't start, GHD will requeue it */
}
return (rc);
case AC_INTR:
case AC_RESET_A: /* Reset, controller active */
/* clean up the active request */
/* halt the DMA engine */
if (ata_pktp->ap_pciide_dma) {
(void) ata_pciide_status_clear(ata_ctlp);
}
/* Do a Software Reset to unwedge the bus */
if (!ata_software_reset(ata_ctlp)) {
return (ATA_FSM_RC_BUSY);
}
/* Then send a DEVICE RESET cmd to each ATAPI device */
return (ATA_FSM_RC_FINI);
case AC_RESET_I: /* Reset, controller idle */
/* Do a Software Reset to unwedge the bus */
if (!ata_software_reset(ata_ctlp)) {
return (ATA_FSM_RC_BUSY);
}
/* Then send a DEVICE RESET cmd to each ATAPI device */
return (ATA_FSM_RC_OKAY);
case AC_FINI:
break;
}
/*
* AC_FINI, check ARQ needs to be started or finished
*/
/*
* The active request is done now.
* Disconnect the request from the controller and
* add it to the done queue.
*/
/*
* If ARQ pkt is done, get ptr to original pkt and wrap it up.
*/
else
goto all_done;
}
/*
* Start ARQ pkt if necessary
*/
/* set controller state back to active */
/* try to start the ARQ pkt */
if (rc == ATA_FSM_RC_BUSY) {
/* let the target driver handle the problem */
goto all_done;
}
return (rc);
}
/*
* Normal completion, no error status, and not an ARQ pkt,
* just fall through.
*/
/*
* wrap everything up and tie a ribbon around it
*/
if (DoneFlgp)
}
return (ATA_FSM_RC_OKAY);
}
static int
{
int bytes;
/*
* Determine just the size of the Request Sense Data buffer within
* the scsi_arq_status structure.
*/
- sizeof (struct scsi_extended_sense))
/* save ptr to original pkt */
/* switch the controller's active pkt to the ARQ pkt */
/* finish initializing the ARQ CDB */
/* finish initializing the ARQ pkt */
/*
* This packet is shared by all drives on this controller
* therefore we need to init the drive number on every ARQ.
*/
/* start it up */
}
/*
*
* reset the bus
*
*/
static int
{
int watchdog;
/*
* Do a Software Reset to unwedge the bus, and send
* ATAPI DEVICE RESET to each ATAPI drive.
*/
&DoneFlg)) {
case ATA_FSM_RC_OKAY:
goto fsm_done;
case ATA_FSM_RC_BUSY:
return (FALSE);
case ATA_FSM_RC_INTR:
continue;
case ATA_FSM_RC_FINI:
continue;
}
}
ADBG_WARN(("ata_reset_bus: watchdog\n"));
/*
* Reinitialize the ATA drives
*/
continue;
continue;
/*
* and current geometry into the drive.
*/
}
/* If DoneFlg is TRUE, it means that ghd_complete() function */
/* has been already called. In this case ignore any errors and */
/* return TRUE to the caller, otherwise return the value of rc */
/* to the caller */
if (DoneFlg)
return (TRUE);
else
return (rc);
}
/*
*
* Low level routine to toggle the Software Reset bit
*
*/
static int
{
ADBG_TRACE(("ata_reset_bus entered\n"));
/* disable interrupts and turn the software reset bit on */
drv_usecwait(30000);
/* turn the software reset bit back off */
/*
* Wait for the controller to assert BUSY status.
* spec says 400 nsecs, (and 2 msecs if device
* was in sleep mode; but we don't put drives to sleep
* so it probably doesn't matter).
*/
drv_usecwait(300000);
/*
* If drive 0 exists the test for completion is simple
*/
goto wait_for_not_busy;
}
/*
* This must be a single device configuration, with drive 1
* only. This complicates the test for completion because
* issuing the software reset just caused drive 1 to
* deselect. With drive 1 deselected, if I just read the
* status register to test the BSY bit I get garbage, but
* I can't re-select drive 1 until I'm certain the BSY bit
* is de-asserted. Catch-22.
*
* this situation like this:
*/
/* give up if the drive doesn't settle within 31 seconds */
/*
* delay 10msec each time around the loop
*/
drv_usecwait(10000);
/*
* try to select drive 1
*/
continue;
continue;
goto wait_for_not_busy;
}
return (FALSE);
/*
* Now wait up to 31 seconds for BUSY to clear.
*/
return (TRUE);
}
/*
*
* DDI interrupt handler
*
*/
static uint_t
{
}
/*
*
* GHD ccc_get_status callback
*
*/
static int
void *hba_handle,
void *intr_status)
{
ADBG_TRACE(("ata_get_status entered\n"));
/*
* ignore interrupts before ata_attach completes
*/
return (FALSE);
/*
* can't be interrupt pending if nothing active
*/
case AS_IDLE:
return (FALSE);
case AS_ACTIVE0:
case AS_ACTIVE1:
break;
}
/*
* If this is a PCI-IDE controller, check the PCI-IDE controller's
* interrupt status latch. But don't clear it yet.
*
* AC_BMSTATREG_PIO_BROKEN flag is used currently for
* CMD chips with device id 0x646. Since the interrupt bit on
* Bus master IDE register is not usable when in PIO mode,
* this chip is treated as a legacy device for interrupt
* indication. The following code for CMD
* chips may need to be revisited when we enable support for dma.
*
* CHANGE: DMA is not disabled for these devices. BM intr bit is
* checked only if there was DMA used or BM intr is useable on PIO,
* else treat it as before - as legacy device.
*/
return (FALSE);
} else {
/*
* and drives don't have an interrupt status bit.
*
* Use a one_shot variable to make sure we only return
* one status per interrupt.
*/
if (intr_status != NULL) {
if (*one_shot == 1)
*one_shot = 0;
else
return (FALSE);
}
}
/* check if device is still busy */
return (FALSE);
return (TRUE);
}
/*
*
* get the current status and clear the IRQ
*
*/
int
{
/*
* Here's where we clear the PCI-IDE interrupt latch. If this
* request used DMA mode then we also have to check and clear
* the DMA error latch at the same time.
*/
if (ata_pktp->ap_pciide_dma) {
/*
* Some requests don't use DMA mode and therefore won't
* set the DMA error latch, but we still have to clear
* the interrupt latch.
* Controllers with broken BM intr in PIO mode do not go
* through this path.
*/
(void) ata_pciide_status_clear(ata_ctlp);
}
/*
* this clears the drive's interrupt
*/
return (status);
}
/*
*
* GHD interrupt handler
*
*/
/* ARGSUSED */
static void
void *hba_handle,
void *intr_status)
{
int watchdog;
int rc;
ADBG_TRACE(("ata_process_intr entered\n"));
/*
* process the ATA or ATAPI interrupt
*/
switch (rc) {
case ATA_FSM_RC_OKAY:
return;
case ATA_FSM_RC_BUSY: /* wait for the next interrupt */
return;
case ATA_FSM_RC_INTR: /* re-invoke the FSM */
break;
case ATA_FSM_RC_FINI: /* move a request to done Q */
break;
}
}
ADBG_WARN(("ata_process_intr: watchdog\n"));
}
/*
*
* GHD ccc_hba_start callback
*
*/
static int
void *hba_handle,
{
int request_started;
int watchdog;
ADBG_TRACE(("ata_hba_start entered\n"));
ADBG_WARN(("ata_hba_start drvp not null\n"));
return (FALSE);
}
ADBG_WARN(("ata_hba_start pktp not null\n"));
return (FALSE);
}
/*
* which drive?
*/
else
/*
* start the request
*/
NULL)) {
case ATA_FSM_RC_OKAY:
goto fsm_done;
case ATA_FSM_RC_BUSY:
/* if first time, tell GHD to requeue the request */
goto fsm_done;
case ATA_FSM_RC_INTR:
/*
* The start function polled for the next
* bus phase, now fake an interrupt to process
* the next action.
*/
break;
case ATA_FSM_RC_FINI: /* move request to the done queue */
break;
}
}
ADBG_WARN(("ata_hba_start: watchdog\n"));
return (request_started);
}
static int
{
int *propp;
int rc;
DDI_PROP_DONTPASS, "vendor-id", 0);
DDI_PROP_DONTPASS, "device-id", 0);
/*
* first check for a match in the "pci-ide-blacklist" property
*/
if (rc == DDI_PROP_SUCCESS) {
while (count--) {
/* check for matching ID */
blp++;
continue;
}
blp++;
continue;
}
/* got a match */
return (TRUE);
} else {
return (FALSE);
}
}
}
/*
* then check the built-in blacklist
*/
continue;
continue;
continue;
return (TRUE);
}
return (FALSE);
}
int
{
continue;
continue;
}
return (TRUE);
return (FALSE);
}
return (FALSE);
}
/*
* Queue a request to perform some sort of internally
* generated command. When this request packet reaches
* the front of the queue (*func)() is invoked.
*
*/
int
void *arg,
{
int rc;
ADBG_ERROR(("atapi_id_update alloc failed\n"));
return (FALSE);
}
/* set the back ptr from the ata_pkt to the gcmd_t */
/*
* over-ride the default start function
*/
/*
* add it to the queue, when it gets to the front the
* ap_start function is called.
*/
if (rc != TRAN_ACCEPT) {
/* this should never, ever happen */
return (FALSE);
}
return (FALSE);
return (TRUE);
}
/*
* Check if this drive has the "revert to defaults" bug
* PSARC 2001/500 and 2001/xxx - check for the properties
* ata-revert-to-defaults and atarvrt-<diskmodel> before
* examining the blacklist.
* <diskmodel> is made from the model number reported by Identify Drive
* with uppercase letters converted to lowercase and all characters
* except letters, digits, ".", "_", and "-" deleted.
* Return value:
* TRUE: enable revert to defaults
* FALSE: disable revert to defaults
*
* NOTE: revert to power on defaults that includes reverting to MDMA
* mode is allowed by ATA-6 & ATA-7 specs.
* Therefore drives exhibiting this behaviour are not violating the spec.
* Furthermore, the spec explicitly says that after the soft reset
* host should check the current setting of the device features.
* Correctly working BIOS would therefore reprogram either the drive
* Devices with ATA_BL_NORVRT flag will be removed from
* the ata_blacklist.
* The default behaviour will be - no revert to power-on defaults
* for all devices. The property is retained in case the user
* explicitly requests revert-to-defaults before reboot.
*/
/* room for prefix + model number + terminating NUL character */
static int
{
int i, j;
int propval;
/* put prefix into the buffer */
/* append the model number, leaving out invalid characters */
if (c >= 'A' && c <= 'Z') /* uppercase -> lower */
c = c - 'A' + 'a';
if (c >= 'a' && c <= 'z' || c >= '0' && c <= '9' ||
c == '.' || c == '_' || c == '-')
prop_buf[j++] = c;
if (c == '\0')
break;
}
/* make sure there's a terminating NUL character */
if (j >= PROP_LEN_MAX)
j = PROP_LEN_MAX;
prop_buf[j] = '\0';
/* look for a disk-specific "revert" property" */
if (propval == 0)
return (FALSE);
else if (propval != -1)
return (TRUE);
/* look for a global "revert" property" */
0, ATA_REVERT_PROP_GLOBAL, -1);
if (propval == 0)
return (FALSE);
else if (propval != -1)
return (TRUE);
return (FALSE);
}
void
{
int i;
if (ata_cntrl_DMA_sel_msg) {
ATAPRT((
"?\tATA DMA off: %s\n", ata_cntrl_DMA_sel_msg));
} else if (ata_dev_DMA_sel_msg) {
}
ATAPRT(("?\tPIO mode %d selected\n",
} else {
/* Using DMA */
/*
* Rely on the fact that either dwdma or udma is
* selected, not both.
*/
ATAPRT(("?\tMultiwordDMA mode %d selected\n",
ATAC_MDMA_2_SEL ? 2 :
ATAC_MDMA_1_SEL ? 1 : 0));
} else {
for (i = 0; i <= 6; i++) {
(1 << (i + 8))) {
ATAPRT((
"?\tUltraDMA mode %d selected\n",
i));
break;
}
}
}
}
}
/*
* Controller-specific operation pointers.
* Should be extended as needed - init only for now
*/
struct ata_ctl_spec_ops {
};
struct ata_ctl_spec {
};
/* Sil3XXX-specific functions (init only for now) */
&sil3xxx_init_controller /* Sil3XXX cntrl initialization */
};
{0, 0, NULL} /* List must end with cs_ops set to NULL */
};
/*
* Do controller specific initialization if necessary.
* Pick-up controller specific functions.
*/
int
{
DDI_PROP_DONTPASS, "vendor-id", 0);
DDI_PROP_DONTPASS, "device-id", 0);
/* Locate controller specific ops, if they exist */
break;
ctlsp++;
}
/* Initialize controller */
"pci%4x,%4x cntrl specific "
"initialization failed",
return (FALSE);
}
}
}
return (TRUE);
}
/*
* this routine works like ddi_prop_get_int, except that it works on
* a string property that contains ascii representations
* of an integer.
* If the property is not found, the default value is returned.
*/
static int
{
int proprc;
if (proprc == DDI_PROP_SUCCESS) {
} else {
/*
* see if property is encoded as an int instead of string.
*/
}
return (rc);
}
/*
* Initialize the power management components
*/
static void
{
char *pmc[] = {
NULL,
"0=Sleep (PCI D3 State)",
"3=PowerOn (PCI D0 State)",
};
int instance;
ata_ctlp->ac_pm_support = 0;
/* check PCI capabilities */
if (!ata_is_pci(dip))
return;
#ifdef ATA_USE_AUTOPM
return;
}
#endif
ATA_BUSY_COMPONENT(dip, 0);
}
ATA_IDLE_COMPONENT(dip, 0);
}
/*
* resume the hard drive
*/
static void
{
int drive_type;
ADBG_TRACE(("ata_resume_drive entered\n"));
&id);
if (drive_type == ATA_DEV_NONE)
return;
/* Reset Ultra DMA mode */
return;
} else {
(void) atapi_init_drive(ata_drvp);
if (ata_drvp->ad_dma_mode != 0) {
if (!ata_check_dma_mode(ata_drvp))
ata_drvp->ad_dma_mode) {
} else {
}
}
}
}
/*
* resume routine, it will be run when get the command
* DDI_RESUME at attach(9E) from system power management
*/
static int
{
int instance;
if (!ata_ctlp->ac_pm_support)
return (DDI_FAILURE);
return (DDI_SUCCESS);
ATA_BUSY_COMPONENT(dip, 0);
return (DDI_FAILURE);
ATA_IDLE_COMPONENT(dip, 0);
/* enable interrupts from the device */
return (DDI_SUCCESS);
}
/*
* suspend routine, it will be run when get the command
* DDI_SUSPEND at detach(9E) from system power management
*/
static int
{
int instance;
if (!ata_ctlp->ac_pm_support)
return (DDI_FAILURE);
return (DDI_SUCCESS);
/* disable interrupts and turn the software reset bit on */
(void) ata_reset_bus(ata_ctlp);
return (DDI_SUCCESS);
}
int ata_save_pci_config = 0;
/*
* ata specific power management entry point, it was
* used to change the power management component
*/
static int
{
int instance;
ADBG_TRACE(("ata_power entered, component = %d, level = %d\n",
return (DDI_FAILURE);
if (!ata_ctlp->ac_pm_support)
return (DDI_FAILURE);
return (DDI_SUCCESS);
switch (level) {
case PM_LEVEL_D0:
if (ata_save_pci_config)
(void) pci_restore_config_regs(dip);
break;
case PM_LEVEL_D3:
if (ata_save_pci_config)
(void) pci_save_config_regs(dip);
break;
default:
return (DDI_FAILURE);
}
}
/*
* sent commands to ata controller to change the power level
*/
static int
{
int instance;
/*
* Issue command on each disk device on the bus.
*/
continue;
if (ata_drvp->ad_dma_cap == 0 &&
} else if (aidp->ai_dworddma &
}
}
&id) != ATA_DEV_DISK)
continue;
"put drive %d in to power mode %u",
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
(void) ata_software_reset(ata_ctlp);
continue;
else
lastlun = 0;
if (!ata_enable_atapi_luns)
lastlun = 0;
}
}
return (DDI_SUCCESS);
}
/*
* return 1 when ata controller is a pci device,
* otherwise return 0
*/
static int
{
int rc;
char *bufp;
int ispci;
if (rc != DDI_PROP_SUCCESS) {
ADBG_ERROR(("ata_is_pci !device_type\n"));
return (0);
}
return (ispci);
}
/*
* Disable DMA for this drive
*/
static void
{
int i;
return;
return;
/* Print the message */
buf[0] = '\0';
buf[i] = '\0';
}
"?DMA disabled on %s target=%d, lun=%d due to DMA errors,",
}
/*
* Check and select DMA mode
*
* TRUE is returned when set feature is called successfully,
* otherwise return FALSE
*/
int
{
/* Return directly if DMA is not supported */
return (rval);
/* Return if DMA mode is already selected */
return (rval);
/* First check Ultra DMA mode if no DMA is selected */
break;
}
/* Then check multi-word DMA mode */
break;
}
} else {
return (rval);
}
return (rval);
}
/*
* Reset Ultra DMA mode / MWDMA mode
*/
void
{
int mode;
switch (ata_drvp->ad_dma_cap) {
case ATA_DMA_ULTRAMODE:
break;
}
break;
case ATA_DMA_MWORDMODE:
ATAC_MDMA_2_SEL ? 2 :
ATAC_MDMA_1_SEL ? 1 : 0);
break;
default:
return;
}
}
/*
* Check DMA mode is the same with saved info
* return value: 0 - not same
* 1 - same
*/
static int
{
switch (ata_drvp->ad_dma_cap) {
case ATA_DMA_ULTRAMODE:
break;
else
return (0);
case ATA_DMA_MWORDMODE:
break;
else
return (0);
default:
return (0);
}
return (1);
}