nv_sata.c revision fa52d3c1580286e4ece59f1db6108c1b2c6d7963
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * CDDL HEADER START
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * The contents of this file are subject to the terms of the
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * Common Development and Distribution License (the "License").
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * You may not use this file except in compliance with the License.
3437829f938dbb44527d91fbbc5f430a1243c5a5JnRouvignac * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * See the License for the specific language governing permissions
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * and limitations under the License.
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * When distributing Covered Code, include this CDDL HEADER in each
3437829f938dbb44527d91fbbc5f430a1243c5a5JnRouvignac * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
3437829f938dbb44527d91fbbc5f430a1243c5a5JnRouvignac * If applicable, add the following below this CDDL HEADER, with the
3437829f938dbb44527d91fbbc5f430a1243c5a5JnRouvignac * fields enclosed by brackets "[]" replaced with your own identifying
3437829f938dbb44527d91fbbc5f430a1243c5a5JnRouvignac * information: Portions Copyright [yyyy] [name of copyright owner]
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * CDDL HEADER END
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * Use is subject to license terms.
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * nv_sata is a combo SATA HBA driver for ck804/mcp55 based chipsets.
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * A portion of the NCQ is in place, but is incomplete. NCQ is disabled
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * and is likely to be revisited in the future.
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * Power Management
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * ----------------
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * Normally power management would be responsible for ensuring the device
2c379b9a5f7b4dc665dfdc4673c7b051e7005da1gary.williams * is quiescent and then changing power states to the device, such as
#ifdef SGPIO_SUPPORT
#ifdef NV_MSI_SUPPORTED
#ifdef NCQ
int state);
static void nv_timeout(void *);
#ifdef SGPIO_SUPPORT
#ifdef SGPIO_SUPPORT
#ifdef SGPIO_SUPPORT
&modldrv,
int nv_log_delay = 0;
#ifdef DEBUG
int ncq_commands = 0;
int non_ncq_commands = 0;
_init(void)
int error;
if (error != 0) {
return (error);
return (error);
if (error != 0) {
return (error);
return (error);
_fini(void)
int error;
if (error != 0) {
return (error);
return (error);
#ifdef DEBUG
static uint32_t
static uint16_t
static uint8_t
#ifdef SGPIO_SUPPORT
int rlen;
switch (cmd) {
case DDI_ATTACH:
if (command == 0) {
DDI_SUCCESS) {
intr_types));
#ifdef NV_MSI_SUPPORTED
#ifdef SGPIO_SUPPORT
return (DDI_SUCCESS);
case DDI_RESUME:
return (DDI_FAILURE);
if (command == 0) {
return (DDI_SUCCESS);
return (DDI_FAILURE);
int port = 0;
while (--bar >= 0) {
return (DDI_FAILURE);
switch (cmd) {
case DDI_DETACH:
#ifdef SGPIO_SUPPORT
return (DDI_SUCCESS);
case DDI_SUSPEND:
return (DDI_SUCCESS);
return (DDI_FAILURE);
int instance;
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
return (DDI_SUCCESS);
return (DDI_FAILURE);
case DDI_INFO_DEVT2INSTANCE:
return (DDI_SUCCESS);
#ifdef SGPIO_SUPPORT
return (ENXIO);
int inst;
int status;
int drive;
return (EBADF);
return (EBADF);
return (EBADF);
switch (cmd) {
case DEVCTL_SET_LED:
if (status != 0)
return (EFAULT);
return (ENXIO);
return (EINVAL);
return (ENXIO);
return (ENXIO);
case DEVCTL_GET_LED:
if (status != 0)
return (EFAULT);
return (ENXIO);
return (ENXIO);
if (status != 0)
return (EFAULT);
case DEVCTL_NUM_LEDS:
if (status != 0)
return (EFAULT);
return (EINVAL);
return (SATA_FAILURE);
return (SATA_FAILURE);
return (SATA_FAILURE);
return (SATA_SUCCESS);
switch (det) {
case SSTATUS_DET_NODEV:
case SSTATUS_DET_PHYOFFLINE:
return (SATA_SUCCESS);
#ifdef SGPIO_SUPPORT
return (SATA_SUCCESS);
return (SATA_SUCCESS);
return (SATA_SUCCESS);
return (SATA_SUCCESS);
return (SATA_SUCCESS);
return (SATA_FAILURE);
int ret;
return (SATA_TRAN_PORT_ERROR);
if (ddi_in_panic()) {
return (SATA_TRAN_BUSY);
return (SATA_TRAN_PORT_ERROR);
return (SATA_TRAN_CMD_UNSUPPORTED);
return (SATA_TRAN_PORT_ERROR);
return (SATA_TRAN_PORT_ERROR);
return (SATA_TRAN_PORT_ERROR);
(ddi_in_panic() == 0)) {
return (SATA_TRAN_BUSY);
return (SATA_TRAN_BUSY);
return (ret);
return (ret);
int ret;
return (SATA_TRAN_BUSY);
servicing_interrupt()) {
return (SATA_TRAN_BUSY);
return (ret);
return (ret);
return (SATA_TRAN_ACCEPTED);
int ret;
#if ! defined(__lock_lint)
return (SATA_TRAN_ACCEPTED);
return (SATA_TRAN_ACCEPTED);
#if ! defined(__lock_lint)
return (SATA_TRAN_ACCEPTED);
return (SATA_FAILURE);
if (c_a) {
return (ret);
aborted++;
return (aborted);
case SATA_ADDR_CPORT:
case SATA_ADDR_DCPORT:
case SATA_ADDR_CNTRL:
case SATA_ADDR_PMPORT:
case SATA_ADDR_DPMPORT:
return (ret);
return (SATA_SUCCESS);
return (SATA_SUCCESS);
on_bit));
slot = 0;
case SATAC_READ_DMA_EXT:
case SATAC_WRITE_DMA_EXT:
case SATAC_WRITE_DMA:
case SATAC_READ_DMA:
case SATAC_READ_DMA_QUEUED:
case SATAC_WRITE_DMA_QUEUED:
case SATAC_READ_FPDMA_QUEUED:
case SATAC_WRITE_FPDMA_QUEUED:
goto fail;
#ifdef SGPIO_SUPPORT
return (SATA_TRAN_ACCEPTED);
fail:
return (ret);
case NV_SIG_DISK:
case NV_SIG_ATAPI:
case NV_SIG_PM:
case NV_SIG_NOTREADY:
~(MCP55_INT_IGNORE));
#ifdef NCQ
int j, ck804;
#ifdef SGPIO_SUPPORT
if (reg8 != j) {
KM_SLEEP);
return (NV_SUCCESS);
int rc, i;
return (NV_SUCCESS);
KM_SLEEP);
for (i = 0; i < NV_QUEUE_SLOTS; i++) {
return (NV_FAILURE);
return (NV_FAILURE);
return (NV_FAILURE);
return (NV_SUCCESS);
for (i = 0; i < NV_QUEUE_SLOTS; i++) {
if (port == 0) {
bm_addr_offset = 0;
(long)bm_addr_offset;
int port;
static uint_t
if (intr_status == 0) {
return (DDI_INTR_UNCLAIMED);
return (DDI_INTR_CLAIMED);
int port, i;
int nvcleared = 0;
int port_mask_hot[] = {
int port_mask_pm[] = {
clear_bits = 0;
if (clear_bits != 0) {
goto clear;
++nvcleared));
static uint_t
if (int_status == 0) {
NV_FAILURE) {
intr_cycles = 0;
#ifdef NCQ
if (clear) {
clear = 0;
return (ret);
static uint_t
int ret;
return (ret);
#ifdef NCQ
int slot;
return (DDI_INTR_CLAIMED);
int sactive;
return (NV_FAILURE);
return (NV_FAILURE);
active_pkt = 0;
if (active_pkt_bit == 0) {
return (NV_FAILURE);
return (NV_SUCCESS);
return (SATA_TRAN_QUEUE_FULL);
return (SATA_TRAN_QUEUE_FULL);
#ifdef NCQ
* this is not compiled for now as satapkt_device.satadev_qdepth
return (SATA_TRAN_QUEUE_FULL);
return (DDI_FAILURE);
return (DDI_FAILURE);
goto failure;
DDI_SUCCESS) {
goto failure;
goto failure;
for (x = 0; x < actual; x++) {
goto failure;
return (DDI_SUCCESS);
for (y = 0; y < actual; y++) {
return (DDI_FAILURE);
#ifdef NV_MSI_SUPPORTED
return (DDI_FAILURE);
return (DDI_FAILURE);
return (DDI_FAILURE);
DDI_SUCCESS) {
goto failure;
goto failure;
for (x = 0; x < actual; x++) {
goto failure;
return (DDI_SUCCESS);
for (y = 0; y < actual; y++) {
return (DDI_FAILURE);
if (nvc) {
if (nvp) {
if (nv_log_to_console) {
if (nv_prom_print) {
#if defined(DEBUG)
if (nv_log_delay) {
case ATA_ADDR_LBA:
case ATA_ADDR_LBA28:
case ATA_ADDR_LBA48:
return (SATA_TRAN_ACCEPTED);
return (ret);
== SATA_DIR_READ) {
#ifdef NCQ
return (NV_FAILURE);
#ifdef NCQ
#ifdef NCQ
return (SATA_TRAN_ACCEPTED);
return (SATA_TRAN_ACCEPTED);
goto error;
return (SATA_TRAN_ACCEPTED);
return (SATA_TRAN_PORT_ERROR);
return (SATA_TRAN_PORT_ERROR);
return (SATA_TRAN_PORT_ERROR);
return (SATA_TRAN_ACCEPTED);
int count;
int count;
int count;
NV_FAILURE) {
spkt);
ctlr_count));
if (ctlr_count == 0) {
if (ctlr_count > 0) {
if (ctlr_count == 0) {
if (ctlr_count > 0) {
for (; ctlr_count > 0;
int type_wait)
return (B_TRUE);
if (first_time) {
if (servicing_interrupt()) {
#if ! defined(__lock_lint)
return (B_FALSE);
int type_wait)
return (B_TRUE);
return (B_FALSE);
return (B_FALSE);
if (first_time) {
if (servicing_interrupt()) {
#if ! defined(__lock_lint)
return (B_FALSE);
static boolean_t
goto finished;
goto finished;
SATA_ADDR_CPORT, 0);
goto finished;
goto finished;
goto finished;
goto finished;
goto finished;
int_en);
int_en);
#ifdef SGPIO_SUPPORT
#ifdef SGPIO_SUPPORT
SATA_ADDR_CPORT, 0);
SATA_ADDR_CPORT, 0);
return (NV_FAILURE);
return (NV_FAILURE);
return (NV_SUCCESS);
#ifdef SGPIO_SUPPORT
KM_SLEEP);
#if defined(__amd64)
TASKQ_DEFAULTPRI, 0);
if (*csrpp == 0) {
return (NV_FAILURE);
if (*cbpp == 0) {
return (NV_FAILURE);
return (NV_SUCCESS);
int drive_count;
return (NV_FAILURE);
drive_count));
return (NV_SUCCESS);
int seq;
return (NV_SUCCESS);
return (NV_FAILURE);
return (NV_FAILURE);
return (NV_FAILURE);
return (NV_SUCCESS);
return (NV_FAILURE);
return (NV_SUCCESS);
return (NV_FAILURE);
int, old_leds);
new_led_state = 0;
for (i = 0; i < SGPIO_DRV_CNT_VALUE; i++) {
drv_leds |=
if (ticks > 0)
} while (ticks > 0);
int drive;