--- a/usr/src/uts/common/io/sata/adapters/si3124/si3124.c Tue Apr 20 15:27:40 2010 -0400
+++ b/usr/src/uts/common/io/sata/adapters/si3124/si3124.c Tue Apr 20 12:08:29 2010 -0700
@@ -20,13 +20,10 @@
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
-
-
/*
* SiliconImage 3124/3132 sata controller driver
*/
@@ -204,6 +201,7 @@
#include <sys/sata/sata_hba.h>
#include <sys/sata/adapters/si3124/si3124reg.h>
#include <sys/sata/adapters/si3124/si3124var.h>
+#include <sys/sdt.h>
/*
* Function prototypes for driver entry points
@@ -246,7 +244,7 @@
sata_pkt_t *);
static int si_initialize_controller(si_ctl_state_t *);
-static void si_deinititalize_controller(si_ctl_state_t *);
+static void si_deinitialize_controller(si_ctl_state_t *);
static void si_init_port(si_ctl_state_t *, int);
static int si_enumerate_port_multiplier(si_ctl_state_t *,
si_port_state_t *, int);
@@ -307,7 +305,7 @@
static void si_log(si_ctl_state_t *, uint_t, char *, ...);
#endif /* SI_DEBUG */
-static void si_copy_out_regs(sata_cmd_t *, fis_reg_h2d_t *);
+static void si_copy_out_regs(sata_cmd_t *, si_ctl_state_t *, uint8_t, uint8_t);
/*
* DMA attributes for the data buffer
@@ -699,7 +697,7 @@
if (attach_state & ATTACH_PROGRESS_HW_INIT) {
si_ctlp->sictl_flags |= SI_DETACH;
/* We want to set SI_DETACH to deallocate all memory */
- si_deinititalize_controller(si_ctlp);
+ si_deinitialize_controller(si_ctlp);
si_ctlp->sictl_flags &= ~SI_DETACH;
}
@@ -768,9 +766,9 @@
(void) untimeout(si_ctlp->sictl_timeout_id);
si_ctlp->sictl_flags &= ~SI_NO_TIMEOUTS;
- /* deinitialize the controller. */
+ /* de-initialize the controller. */
si_ctlp->sictl_flags |= SI_DETACH;
- si_deinititalize_controller(si_ctlp);
+ si_deinitialize_controller(si_ctlp);
si_ctlp->sictl_flags &= ~SI_DETACH;
/* destroy any mutexes */
@@ -803,7 +801,7 @@
* handle dump(9e) to save CPR state after DDI_SUSPEND
* completes. This is OK since presumably power will be
* removed anyways. No outstanding transactions should be
- * on the controller since the children are already quiesed.
+ * on the controller since the children are already quiesced.
*
* If any ioctls/cfgadm support is added that touches
* hardware, those entry points will need to check for
@@ -818,7 +816,7 @@
mutex_enter(&si_ctlp->sictl_mutex);
}
- si_deinititalize_controller(si_ctlp);
+ si_deinitialize_controller(si_ctlp);
si_ctlp->sictl_flags |= SI_NO_TIMEOUTS;
(void) untimeout(si_ctlp->sictl_timeout_id);
@@ -910,7 +908,7 @@
(void) untimeout(si_ctlp->sictl_timeout_id);
si_ctlp->sictl_flags &= ~SI_NO_TIMEOUTS;
- si_deinititalize_controller(si_ctlp);
+ si_deinitialize_controller(si_ctlp);
si_ctlp->sictl_power_level = PM_LEVEL_D3;
}
@@ -1240,9 +1238,8 @@
if (spkt->satapkt_op_mode & (SATA_OPMODE_POLLING|SATA_OPMODE_SYNCH)) {
/* we need to poll now */
- mutex_exit(&si_portp->siport_mutex);
si_poll_cmd(si_ctlp, si_portp, cport, slot, spkt);
- mutex_enter(&si_portp->siport_mutex);
+
}
mutex_exit(&si_portp->siport_mutex);
@@ -1302,9 +1299,7 @@
uint32_t finished_tags, unfinished_tags;
int tmpslot;
sata_pkt_t *satapkt;
- si_prb_t *prb;
- uint32_t *prb_word_ptr;
- int i;
+ struct sata_cmd_flags *flagsp;
SIDBG1(SIDBG_ERRS|SIDBG_ENTRY, si_ctlp,
"si_mop_commands entered: slot_status: 0x%x",
@@ -1342,12 +1337,11 @@
satapkt = si_portp->siport_slot_pkts[tmpslot];
ASSERT(satapkt != NULL);
- prb = &si_portp->siport_prbpool[tmpslot];
- ASSERT(prb != NULL);
- satapkt->satapkt_cmd.satacmd_status_reg =
- GET_FIS_COMMAND(prb->prb_fis);
- if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs)
- si_copy_out_regs(&satapkt->satapkt_cmd, &prb->prb_fis);
+
+ if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs) {
+ si_copy_out_regs(&satapkt->satapkt_cmd, si_ctlp,
+ port, tmpslot);
+ }
SIDBG1(SIDBG_ERRS, si_ctlp,
"si_mop_commands sending up completed satapkt: %x",
@@ -1376,48 +1370,21 @@
si_set_sense_data(satapkt, SATA_PKT_DEV_ERROR);
}
- /*
- * The LRAM contains the the modified FIS.
- * Read the modified FIS to obtain the Error & Status.
- */
- prb = &(si_portp->siport_prbpool[tmpslot]);
-
- prb_word_ptr = (uint32_t *)(void *)prb;
- for (i = 0; i < (sizeof (si_prb_t)/4); i++) {
- prb_word_ptr[i] = ddi_get32(
- si_ctlp->sictl_port_acc_handle,
- (uint32_t *)(PORT_LRAM(si_ctlp, port,
- tmpslot)+i*4));
- }
-
- satapkt->satapkt_cmd.satacmd_status_reg =
- GET_FIS_COMMAND(prb->prb_fis);
- satapkt->satapkt_cmd.satacmd_error_reg =
- GET_FIS_FEATURES(prb->prb_fis);
- satapkt->satapkt_cmd.satacmd_sec_count_lsb =
- GET_FIS_SECTOR_COUNT(prb->prb_fis);
- satapkt->satapkt_cmd.satacmd_lba_low_lsb =
- GET_FIS_SECTOR(prb->prb_fis);
- satapkt->satapkt_cmd.satacmd_lba_mid_lsb =
- GET_FIS_CYL_LOW(prb->prb_fis);
- satapkt->satapkt_cmd.satacmd_lba_high_lsb =
- GET_FIS_CYL_HI(prb->prb_fis);
- satapkt->satapkt_cmd.satacmd_device_reg =
- GET_FIS_DEV_HEAD(prb->prb_fis);
-
- if (satapkt->satapkt_cmd.satacmd_addr_type == ATA_ADDR_LBA48) {
- satapkt->satapkt_cmd.satacmd_sec_count_msb =
- GET_FIS_SECTOR_COUNT_EXP(prb->prb_fis);
- satapkt->satapkt_cmd.satacmd_lba_low_msb =
- GET_FIS_SECTOR_EXP(prb->prb_fis);
- satapkt->satapkt_cmd.satacmd_lba_mid_msb =
- GET_FIS_CYL_LOW_EXP(prb->prb_fis);
- satapkt->satapkt_cmd.satacmd_lba_high_msb =
- GET_FIS_CYL_HI_EXP(prb->prb_fis);
- }
-
- if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs)
- si_copy_out_regs(&satapkt->satapkt_cmd, &prb->prb_fis);
+
+ flagsp = &satapkt->satapkt_cmd.satacmd_flags;
+
+ flagsp->sata_copy_out_lba_low_msb = B_TRUE;
+ flagsp->sata_copy_out_lba_mid_msb = B_TRUE;
+ flagsp->sata_copy_out_lba_high_msb = B_TRUE;
+ flagsp->sata_copy_out_lba_low_lsb = B_TRUE;
+ flagsp->sata_copy_out_lba_mid_lsb = B_TRUE;
+ flagsp->sata_copy_out_lba_high_lsb = B_TRUE;
+ flagsp->sata_copy_out_error_reg = B_TRUE;
+ flagsp->sata_copy_out_sec_count_msb = B_TRUE;
+ flagsp->sata_copy_out_sec_count_lsb = B_TRUE;
+ flagsp->sata_copy_out_device_reg = B_TRUE;
+
+ si_copy_out_regs(&satapkt->satapkt_cmd, si_ctlp, port, tmpslot);
/*
* In the case of NCQ command failures, the error is
@@ -2293,7 +2260,6 @@
pkt_timeout_ticks = drv_usectohz((clock_t)satapkt->satapkt_time *
1000000);
- mutex_enter(&si_portp->siport_mutex);
/* we start out with SATA_PKT_COMPLETED as the satapkt_reason */
satapkt->satapkt_reason = SATA_PKT_COMPLETED;
@@ -2328,7 +2294,8 @@
if (satapkt->satapkt_reason != SATA_PKT_COMPLETED) {
/* The si_mop_command() got to our packet before us */
- goto poll_done;
+
+ return;
}
/*
@@ -2350,7 +2317,7 @@
(void) si_intr_command_error(si_ctlp, si_portp, port);
mutex_enter(&si_portp->siport_mutex);
- goto poll_done;
+ return;
/*
* Why do we need to call si_intr_command_error() ?
@@ -2383,11 +2350,15 @@
port_intr_status & INTR_MASK);
}
-
} else if (slot_status & SI_SLOT_MASK & (0x1 << slot)) {
satapkt->satapkt_reason = SATA_PKT_TIMEOUT;
+
} /* else: the command completed successfully */
+ if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs) {
+ si_copy_out_regs(&satapkt->satapkt_cmd, si_ctlp, port, slot);
+ }
+
if ((satapkt->satapkt_cmd.satacmd_cmd_reg ==
SATAC_WRITE_FPDMA_QUEUED) ||
(satapkt->satapkt_cmd.satacmd_cmd_reg ==
@@ -2397,9 +2368,6 @@
CLEAR_BIT(si_portp->siport_pending_tags, slot);
-poll_done:
- mutex_exit(&si_portp->siport_mutex);
-
/*
* tidbit: What is the interaction of abort with polling ?
* What happens if the current polled pkt is aborted in parallel ?
@@ -3025,14 +2993,14 @@
* before calling us.
*/
static void
-si_deinititalize_controller(si_ctl_state_t *si_ctlp)
+si_deinitialize_controller(si_ctl_state_t *si_ctlp)
{
int port;
_NOTE(ASSUMING_PROTECTED(si_ctlp))
SIDBG0(SIDBG_INIT|SIDBG_ENTRY, si_ctlp,
- "si3124: si_deinititalize_controller entered");
+ "si3124: si_deinitialize_controller entered");
/* disable all the interrupts. */
si_disable_all_interrupts(si_ctlp);
@@ -3068,7 +3036,7 @@
PORT_CONTROL_SET_BITS_PORT_INITIALIZE);
/*
- * Clear the InterruptNCOR (Interupt No Clear on Read).
+ * Clear the InterruptNCOR (Interrupt No Clear on Read).
* This step ensures that a mere reading of slot_status will clear
* the interrupt; no explicit clearing of interrupt condition
* will be needed for successful completion of commands.
@@ -3667,20 +3635,18 @@
finished_tags = si_portp->siport_pending_tags &
~slot_status & SI_SLOT_MASK;
while (finished_tags) {
- si_prb_t *prb;
finished_slot = ddi_ffs(finished_tags) - 1;
if (finished_slot == -1) {
break;
}
- prb = &si_portp->siport_prbpool[finished_slot];
satapkt = si_portp->siport_slot_pkts[finished_slot];
- satapkt->satapkt_cmd.satacmd_status_reg =
- GET_FIS_COMMAND(prb->prb_fis);
-
- if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs)
- si_copy_out_regs(&satapkt->satapkt_cmd, &prb->prb_fis);
+
+ if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs) {
+ si_copy_out_regs(&satapkt->satapkt_cmd, si_ctlp, port,
+ finished_slot);
+ }
CLEAR_BIT(si_portp->siport_pending_tags, finished_slot);
CLEAR_BIT(finished_tags, finished_slot);
@@ -4998,6 +4964,7 @@
sata_device_t sdevice;
uint32_t SStatus;
uint32_t SControl;
+ uint32_t port_intr_status;
_NOTE(ASSUMING_PROTECTED(si_portp))
@@ -5027,28 +4994,6 @@
si_portp->siport_reset_in_progress = 1;
}
- /*
- * For some reason, we are losing the interrupt enablement after
- * any reset condition. So restore them back now.
- */
- SIDBG1(SIDBG_INIT, si_ctlp,
- "current interrupt enable set: 0x%x",
- ddi_get32(si_ctlp->sictl_port_acc_handle,
- (uint32_t *)PORT_INTERRUPT_ENABLE_SET(si_ctlp, port)));
-
- ddi_put32(si_ctlp->sictl_port_acc_handle,
- (uint32_t *)PORT_INTERRUPT_ENABLE_SET(si_ctlp, port),
- (INTR_COMMAND_COMPLETE |
- INTR_COMMAND_ERROR |
- INTR_PORT_READY |
- INTR_POWER_CHANGE |
- INTR_PHYRDY_CHANGE |
- INTR_COMWAKE_RECEIVED |
- INTR_UNRECOG_FIS |
- INTR_DEV_XCHANGED |
- INTR_SETDEVBITS_NOTIFY));
-
- si_enable_port_interrupts(si_ctlp, port);
/*
* Every reset needs a PHY initialization.
@@ -5180,6 +5125,43 @@
}
}
+
+ /*
+ * For some reason, we are losing the interrupt enablement after
+ * any reset condition. So restore them back now.
+ */
+
+ SIDBG1(SIDBG_INIT, si_ctlp,
+ "current interrupt enable set: 0x%x",
+ ddi_get32(si_ctlp->sictl_port_acc_handle,
+ (uint32_t *)PORT_INTERRUPT_ENABLE_SET(si_ctlp, port)));
+
+ ddi_put32(si_ctlp->sictl_port_acc_handle,
+ (uint32_t *)PORT_INTERRUPT_ENABLE_SET(si_ctlp, port),
+ (INTR_COMMAND_COMPLETE |
+ INTR_COMMAND_ERROR |
+ INTR_PORT_READY |
+ INTR_POWER_CHANGE |
+ INTR_PHYRDY_CHANGE |
+ INTR_COMWAKE_RECEIVED |
+ INTR_UNRECOG_FIS |
+ INTR_DEV_XCHANGED |
+ INTR_SETDEVBITS_NOTIFY));
+
+ si_enable_port_interrupts(si_ctlp, port);
+
+ /*
+ * make sure interrupts are cleared
+ */
+ port_intr_status = ddi_get32(si_ctlp->sictl_global_acc_handle,
+ (uint32_t *)PORT_INTERRUPT_STATUS(si_ctlp, port));
+
+ ddi_put32(si_ctlp->sictl_port_acc_handle,
+ (uint32_t *)(PORT_INTERRUPT_STATUS(si_ctlp,
+ port)),
+ port_intr_status & INTR_MASK);
+
+
SIDBG0(SIDBG_POLL_LOOP, si_ctlp,
"si_reset_dport_wait_till_ready returning success");
@@ -5446,28 +5428,97 @@
#endif /* SI_DEBUG */
static void
-si_copy_out_regs(sata_cmd_t *scmd, fis_reg_h2d_t *fisp)
+si_copy_out_regs(sata_cmd_t *scmd, si_ctl_state_t *si_ctlp, uint8_t port,
+ uint8_t slot)
{
- fis_reg_h2d_t fis = *fisp;
-
- if (scmd->satacmd_flags.sata_copy_out_sec_count_msb)
- scmd->satacmd_sec_count_msb = GET_FIS_SECTOR_COUNT_EXP(fis);
- if (scmd->satacmd_flags.sata_copy_out_lba_low_msb)
- scmd->satacmd_lba_low_msb = GET_FIS_SECTOR_EXP(fis);
- if (scmd->satacmd_flags.sata_copy_out_lba_mid_msb)
- scmd->satacmd_lba_mid_msb = GET_FIS_CYL_LOW_EXP(fis);
- if (scmd->satacmd_flags.sata_copy_out_lba_high_msb)
- scmd->satacmd_lba_high_msb = GET_FIS_CYL_HI_EXP(fis);
- if (scmd->satacmd_flags.sata_copy_out_sec_count_lsb)
- scmd->satacmd_sec_count_lsb = GET_FIS_SECTOR_COUNT(fis);
- if (scmd->satacmd_flags.sata_copy_out_lba_low_lsb)
- scmd->satacmd_lba_low_lsb = GET_FIS_SECTOR(fis);
- if (scmd->satacmd_flags.sata_copy_out_lba_mid_lsb)
- scmd->satacmd_lba_mid_lsb = GET_FIS_CYL_LOW(fis);
- if (scmd->satacmd_flags.sata_copy_out_lba_high_lsb)
- scmd->satacmd_lba_high_lsb = GET_FIS_CYL_HI(fis);
- if (scmd->satacmd_flags.sata_copy_out_device_reg)
- scmd->satacmd_device_reg = GET_FIS_DEV_HEAD(fis);
- if (scmd->satacmd_flags.sata_copy_out_error_reg)
- scmd->satacmd_error_reg = GET_FIS_FEATURES(fis);
+ uint32_t *fis_word_ptr;
+ si_prb_t *prb;
+ int i;
+
+ /*
+ * The LRAM contains the the modified FIS after command completion, so
+ * first copy it back to the in-core PRB pool. To save read cycles,
+ * just copy over the FIS portion of the PRB pool.
+ */
+ prb = &si_ctlp->sictl_ports[port]->siport_prbpool[slot];
+
+ fis_word_ptr = (uint32_t *)(void *)(&prb->prb_fis);
+
+ for (i = 0; i < (sizeof (fis_reg_h2d_t)/4); i++) {
+ fis_word_ptr[i] = ddi_get32(
+ si_ctlp->sictl_port_acc_handle,
+ (uint32_t *)(PORT_LRAM(si_ctlp, port,
+ slot) + i * 4 + 0x08));
+ }
+
+ /*
+ * always get the status register
+ */
+ scmd->satacmd_status_reg = GET_FIS_COMMAND(prb->prb_fis);
+
+ DTRACE_PROBE1(satacmd_status_reg, int, scmd->satacmd_status_reg);
+
+ if (scmd->satacmd_flags.sata_copy_out_sec_count_msb) {
+ scmd->satacmd_sec_count_msb =
+ GET_FIS_SECTOR_COUNT_EXP(prb->prb_fis);
+ SIDBG1(SIDBG_VERBOSE, NULL,
+ "copyout satacmd_sec_count_msb %x\n",
+ scmd->satacmd_sec_count_msb);
+ }
+
+ if (scmd->satacmd_flags.sata_copy_out_lba_low_msb) {
+ scmd->satacmd_lba_low_msb = GET_FIS_SECTOR_EXP(prb->prb_fis);
+ SIDBG1(SIDBG_VERBOSE, NULL, "copyout satacmd_lba_low_msb %x\n",
+ scmd->satacmd_lba_low_msb);
+ }
+
+ if (scmd->satacmd_flags.sata_copy_out_lba_mid_msb) {
+ scmd->satacmd_lba_mid_msb = GET_FIS_CYL_LOW_EXP(prb->prb_fis);
+ SIDBG1(SIDBG_VERBOSE, NULL, "copyout satacmd_lba_mid_msb %x\n",
+ scmd->satacmd_lba_mid_msb);
+ }
+
+ if (scmd->satacmd_flags.sata_copy_out_lba_high_msb) {
+ scmd->satacmd_lba_high_msb = GET_FIS_CYL_HI_EXP(prb->prb_fis);
+ SIDBG1(SIDBG_VERBOSE, NULL, "copyout satacmd_lba_high_msb %x\n",
+ scmd->satacmd_lba_high_msb);
+ }
+
+ if (scmd->satacmd_flags.sata_copy_out_sec_count_lsb) {
+ scmd->satacmd_sec_count_lsb =
+ GET_FIS_SECTOR_COUNT(prb->prb_fis);
+ SIDBG1(SIDBG_VERBOSE, NULL,
+ "copyout satacmd_sec_count_lsb %x\n",
+ scmd->satacmd_sec_count_lsb);
+ }
+
+ if (scmd->satacmd_flags.sata_copy_out_lba_low_lsb) {
+ scmd->satacmd_lba_low_lsb = GET_FIS_SECTOR(prb->prb_fis);
+ SIDBG1(SIDBG_VERBOSE, NULL, "copyout satacmd_lba_low_lsb %x\n",
+ scmd->satacmd_lba_low_lsb);
+ }
+
+ if (scmd->satacmd_flags.sata_copy_out_lba_mid_lsb) {
+ scmd->satacmd_lba_mid_lsb = GET_FIS_CYL_LOW(prb->prb_fis);
+ SIDBG1(SIDBG_VERBOSE, NULL, "copyout satacmd_lba_mid_lsb %x\n",
+ scmd->satacmd_lba_mid_lsb);
+ }
+
+ if (scmd->satacmd_flags.sata_copy_out_lba_high_lsb) {
+ scmd->satacmd_lba_high_lsb = GET_FIS_CYL_HI(prb->prb_fis);
+ SIDBG1(SIDBG_VERBOSE, NULL, "copyout satacmd_lba_high_lsb %x\n",
+ scmd->satacmd_lba_high_lsb);
+ }
+
+ if (scmd->satacmd_flags.sata_copy_out_device_reg) {
+ scmd->satacmd_device_reg = GET_FIS_DEV_HEAD(prb->prb_fis);
+ SIDBG1(SIDBG_VERBOSE, NULL, "copyout satacmd_device_reg %x\n",
+ scmd->satacmd_device_reg);
+ }
+
+ if (scmd->satacmd_flags.sata_copy_out_error_reg) {
+ scmd->satacmd_error_reg = GET_FIS_FEATURES(prb->prb_fis);
+ SIDBG1(SIDBG_VERBOSE, NULL, "copyout satacmd_error_reg %x\n",
+ scmd->satacmd_error_reg);
+ }
}