ata_disk.c revision 0f2c99a46e005b1add7df43157ee8516e585157a
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "ata_common.h"
#include "ata_disk.h"
/*
*/
/*
* DADA entry points
*/
/*
* DADA packet callbacks
*/
int do_callback);
/*
* Local Function prototypes
*/
int flag);
/*
* Local static data
*/
int ata_disk_do_standby_timer = TRUE;
/* timeout value for device update firmware */
int ata_disk_updatefw_time = 60;
/*
* ata_write_cache == 1 force write cache on.
* ata_write_cache == 0 do not modify write cache. firmware defaults kept.
* ata_write_cache == -1 force write cache off.
*/
int ata_write_cache = 1;
static struct ctl_objops ata_disk_objops = {
0, 0
};
/*
*
* initialize the ata_disk sub-system
*
*/
/*ARGSUSED*/
int
{
ADBG_TRACE(("ata_disk_init entered\n"));
return (TRUE);
}
/*
*
* destroy the ata_disk sub-system
*
*/
/*ARGSUSED*/
void
{
ADBG_TRACE(("ata_disk_destroy entered\n"));
}
/*
* Test whether the disk can support Logical Block Addressing
*/
int
{
#ifdef __old_version__
/*
* determine if the drive supports LBA mode
*/
return (TRUE);
#else
/*
* Determine if the drive supports LBA mode
* LBA 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 should be 0xffff or 0x0000
* (version not reported).
*/
/* ATA-3 or better */
return (TRUE);
/* ATA-2 LBA capability bit set */
return (TRUE);
} else {
return (FALSE);
}
#endif
}
/*
* ATA-6 drives do not provide geometry information, so words
* ai_heads, ai_sectors and ai_fixcyls may not be valid
*/
static void
{
/* check cylinders, heads, and sectors for valid values */
aidp->ai_fixcyls != 0)
return; /* assume valid geometry - do nothing */
/*
* Pre-set standard geometry values - they are not necessarily
* optimal for a given capacity
*/
/*
* The fixcyls value will get fixed up later in
* ata_fix_large_disk_geometry.
*/
}
/*
*
* initialize the soft-structure for an ATA (non-PACKET) drive and
* then configure the drive with the correct modes and options.
*
*/
int
{
struct scsi_device *devp;
int len;
int val;
int mode;
short *chs;
char buf[80];
ADBG_TRACE(("ata_disk_init_drive entered\n"));
/* ATA disks don't support LUNs */
return (FALSE);
/*
* set up drive structure
* ATA-6 drives do not provide geometry information, so words
* ai_heads, ai_sectors and ai_fixcyls may not be valid - they
* will be fixed later
*/
/* Get capacity and check for 48-bit mode */
}
/* straighten out the geometry */
/*
* if the number of sectors and heads in bios matches the
* physical geometry, then so should the number of cylinders
* this is to prevent the 1023 limit in the older bios's
* causing loss of space.
*/
/* Set chs[0] to zero-based number of cylinders. */
/*
* bios and the drive does not support LBA. We go ahead
* and advertise the bios geometry but use the physical
* geometry for sector translation.
*/
"different from physical, and no LBA support.",
}
/*
* chs[0,1] are zero-based; make them one-based.
*/
} else {
/*
* Property not present; this means that boot.bin has
* determined that the drive supports Int13 LBA. Note
* this, but just return a geometry with a large
* cylinder count; this will be the signal for dadk to
* fail DKIOCG_VIRTGEOM.
* ad_drvr* are already set; just recalculate ad_drvrcyl
* from capacity.
*/
if (ata_drvp->ad_capacity != 0) {
} else {
/*
* Something's wrong; return something sure to
* fail the "cyls < 1024" test. This will
* never make it out of the DKIOCG_VIRTGEOM
* call, so its total bogosity won't matter.
*/
}
}
/* fix geometry for disks > 31GB, if needed */
/*
* set up the scsi_device and ctl_obj structures
*/
/*
* DADA ops vectors and cookie
*/
/*
* this is filled in with gtgtp by ata_disk_bus_ctl(INITCHILD)
*/
/*
* Get highest block factor supported by the drive.
* adjust their blocking factor to 1.
*/
/*
* If a block factor property exists, use the smaller of the
* property value and the highest value the drive can support.
*/
if (ata_drvp->ad_block_factor == 0)
return (FALSE);
return (TRUE);
}
/*
* Test if a disk supports 48-bit (extended mode) addressing and
* get disk capacity.
* Return value:
* AD_EXT48 if 48-bit mode is available, 0 otherwise,
* capacity in sectors.
* There are several indicators for 48-bit addressing. If any of
* them is missing, assume 28-bit (non-extended) addressing.
*/
static int
{
/*
* First compute capacity in 28-bit mode, using 28-bit capacity
* words in IDENTIFY DEVICE response words
*/
/* No 48-bit mode before ATA 6 */
return (0);
/* Check that 48 bit addressing is supported & enabled */
/* words 83 and 86 */
return (0);
return (0);
/*
* Drive supports ATA-6. Since ATA-6 drives may not provide
* geometry info, pre-set standard geometry values
*/
/* Compute 48-bit capacity */
/*
* If capacity is smaller then the maximum capacity addressable
* in 28-bit mode, just use 28-bit capacity value.
*/
if (cap48 <= MAX_28BIT_CAPACITY)
return (0);
/*
* Capacity is too big for 28-bits addressing. But, to make
* sure that the drive implements ATA-6 correctly, the
* final check: cap28 should be MAX for 28-bit addressing.
* If it's not, we shouldn't use 48-bit mode, so return
* the capacity reported in 28-bit capacity words.
*/
if (cap28 != MAX_28BIT_CAPACITY)
return (0); /* not max, use 28-bit value */
/*
* All is well so return 48-bit capacity indicator
*/
ADBG_INIT(("ATA: using 48-bit mode for capacity %llx blocks\n",
(unsigned long long)cap48));
return (AD_EXT48);
}
/*
* With the advent of disks that hold more than 31 GB, we run into a
* limitation in the sizes of the fields that describe the geometry.
* The cylinders, heads, and sectors-per-track are each described by a
* 16-bit number -- both in the structure returned from IDENTIFY
* DEVICE and in the structure returned from the DIOCTL_GETGEOM or
* DIOCTL_GETPHYGEOM ioctl.
*
* The typical disk has 32 heads per cylinder and 63 sectors per
* track. A 16 bit field can contain up to 65535. So the largest
* disk that can be described in these fields is 65535 * 32 * 63 * 512
* when stored in a narrow field, so a 40GB disk appears to have only
* 8 GB!
*
* The solution (for the time being at least) is to lie about the
* geometry. If the number of cylinders is too large to fit in 16
* bits, we will halve the cylinders and double the heads, repeating
* until we can fit the geometry into 3 shorts.
* FUTURE ENHANCEMENT: If this ever isn't enough, we could
*/
static void
{
/* no hope for large disks if LBA not supported */
return;
/*
* Fix up the geometry to be returned by DIOCTL_GETGEOM.
* If number of cylinders > USHRT_MAX, double heads and
* halve cylinders until everything fits.
*/
int tempheads;
/* is there room in 16 bits to double the heads? */
/*
* No room to double the heads.
* I give up, there's no way to represent this.
* Limit disk size.
*/
"Disk is too large: "
"Model %s, Serial# %s "
"Approximating...\n",
break;
}
/* OK, so double the heads and halve the cylinders */
}
}
/*
* Calculate capacity using 28-bit capacity words from IDENTIFY DEVICE
* return words
*/
{
/*
* Asked x3t13 for advice; this implements Hale Landis'
* response, minus the "use ATA_INIT_DEVPARMS".
* See "capacity.notes".
*/
}
/*
* If we're not LBA, then first try to validate "current" values.
*/
return ((uint64_t)curcap_w57_58);
}
/*
* At this point, Hale recommends ATA_INIT_DEVPARMS.
* I don't want to do that, so simply use 1/3/6 as
* a final fallback, and continue to assume the BIOS
* has done whatever INIT_DEVPARMS are necessary.
*/
}
/*
* Calculate capacity using 48-bits capacity words from IDENTIFY DEVICE
* return words
*/
{
int i;
for (i = 3; i >= 0; --i) {
cap48 <<= 16;
}
return (cap48);
}
/*
*
* current translation geometry. Necessary during attach and after
* Software Resets.
*
*/
int
{
/*
* program geometry info back to the drive
*/
return (FALSE);
}
/*
* Determine the blocking factor
*/
/*
* Program the block factor into the drive. If this
* fails, then go back to using a block size of 1.
*/
}
} else {
}
ADBG_INIT(("set block factor for drive %d to %d\n",
return (TRUE);
}
/*
* Take the timeout value specified in the "standby" property
* and convert from seconds to the magic parm expected by the
* the drive. Then issue the IDLE command to set the drive's
* internal standby timer.
*/
static void
{
/*
* take the timeout value, specificed in seconds, and
* encode it into the proper command parm
*/
/*
* don't change it if no property specified or if
* the specified value is out of range
*/
return;
/* 1 to 1200 seconds (20 minutes) == N * 5 seconds */
/* 20 to 21 minutes == 21 minutes */
parm = 252;
/* 21 minutes to 21 minutes 15 seconds == 21:15 */
parm = 255;
/* 21:15 to 330 minutes == N * 30 minutes */
/* > 330 minutes == 8 to 12 hours */
else
parm = 253;
}
/*
*
* destroy an ata disk drive
*
*/
void
{
ADBG_TRACE(("ata_disk_uninit_drive entered\n"));
}
/*
*
* DADA compliant bus_ctl entry point
*
*/
/*ARGSUSED*/
int
dev_info_t *d,
dev_info_t *r,
void *a,
void *v)
{
ADBG_TRACE(("ata_disk_bus_ctl entered\n"));
switch (o) {
case DDI_CTLOPS_REPORTDEV:
{
int targ;
"target", 0);
ddi_driver_name(r), ddi_get_instance(r),
return (DDI_SUCCESS);
}
case DDI_CTLOPS_INITCHILD:
{
struct scsi_device *devp;
char name[MAXNAMELEN];
/*
* save time by picking up ptr to drive struct left
* by ata_bus_ctl - isn't that convenient.
*/
/* set up pointers to child dip */
/*
* If sd_dev is set, it means that the target has already
* being initialized. The cdip is a duplicate node from
* reexpansion of driver.conf. Fail INITCHILD here.
*/
return (DDI_FAILURE);
}
/*
* Create the "ata" property for use by the target driver
*/
return (DDI_FAILURE);
}
/* gt_tgt_private points to ata_tgt_t */
/* gtgtp is the opaque arg to all my entry points */
/* create device name */
return (DDI_SUCCESS);
}
case DDI_CTLOPS_UNINITCHILD:
{
struct scsi_device *devp;
return (DDI_SUCCESS);
}
default:
return (DDI_FAILURE);
}
}
/*
*
* DADA abort entry point - not currently used by dadk
*
*/
/* ARGSUSED */
static int
{
ADBG_TRACE(("ata_disk_abort entered\n"));
/* XXX - Note that this interface is currently not used by dadk */
/*
* GHD abort functions take a pointer to a scsi_address
* and so they're unusable here. The ata driver used to
* return DDI_SUCCESS here without doing anything. Its
* seems that DDI_FAILURE is more appropriate.
*/
return (DDI_FAILURE);
}
/*
*
* DADA reset entry point - not currently used by dadk
* (except in debug versions of driver)
*
*/
/* ARGSUSED */
static int
{
int rc;
ADBG_TRACE(("ata_disk_reset entered\n"));
/* XXX - Note that this interface is currently not used by dadk */
if (level == RESET_TARGET) {
NULL);
NULL);
}
}
/*
*
* DADA ioctl entry point
*
*/
/* ARGSUSED */
static int
{
int wce;
#ifdef _MULTI_DATAMODEL
#endif
char buf[80];
int i;
switch (cmd) {
case DIOCTL_GETGEOM:
case DIOCTL_GETPHYGEOM:
return (EFAULT);
return (0);
case DCMD_UPDATE_GEOM:
/* ??? fix this to issue IDENTIFY DEVICE ??? */
/* can change its geometry. On the other hand, ATAPI devices like the */
return (0);
/* copy the model number into the caller's buffer */
case DIOCTL_GETMODEL:
return (rc);
/* copy the serial number into the caller's buffer */
case DIOCTL_GETSERIAL:
flag);
return (rc);
case DIOCTL_GETWCE:
/*
* WCE is only supported in ATAPI-4 or higher, for
* lower rev devices, must assume write cache is
* enabled.
* NOTE: Since there is currently no Solaris mechanism
* to change the state of the Write Cache Enable feature,
* this code just checks the value of the WCE bit
* obtained at device init time. If a mechanism
* is added to the driver to change WCE, this code
* must be updated appropriately.
*/
return (EFAULT);
return (0);
case DCMD_GET_STATE:
gtgtp);
break;
case DCMD_LOCK:
case DKIOCLOCK:
gtgtp);
break;
case DCMD_UNLOCK:
case DKIOCUNLOCK:
gtgtp);
break;
case DCMD_START_MOTOR:
case CDROMSTART:
break;
case DCMD_STOP_MOTOR:
case CDROMSTOP:
gtgtp);
break;
case DKIOCEJECT:
case CDROMEJECT:
gtgtp);
break;
case DKIOC_UPDATEFW:
/*
* Call DOWNLOAD MICROCODE command to update device
* firmware.
*
* return value:
* normal 0 Download microcode success
* error EFAULT Bad address
* ENXIO No such device or address
* EINVAL Invalid argument
* ENOMEM Not enough core
* ENOTSUP Operation not supported
* EIO I/O error
* EPERM Not owner
*/
/*
* The following code deals with handling 32-bit request
* in 64-bit kernel.
*/
#ifdef _MULTI_DATAMODEL
sizeof (dk_updatefw_32_t), flag))
return (EFAULT);
} else {
sizeof (dk_updatefw_t), flag))
return (EFAULT);
}
#else
sizeof (dk_updatefw_t), flag))
return (EFAULT);
#endif
/*
* According to ATA8-ACS spec, the new microcode should
* become effective immediately after the transfer of the
* last data segment has completed, so here we will call
* IDENTIFY DEVICE command immediately to update
* ata_id content when success.
*/
if (rc == 0) {
return (ENXIO);
} else {
/*
* Check whether the content of the IDENTIFY
* DEVICE data is incomplete, if yes, it's
* because the device supports the Power-up
* in Standby feature set, and we will first
* check word 2, and then decide whether need
* to call set feature to spin-up the device,
* and then call IDENTIFY DEVICE command again.
*/
/* Spin-up the device */
(void) ata_queue_cmd(
NULL,
gtgtp);
}
/* Try to update ata_id again */
rc2 = ata_queue_cmd(
NULL,
gtgtp);
return (ENXIO);
} else {
return (ENXIO);
}
}
/*
* Dump the drive information.
*/
ATAPRT(("?\tUpdate firmware of %s device at "
"targ %d, lun %d lastlun 0x%x\n",
aidp->ai_lastlun));
buf[i] == ' '; i--)
buf[i] = '\0';
buf[i] == ' '; i--)
buf[i] = '\0';
}
}
return (rc);
case DKIOC_GETDISKID:
/* Get the model number */
/* Get the firmware revision */
/* Get the serial number */
sizeof (dk_disk_id_t), flag))
return (EFAULT);
else
return (0);
default:
return (ENOTTY);
}
if (rc)
return (0);
return (ENXIO);
}
#ifdef ___not___used___
/*
* Issue an ATA command to the drive using the packet already
* allocated by the target driver
*/
int
void *arg,
{
int rc;
/*
* 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 (ENXIO);
}
return (ENXIO);
return (0);
}
#endif
/*
*
* DADA pktalloc entry point
*
*/
/* ARGSUSED */
static cmpkt_t *
{
ADBG_TRACE(("ata_disk_pktalloc entered\n"));
/*
* Allocate and init the GHD gcmd_t structure and the
* DADA cmpkt and the ata_pkt
*/
}
/*
* At this point the structures are linked like this:
*
* (struct cmpkt) <--> (struct gcmd) <--> (struct ata_pkt)
*/
/* callback functions */
/* other ata_pkt setup */
/* cmpkt setup */
return (pktp);
}
/*
*
* DADA pktfree entry point
*
*/
/* ARGSUSED */
static void
{
ADBG_TRACE(("ata_disk_pktfree entered\n"));
/* check not free already */
}
/*
*
* DADA memsetup entry point
*
*/
/* ARGSUSED */
static cmpkt_t *
{
int flags;
ADBG_TRACE(("ata_disk_memsetup entered\n"));
return (pktp);
}
goto skip_dma_setup;
if (ata_dma_disabled)
goto skip_dma_setup;
/*
* The PCI-IDE DMA engine is brain-damaged and can't
* DMA non-aligned buffers.
*/
goto skip_dma_setup;
}
/*
* It also insists that the byte count must be even.
*/
goto skip_dma_setup;
/* check direction for data transfer */
} else {
}
/*
* Bind the DMA handle to the buf
*/
return (pktp);
}
return (pktp);
}
/*
*
* DADA memfree entry point
*
*/
/*
* 1157317 sez that drivers shouldn't call bp_mapout(), as either
* biodone() or biowait() will end up doing it, but after they
* call bp->b_iodone(), which is a necessary sequence for
* Online Disk Suite. However, the DDI group wants to rethink
* bp_mapin()/bp_mapout() and how they should behave in the
* presence of layered drivers, etc. For the moment, fix
* the OLDS problem by removing the bp_mapout() call.
*/
#define BUG_1157317
/* ARGSUSED */
static void
{
ADBG_TRACE(("ata_disk_memfree entered\n"));
if (gcmdp->cmd_dma_handle)
#if !defined(BUG_1157317)
else
#endif
}
/*
*
* DADA iosetup entry point
*
*/
static cmpkt_t *
{
ADBG_TRACE(("ata_disk_iosetup entered\n"));
/*
* Check for DCMD_FLUSH_CACHE (which does no I/O) and
* just do basic setup.
*/
ata_pktp->ap_startsec = 0;
return (pktp);
}
/* check for error retry */
/*
* this is a temporary work-around for dadk calling
* iosetup for retry. The correct
* solution is changing dadk to not to call iosetup
* for a retry.
* We do not apply the work-around for pio mode since
* that does not involve moving dma windows and reducing the
* sector count would work for pio mode on a retry
* for now.
*/
return (NULL);
}
sec_count = 1;
/*
* Since we are retrying the last read or write operation,
* restore the old values of the ap_v_addr and ap_resid.
* This assumes CTL_IOSETUP is called again on retry; if not,
* this needs to be done in CTL_TRANSPORT.
*/
}
} else {
/*
* Limit request to ac_max_transfer sectors.
* The value is specified by the user in the
* max_transfer property. It must be in the range 1 to 256.
* When max_transfer is 0x100 it is bigger than 8 bits.
* The spec says 0 represents 256 so it should be OK.
*/
/*
* Save the current values of ap_v_addr and ap_resid
* in case a retry operation happens. During a retry
* operation we need to restore these values.
*/
}
/* reset flags */
#ifdef DADKIO_RWCMD_READ
#else
#endif
/*
*/
(byte_count == 0)) {
ADBG_ERROR(("ata_disk_iosetup: byte count zero\n"));
return (NULL);
}
}
/*
* In the non-48-bit mode addressing (CHS and LBA28) the sector
* count is a 8-bit value and the sector count 0 represents 256
* sectors.
* In the extended addressing (LBA48) the sector count is a 16-bit
* value, so max_transfer 0x100 cannot be truncated to 8-bits
* because this would represent a zero sector count.
*/
}
#ifdef DADKIO_RWCMD_READ
if (pktp->cp_passthru) {
case DADKIO_RWCMD_READ:
} else {
}
break;
case DADKIO_RWCMD_WRITE:
} else {
}
break;
}
/*
* should set bytes_per_block to one sector
* XXX- why wasn't this in the old driver??
*/
} else
#endif
{
/* setup the task file registers */
case DCMD_READ:
} else {
}
break;
case DCMD_WRITE:
} else {
}
break;
default:
ADBG_WARN(("ata_disk_iosetup: unknown command 0x%x\n",
break;
}
}
/* If 48-bit mode is used, convert command to 48-bit mode cmd */
case ATC_RDSEC:
break;
case ATC_WRSEC:
break;
case ATC_RDMULT:
break;
case ATC_WRMULT:
break;
case ATC_READ_DMA:
break;
case ATC_WRITE_DMA:
break;
}
}
return (pktp);
}
/*
*
* DADA transport entry point
*
*/
static int
{
int rc;
ADBG_TRACE(("ata_disk_transport entered\n"));
/* check for polling pkt */
}
/* call ghd transport routine */
/* see if pkt was not accepted */
return (CTL_SEND_BUSY);
if (rc == TRAN_ACCEPT)
return (CTL_SEND_SUCCESS);
return (CTL_SEND_FAILURE);
}
/*
*
* task file registers.
*
*/
static void
{
lba >>= 8;
lba >>= 8;
lba >>= 8;
/*
* must also include drive selector.
*/
}
/*
* In 48-bit extended mode, the sector count is 16 bits wide, and the
* LBA is 48 bits wide, as follows:
* register most recent previous
* name value value
* -------- ---------- ---------
* sector cnt count(7:0) count(15:8)
* sector num lba(7:0) lba(31:24)
* cyl low lba(15:8) lba(39:32)
* cyl hi lba(23:16) lba(47:40)
* ^ ^
* | |
* | +-- drive number
* |
* +-- indicates LBA
* The other two 1 bits are historical and are not used in 48bit
* extended mode.
*/
/*
* WARNING:
* dada framework passes starting sector as daddr_t type, thus
* limiting reachable disk space in 32-bit x86 architecture to 1 terabyte.
* Therefore high 16 bits of the 48-bits address can be and
* are currently ignored.
*/
static void
{
/* high-order 8 bits of lbalow never get used */
/* Send the high-order half first */
lbahi >>= 8;
lbahi >>= 8;
/* Send the low-order half */
lbalow >>= 8;
lbalow >>= 8;
}
static void
{
/* automatically truncate to char */
/* lcyl gets truncated to 8 bits */
}
/*
*
* packet start callback routines
*
*/
/* ARGSUSED */
static int
{
ADBG_TRACE(("ata_disk_start_common entered\n"));
ADBG_TRANSPORT(("ata_disk_start:\tpkt = 0x%p, pkt flags = 0x%x\n",
ADBG_TRANSPORT(("\tcommand=0x%x, sect=0x%lx\n",
ADBG_TRANSPORT(("\tcount=0x%x, drvhd = 0x%x\n",
/*
* If AC_BSY_WAIT is set, wait for controller to not be busy,
* before issuing a command. If AC_BSY_WAIT is not set,
* skip the wait. This is important for laptops that do
* drop after a resume.
*
* implement the overlapped/queued command protocols. Currently,
* conditional.
*/
0, ATS_BSY, 5000000)) {
ADBG_ERROR(("ata_disk_start: BUSY\n"));
return (FALSE);
}
}
/*
* make certain the drive selected
*/
ADBG_ERROR(("ata_disk_start: select failed\n"));
return (FALSE);
}
/* the sector count is 16 bits wide */
/* put subcommand for DOWNLOAD MICROCODE */
} else {
/*
* We use different methods for loading the task file
* registers, depending on whether the disk
* uses LBA or CHS addressing and whether 48-bit
* extended addressing is to be used.
*/
else
}
/*
* Always make certain interrupts are enabled. It's been reported
* (but not confirmed) that some notebook computers don't
* clear the interrupt disable bit after being resumed. The
* easiest way to fix this is to always clear the disable bit
* before every command.
*/
return (TRUE);
}
/*
*
* Start a non-data ATA command (not DMA and not PIO):
*
*/
static int
{
int rc;
if (!rc)
return (ATA_FSM_RC_BUSY);
/*
* This next one sets the controller in motion
*/
/* wait for the busy bit to settle */
return (ATA_FSM_RC_OKAY);
}
static int
{
int rc;
if (!rc)
return (ATA_FSM_RC_BUSY);
/*
* Physical Region Descriptor Table
*/
/*
* reset the PCIIDE Controller's interrupt and error status bits
*/
(void) ata_pciide_status_clear(ata_ctlp);
/*
* This next one sets the drive in motion
*/
/* wait for the drive's busy bit to settle */
return (ATA_FSM_RC_OKAY);
}
static int
{
int rc;
if (!rc)
return (ATA_FSM_RC_BUSY);
/*
* Physical Region Descriptor Table
*/
/*
* reset the PCIIDE Controller's interrupt and error status bits
*/
(void) ata_pciide_status_clear(ata_ctlp);
/*
* This next one sets the drive in motion
*/
/* wait for the drive's busy bit to settle */
return (ATA_FSM_RC_OKAY);
}
/*
*
* Start a PIO data-in ATA command:
*
*/
static int
{
int rc;
if (!rc)
return (ATA_FSM_RC_BUSY);
/*
* This next one sets the controller in motion
*/
/* wait for the busy bit to settle */
return (ATA_FSM_RC_OKAY);
}
/*
*
* Start a PIO data-out ATA command:
*
*/
static int
{
int rc;
ata_pktp->ap_wrt_count = 0;
if (!rc)
return (ATA_FSM_RC_BUSY);
/*
* This next one sets the controller in motion
*/
/* wait for the busy bit to settle */
/*
* Wait for the drive to assert DRQ to send the first chunk
* of data. Have to busy wait because there's no interrupt for
* the first chunk. This sucks (a lot of cycles) if the
* drive responds too slowly or if the wait loop granularity
* is too large. It's really bad if the drive is defective and
* the loop times out.
*/
4000000)) {
ADBG_WARN(("ata_disk_start_pio_out: no DRQ\n"));
return (ATA_FSM_RC_INTR);
}
/*
* Tell the upper layer to fake a hardware interrupt which
* actually causes the first segment to be written to the drive.
*/
return (ATA_FSM_RC_INTR);
}
/*
*
* packet complete callback routine
*
*/
static void
int do_callback)
{
ADBG_TRACE(("ata_disk_complete entered\n"));
/* update resid */
else
else /* any unknown error */
} else {
}
/* callback */
if (do_callback)
}
/*
*
* Interrupt callbacks
*
*/
/*
*
* ATA command, no data
*
*/
/* ARGSUSED */
static int
{
ADBG_TRACE(("ata_disk_intr entered\n"));
/*
* check for errors
*/
}
}
/* tell the upper layer this request is complete */
return (ATA_FSM_RC_FINI);
}
/*
*
* ATA command, PIO data in
*
*/
/* ARGSUSED */
static int
{
ADBG_TRACE(("ata_disk_pio_in entered\n"));
/*
* first make certain DRQ is asserted (and no errors)
*/
4000000);
ADBG_WARN(("ata_disk_pio_in: BUSY\n"));
return (ATA_FSM_RC_BUSY);
}
/*
* record any errors
*/
ADBG_WARN(("ata_disk_pio_in: status 0x%x error 0x%x\n",
}
/*
* read the next chunk of data (if any)
*/
}
/*
* If that was the last chunk, wait for the device to clear DRQ
*/
/* tell the upper layer this request is complete */
return (ATA_FSM_RC_FINI);
}
ADBG_WARN(("ata_disk_pio_in: DRQ stuck\n"));
}
/*
* check for errors
*/
return (ATA_FSM_RC_FINI);
}
/*
* If the read command isn't done yet,
* wait for the next interrupt.
*/
ADBG_TRACE(("ata_disk_pio_in: partial\n"));
return (ATA_FSM_RC_OKAY);
}
/*
*
* ATA command, PIO data out
*
*/
/* ARGSUSED */
static int
{
/*
* clear the IRQ
*/
ADBG_TRACE(("ata_disk_intr_pio_out entered\n"));
/*
* check for errors
*/
ADBG_WARN(("ata_disk_intr_pio_out: status 0x%x error 0x%x\n",
/* tell the upper layer this request is complete */
return (ATA_FSM_RC_FINI);
}
/*
* last write was okay, bump the ptr and
* decr the resid count
*/
/*
* check for final interrupt on write command
*/
/* tell the upper layer this request is complete */
return (ATA_FSM_RC_FINI);
}
/*
* Perform the next data transfer
*
* First make certain DRQ is asserted and no error status.
* (I'm not certain but I think some drives might deassert BSY
* before asserting DRQ. This extra ata_wait3() will
* compensate for such drives).
*
*/
/* this should never happen */
ADBG_WARN(("ata_disk_intr_pio_out: BUSY\n"));
return (ATA_FSM_RC_BUSY);
}
/*
* bailout if any errors
*/
ADBG_WARN(("ata_disk_pio_out: status 0x%x error 0x%x\n",
return (ATA_FSM_RC_FINI);
}
/*
* write the next chunk of data
*/
ADBG_TRACE(("ata_disk_intr_pio_out: write xfer\n"));
/*
* Wait for the next interrupt before checking the transfer
* status and adjusting the transfer count.
*
*/
return (ATA_FSM_RC_OKAY);
}
/*
*
*
*/
static int
{
ADBG_TRACE(("ata_disk_intr_dma entered\n"));
/*
* halt the DMA engine
*/
/*
* wait for the device to clear DRQ
*/
ADBG_WARN(("ata_disk_intr_dma: DRQ stuck\n"));
return (ATA_FSM_RC_BUSY);
}
/*
* get the status and clear the IRQ, and check for DMA error
*/
/*
* check for drive errors
*/
ADBG_WARN(("ata_disk_intr_dma: status 0x%x error 0x%x\n",
}
/*
* If there was a drive or DMA error, compute a resid count
*/
/*
* grab the last sector address from the drive regs
* and use that to compute the resid
*/
} else {
}
/* tell the upper layer this request is complete */
return (ATA_FSM_RC_FINI);
}
/*
*
* Low level PIO routine that transfers data from the drive
*
*/
static void
{
int count;
ADBG_TRANSPORT(("ata_disk_pio_xfer_data_in: 0x%x bytes, addr = 0x%p\n",
/*
* read count bytes
*/
/* wait for the busy bit to settle */
/*
* this read command completed okay, bump the ptr and
* decr the resid count now.
*/
}
/*
*
* Low level PIO routine that transfers data to the drive
*
*/
static void
{
int count;
ADBG_TRANSPORT(("ata_disk_pio_xfer_data_out: 0x%x bytes, addr = 0x%p\n",
/*
* read or write count bytes
*/
/* wait for the busy bit to settle */
/*
* save the count here so I can correctly adjust
* the ap_v_addr and ap_resid values at the next
* interrupt.
*/
}
/*
*
* ATA Initialize Device Parameters (aka Set Params) command
*
* mode by the BIOS, this function will reset it to its "native"
* CHS geometry. This ensures that we don't run into any sort of
* 1024 cylinder (or 65535 cylinder) limitation that may have been
* created by a BIOS (or users) that chooses a bogus translated geometry.
*/
static int
{
int rc;
0, /* feature n/a */
0, /* sector n/a */
0, /* cyl_low n/a */
0); /* cyl_hi n/a */
if (rc)
return (TRUE);
ADBG_ERROR(("ata_init_dev_parms: failed\n"));
return (FALSE);
}
/*
*
* create fake inquiry data for DADA interface
*
*/
static void
{
ADBG_TRACE(("ata_disk_fake_inquiry entered\n"));
sizeof (inqp->inq_revision));
}
#define LOOP_COUNT 10000
/*
*
* ATA Set Multiple Mode
*
*/
static int
{
int rc;
0, /* feature n/a */
0, /* sector n/a */
0, /* head n/a */
0, /* cyl_low n/a */
0); /* cyl_hi n/a */
if (rc) {
return (TRUE);
}
ADBG_ERROR(("ata_disk_set_multiple: failed\n"));
return (FALSE);
}
/*
*
* ATA Identify Device command
*
*/
int
{
int rc;
ADBG_TRACE(("ata_disk_id entered\n"));
if (!rc)
return (FALSE);
/*
* If the disk is a CF/Microdrive that works under ATA mode
* through CF<->ATA adapters, identify it as an ATA device
* and a non removable media.
*/
}
return (FALSE);
return (FALSE);
}
return (TRUE);
}
static daddr_t
{
return (lbastop);
}
static daddr_t
{
lbastop <<= 8;
lbastop <<= 8;
lbastop <<= 8;
return (lbastop);
}
static daddr_t
{
/* turn on HOB and read the high-order 24 bits */
lbastop <<= 8;
lbastop <<= 8;
lbastop <<= 8;
/* Turn off HOB and read the low-order 24-bits */
lbastop <<= 8;
lbastop <<= 8;
return (lbastop);
}
/*
*
* Need to compute a value for ap_resid so that cp_resid can
* be set by ata_disk_complete(). The cp_resid var is actually
* misnamed. It's actually the offset to the block in which the
* error occurred not the number of bytes transferred to the device.
* At least that's how dadk actually uses the cp_resid when reporting
* an error. In other words the sector that had the error and the
* number of bytes transferred don't always indicate the same offset.
* On top of that, when doing DMA transfers there's actually no
* way to determine how many bytes have been transferred by the DMA
* engine. On the other hand, the drive will report which sector
* it faulted on. Using that address this routine computes the
* number of residual bytes beyond that point which probably weren't
* written to the drive (the drive is allowed to re-order sector
* writes but on an ATA disk there's no way to deal with that
* complication; in other words, the resid value calculated by
* this routine is as good as we can manage).
*/
static void
{
else /* CHS mode */
ADBG_TRACE(("ata_disk_get_resid start 0x%x cnt 0x%x stop 0x%x\n",
}
/*
* Removable media commands *
*/
/*
* get the media status
*
* NOTE: the error handling case probably isn't correct but it
* will have to do until someone gives me a drive to test this on.
*/
static int
{
ADBG_TRACE(("ata_disk_state\n"));
ATC_DOOR_LOCK, 0, 0, 0, 0, 0, 0)) {
*statep = DKIO_INSERTED;
return (ATA_FSM_RC_FINI);
}
*statep = DKIO_EJECTED;
else
return (ATA_FSM_RC_FINI);
}
/*
* eject the media
*/
static int
{
ADBG_TRACE(("ata_disk_eject\n"));
ATC_EJECT, 0, 0, 0, 0, 0, 0)) {
return (ATA_FSM_RC_FINI);
}
return (ATA_FSM_RC_FINI);
}
/*
* lock the drive
*
*/
static int
{
ADBG_TRACE(("ata_disk_lock\n"));
ATC_DOOR_LOCK, 0, 0, 0, 0, 0, 0)) {
return (ATA_FSM_RC_FINI);
}
return (ATA_FSM_RC_FINI);
}
/*
* unlock the drive
*
*/
static int
{
ADBG_TRACE(("ata_disk_unlock\n"));
ATC_DOOR_UNLOCK, 0, 0, 0, 0, 0, 0)) {
return (ATA_FSM_RC_FINI);
}
return (ATA_FSM_RC_FINI);
}
/*
* put the drive into standby mode
*/
static int
{
ADBG_TRACE(("ata_disk_standby\n"));
ATC_STANDBY_IM, 0, 0, 0, 0, 0, 0)) {
return (ATA_FSM_RC_FINI);
}
return (ATA_FSM_RC_FINI);
}
/*
* Recalibrate
*
* Note the extra long timeout value. This is necessary in case
* the drive was in standby mode and needs to spin up the media.
*
*/
static int
{
ADBG_TRACE(("ata_disk_recalibrate\n"));
ATC_RECAL, 0, 0, 0, 0, 0, 0)) {
return (ATA_FSM_RC_FINI);
}
return (ATA_FSM_RC_FINI);
}
/*
* Copy a string of bytes that were obtained by Identify Device into a
* string buffer provided by the caller.
*
* 1. Determine the amount to copy. This is the lesser of the
* length of the source string or the space available in the user's
* buffer.
* 2. The true length of the source string is always returned to the
* caller in the size field of the argument.
* 3. Copy the string, add a terminating NUL character at the end.
*/
static int
{
int destsize;
char nulchar;
/*
* The ioctls that use this routine are only available to
* the kernel.
*/
return (EFAULT);
/* 1. determine size of user's buffer */
flag))
return (EFAULT);
/*
* 2. Return the copied length to the caller. Note: for
* convenience, we actually copy the entire structure back out, not
* just the length. We don't change the is_buf field, so this
* shouldn't break anything.
*/
flag))
return (EFAULT);
/* 3. copy the string and add a NULL terminator */
return (EFAULT);
nulchar = '\0';
return (EFAULT);
return (0);
}
/*
* Sun branded drives are shipped write cache disabled. The default is to
* force write write caching on.
*/
static void
{
char *path;
if (ata_write_cache == 1) {
== FALSE) {
"%s unable to enable write cache targ=%d",
}
}
} else if (ata_write_cache == -1) {
== FALSE) {
"%s unable to disable write cache targ=%d",
}
}
}
}
/*
* Call set feature to spin-up the device.
*/
static int
{
int rc;
ADBG_TRACE(("ata_disk_set_feature_spinup entered\n"));
if (!rc)
return (ATA_FSM_RC_FINI);
}
/*
* Update device ata_id content - IDENTIFY DEVICE command.
*/
static int
{
int rc;
ADBG_TRACE(("ata_disk_id_update entered\n"));
/*
* select the appropriate drive and LUN
*/
/*
* make certain the drive is selected, and wait for not busy
*/
ADBG_ERROR(("ata_disk_id_update: select failed\n"));
return (ATA_FSM_RC_FINI);
}
if (!rc) {
} else {
}
return (ATA_FSM_RC_FINI);
}
/*
* Update device firmware.
*/
static int
{
int rc;
/*
* First check whether DOWNLOAD MICROCODE command is supported
*/
ADBG_ERROR(("drive doesn't support download "
"microcode command\n"));
return (ENOTSUP);
}
switch (type) {
case FW_TYPE_TEMP:
break;
case FW_TYPE_PERM:
break;
default:
return (EINVAL);
}
if (cmd_type == ATCM_FW_TEMP) {
ADBG_ERROR(("Temporary use is obsolete in "
return (ENOTSUP);
}
}
if (total_sec_count > MAX_FWFILE_SIZE_ONECMD) {
if (cmd_type == ATCM_FW_TEMP) {
ADBG_ERROR(("firmware size: %x sectors is too large\n",
return (EINVAL);
} else {
ADBG_WARN(("firmware size: %x sectors is larger than"
" one command, need to use the multicommand"
" subcommand\n", total_sec_count));
ADBG_ERROR(("This drive doesn't support "
"the multicommand subcommand\n"));
return (ENOTSUP);
}
}
}
ADBG_ERROR(("ata_disk_update_fw copyin failed\n"));
goto done;
}
for (; total_sec_count > 0; ) {
ADBG_ERROR(("ata_disk_update_fw alloc failed\n"));
goto done;
}
/* set the back ptr from the ata_pkt to the gcmd_t */
/* use PIO mode to update disk firmware */
/* use ap_bcount to set subcommand code */
/* add it to the queue, and use POLL mode */
if (rc != TRAN_ACCEPT) {
/* this should never, ever happen */
goto done;
}
} else
goto done;
} else {
}
}
rc = 0;
done:
return (rc);
}