diff options
author | Xiao-Yu Zhang <Xiao-Yu.Zhang@Sun.COM> | 2009-03-28 15:28:14 +0800 |
---|---|---|
committer | Xiao-Yu Zhang <Xiao-Yu.Zhang@Sun.COM> | 2009-03-28 15:28:14 +0800 |
commit | 0a4c4cec315123d3aa1d87ee8ea976c5501de577 (patch) | |
tree | cda148ef745476feb1f290612391b5cb66826a63 | |
parent | 617e2443dfc17fe44fd44c0675d6aad2ffc9df42 (diff) | |
download | illumos-gate-0a4c4cec315123d3aa1d87ee8ea976c5501de577.tar.gz |
6753962 ahci does not work with Asus M3N78 Pro/M3N-HT (nforce 780a) motherboard SATA interfaces
-rw-r--r-- | usr/src/uts/common/io/sata/adapters/ahci/ahci.c | 376 | ||||
-rw-r--r-- | usr/src/uts/common/sys/sata/adapters/ahci/ahcireg.h | 3 | ||||
-rw-r--r-- | usr/src/uts/common/sys/sata/adapters/ahci/ahcivar.h | 12 |
3 files changed, 245 insertions, 146 deletions
diff --git a/usr/src/uts/common/io/sata/adapters/ahci/ahci.c b/usr/src/uts/common/io/sata/adapters/ahci/ahci.c index e749299c46..ad3ba14090 100644 --- a/usr/src/uts/common/io/sata/adapters/ahci/ahci.c +++ b/usr/src/uts/common/io/sata/adapters/ahci/ahci.c @@ -637,6 +637,13 @@ ahci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) "hba does not support 64-bit addressing"); } + /* Checking for Support Command List Override */ + if (cap_status & AHCI_HBA_CAP_SCLO) { + ahci_ctlp->ahcictl_cap |= AHCI_CAP_SCLO; + AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, + "hba supports command list override."); + } + if (pci_config_setup(dip, &ahci_ctlp->ahcictl_pci_conf_handle) != DDI_SUCCESS) { cmn_err(CE_WARN, "!ahci%d: Cannot set up pci configure space", @@ -2842,7 +2849,8 @@ static int ahci_initialize_port(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, uint8_t port) { - uint32_t port_cmd_status; + uint32_t port_sstatus, port_task_file, port_cmd_status; + int ret; port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port)); @@ -2854,22 +2862,63 @@ ahci_initialize_port(ahci_ctl_t *ahci_ctlp, * Check whether the port is in NotRunning state, if not, * put the port in NotRunning state */ - if (!(port_cmd_status & + if (port_cmd_status & (AHCI_CMD_STATUS_ST | AHCI_CMD_STATUS_CR | AHCI_CMD_STATUS_FRE | - AHCI_CMD_STATUS_FR))) { - - goto next; + AHCI_CMD_STATUS_FR)) { + (void) ahci_put_port_into_notrunning_state(ahci_ctlp, + ahci_portp, port); } - if (ahci_restart_port_wait_till_ready(ahci_ctlp, ahci_portp, - port, AHCI_RESET_NO_EVENTS_UP|AHCI_PORT_INIT, NULL) != AHCI_SUCCESS) - return (AHCI_FAILURE); + /* Device is unknown at first */ + ahci_portp->ahciport_device_type = SATA_DTYPE_UNKNOWN; -next: - AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, - "port %d is in NotRunning state now", port); + port_sstatus = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, + (uint32_t *)AHCI_PORT_PxSSTS(ahci_ctlp, port)); + port_task_file = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, + (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port)); + + /* Check physcial link status */ + if (SSTATUS_GET_IPM(port_sstatus) == SSTATUS_IPM_NODEV_NOPHYCOM || + SSTATUS_GET_DET(port_sstatus) == SSTATUS_DET_DEVPRE_NOPHYCOM || + + /* Check interface status */ + port_task_file & AHCI_TFD_STS_BSY || + port_task_file & AHCI_TFD_STS_DRQ) { + + /* Incorrect task file state, we need to reset port */ + ret = ahci_port_reset(ahci_ctlp, ahci_portp, port); + + /* Does port reset succeed on HBA port? */ + if (ret != AHCI_SUCCESS) { + AHCIDBG1(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp, + "ahci_initialize_port:" + "port reset faild at port %d", port); + return (AHCI_FAILURE); + } + + /* Is port failed? */ + if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED) { + AHCIDBG2(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp, + "ahci_initialize_port: port %d state 0x%x", + port, ahci_portp->ahciport_port_state); + return (AHCI_FAILURE); + } + + /* Is there any device attached? */ + if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) { + + /* Do not waste time on empty port */ + AHCIDBG1(AHCIDBG_INIT|AHCIDBG_INFO, ahci_ctlp, + "ahci_initialize_port: No device is found " + "at port %d", port); + goto out; + } + } + ahci_portp->ahciport_port_state = SATA_STATE_READY; + + AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "port %d is ready now.", port); /* * At the time being, only probe ports/devices and get the types of @@ -2878,7 +2927,10 @@ next: * don't support the situation. */ if (ahci_ctlp->ahcictl_flags & AHCI_ATTACH) { - /* Try to get the device signature */ + /* + * Till now we can assure a device attached to that HBA port + * and work correctly. Now try to get the device signature. + */ ahci_find_dev_signature(ahci_ctlp, ahci_portp, port); } else { @@ -3143,16 +3195,18 @@ ahci_software_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, ahci_cmd_header_t *cmd_header; uint32_t port_cmd_status, port_cmd_issue, port_task_file; int slot, loop_count; + int rval = AHCI_FAILURE; AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, "Port %d device resetting", port); - /* First clear PxCMD.ST */ - (void) ahci_put_port_into_notrunning_state(ahci_ctlp, - ahci_portp, port); - - /* Then re-set PxCMD.ST */ - (void) ahci_start_port(ahci_ctlp, ahci_portp, port); + /* First clear PxCMD.ST (AHCI v1.2 10.4.1) */ + if (ahci_put_port_into_notrunning_state(ahci_ctlp, ahci_portp, + port) != AHCI_SUCCESS) { + AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + "ahci_software_reset: cannot stop HBA port %d.", port); + goto out; + } /* Check PxTFD.STS.BSY and PxTFD.STS.DRQ */ port_task_file = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, @@ -3160,24 +3214,75 @@ ahci_software_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, if (port_task_file & AHCI_TFD_STS_BSY || port_task_file & AHCI_TFD_STS_DRQ) { + if (!(ahci_ctlp->ahcictl_cap & AHCI_CAP_SCLO)) { + AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + "PxTFD.STS.BSY/DRQ is set (PxTFD=0x%x), " + "cannot issue a software reset.", port_task_file); + goto out; + } + + /* + * If HBA Support CLO, as Command List Override (CAP.SCLO is + * set), PxCMD.CLO bit should be set before set PxCMD.ST, in + * order to clear PxTFD.STS.BSY and PxTFD.STS.DRQ. + */ + AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp, + "PxTFD.STS.BSY/DRQ is set, try SCLO.") + port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port)); - if (!(port_cmd_status & AHCI_CMD_STATUS_CLO)) { - AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp, - "PxTFD.STS.BSY or PxTFD.STS.DRQ is still set, " - "but PxCMD.CLO isn't supported, so a port " - "reset is needed."); - return (AHCI_FAILURE); + ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle, + (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port), + port_cmd_status|AHCI_CMD_STATUS_CLO); + + /* Waiting till PxCMD.SCLO bit is cleared */ + loop_count = 0; + do { + /* Wait for 10 millisec */ + drv_usecwait(AHCI_10MS_USECS); + + /* We are effectively timing out after 1 sec. */ + if (loop_count++ > 100) { + AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + "SCLO time out. port %d is busy.", port); + goto out; + } + + port_cmd_status = + ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, + (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port)); + } while (port_cmd_status & AHCI_CMD_STATUS_CLO); + + /* Re-check */ + port_task_file = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, + (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port)); + if (port_task_file & AHCI_TFD_STS_BSY || + port_task_file & AHCI_TFD_STS_DRQ) { + AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + "SCLO cannot clear PxTFD.STS.BSY/DRQ (PxTFD=0x%x)", + port_task_file); + goto out; } } - slot = ahci_claim_free_slot(ahci_ctlp, ahci_portp, AHCI_NON_NCQ_CMD); - if (slot == AHCI_FAILURE) { - AHCIDBG0(AHCIDBG_INFO, ahci_ctlp, - "ahci_software_reset: no free slot"); - return (AHCI_FAILURE); + /* Then start port */ + if (ahci_start_port(ahci_ctlp, ahci_portp, port) + != AHCI_SUCCESS) { + AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, + "ahci_software_reset: cannot start AHCI port %d.", port); + goto out; } + /* + * When ahci_port.ahciport_mop_in_progress is set, A non-zero + * ahci_port.ahciport_pending_ncq_tags may fail + * ahci_claim_free_slot(). Actually according to spec, by clearing + * PxCMD.ST there is no command outstanding while executing software + * reseting. Hence we directly use slot 0 instead of + * ahci_claim_free_slot(). + */ + slot = 0; + /* Now send the first H2D Register FIS with SRST set to 1 */ cmd_table = ahci_portp->ahciport_cmd_tables[slot]; bzero((void *)cmd_table, ahci_cmd_table_size); @@ -3186,7 +3291,6 @@ ahci_software_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, &(cmd_table->ahcict_command_fis.ahcifc_fis.ahcifc_h2d_register); SET_FIS_TYPE(h2d_register_fisp, AHCI_H2D_REGISTER_FIS_TYPE); - SET_FIS_PMP(h2d_register_fisp, AHCI_PORTMULT_CONTROL_PORT); SET_FIS_DEVCTL(h2d_register_fisp, SATA_DEVCTL_SRST); /* Set Command Header in Command List */ @@ -3223,7 +3327,7 @@ ahci_software_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, /* We are effectively timing out after 1 sec. */ if (loop_count++ > AHCI_POLLRATE_PORT_SOFTRESET) { - break; + goto out; } /* Wait for 10 millisec */ delay(AHCI_10MS_TICKS); @@ -3234,8 +3338,6 @@ ahci_software_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, "port_cmd_issue = 0x%x, slot = 0x%x", loop_count, port_cmd_issue, slot); - CLEAR_BIT(ahci_portp->ahciport_pending_tags, slot); - /* Now send the second H2D Register FIS with SRST cleard to zero */ cmd_table = ahci_portp->ahciport_cmd_tables[slot]; bzero((void *)cmd_table, ahci_cmd_table_size); @@ -3244,7 +3346,6 @@ ahci_software_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, &(cmd_table->ahcict_command_fis.ahcifc_fis.ahcifc_h2d_register); SET_FIS_TYPE(h2d_register_fisp, AHCI_H2D_REGISTER_FIS_TYPE); - SET_FIS_PMP(h2d_register_fisp, AHCI_PORTMULT_CONTROL_PORT); /* Set Command Header in Command List */ cmd_header = &ahci_portp->ahciport_cmd_list[slot]; @@ -3278,7 +3379,7 @@ ahci_software_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, /* We are effectively timing out after 1 sec. */ if (loop_count++ > AHCI_POLLRATE_PORT_SOFTRESET) { - break; + goto out; } /* Wait for 10 millisec */ delay(AHCI_10MS_TICKS); @@ -3291,7 +3392,14 @@ ahci_software_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, CLEAR_BIT(ahci_portp->ahciport_pending_tags, slot); - return (AHCI_SUCCESS); + rval = AHCI_SUCCESS; +out: + AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp, + "ahci_software_reset: %s at port %d", + rval == AHCI_SUCCESS ? "succeed" : "failed", + port); + + return (rval); } /* @@ -3318,18 +3426,16 @@ static int ahci_port_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, uint8_t port) { uint32_t cap_status, port_cmd_status; - uint32_t port_scontrol, port_sstatus; + uint32_t port_scontrol, port_sstatus, port_serror; uint32_t port_intr_status, port_task_file; -#if AHCI_DEBUG - uint32_t port_signature; -#endif + int loop_count; - int rval = AHCI_SUCCESS; int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip); AHCIDBG1(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "Port %d port resetting...", port); ahci_portp->ahciport_port_state = 0; + ahci_portp->ahciport_device_type = SATA_DTYPE_UNKNOWN; cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_GLOBAL_CAP(ahci_ctlp)); @@ -3495,21 +3601,26 @@ ahci_port_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, uint8_t port) * is no device present. */ ahci_portp->ahciport_device_type = SATA_DTYPE_NONE; - goto out; + return (AHCI_SUCCESS); } /* Now we can make sure there is a device connected to the port */ port_intr_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxIS(ahci_ctlp, port)); + port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, + (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port)); - /* a COMINIT signal is supposed to be received */ - if (!(port_intr_status & AHCI_INTR_STATUS_PCS)) { + /* + * A COMINIT signal is supposed to be received + * PxSERR.DIAG.X or PxIS.PCS should be set + */ + if (!(port_intr_status & AHCI_INTR_STATUS_PCS) && + !(port_serror & SERROR_EXCHANGED_ERR)) { cmn_err(CE_WARN, "!ahci%d: ahci_port_reset port %d " "COMINIT signal from the device not received", instance, port); ahci_portp->ahciport_port_state |= SATA_PSTATE_FAILED; - rval = AHCI_FAILURE; - goto out; + return (AHCI_FAILURE); } /* @@ -3539,95 +3650,72 @@ ahci_port_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, uint8_t port) SERROR_EXCHANGED_ERR); /* - * Next check whether COMRESET is completed successfully + * Devices should return a FIS contains its signature to HBA after + * COMINIT signal. Check whether a D2H FIS is received by polling + * PxTFD.STS.ERR bit. */ loop_count = 0; do { - port_task_file = - ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, - (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port)); - - /* - * The Error bit '1' means COMRESET is finished successfully - * The device hardware has been initialized and the power-up - * diagnostics successfully completed. - */ - if (((port_task_file & AHCI_TFD_ERR_MASK) - >> AHCI_TFD_ERR_SHIFT) == 0x1) { -#if AHCI_DEBUG - port_signature = ddi_get32( - ahci_ctlp->ahcictl_ahci_acc_handle, - (uint32_t *)AHCI_PORT_PxSIG(ahci_ctlp, port)); - AHCIDBG2(AHCIDBG_INFO, ahci_ctlp, - "COMRESET success, D2H register FIS " - "post to received FIS structure " - "port %d signature = 0x%x", - port, port_signature); -#endif - goto out_check; - } + /* Wait for 10 millisec */ + delay(AHCI_10MS_TICKS); if (loop_count++ > AHCI_POLLRATE_PORT_TFD_ERROR) { /* * We are effectively timing out after 11 sec. */ + cmn_err(CE_WARN, "!ahci%d: ahci_port_reset port %d " + "the device hardware has been initialized and " + "the power-up diagnostics failed", + instance, port); + + AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: " + "port %d PxTFD.STS.ERR is not set, we need another " + "software reset.", port); + + /* Clear port serror register for the port */ + ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle, + (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port), + AHCI_SERROR_CLEAR_ALL); + + /* Try another software reset. */ + if (ahci_software_reset(ahci_ctlp, ahci_portp, + port) != AHCI_SUCCESS) { + ahci_portp->ahciport_port_state |= + SATA_PSTATE_FAILED; + return (AHCI_FAILURE); + } break; } - /* Wait for 10 millisec */ - delay(AHCI_10MS_TICKS); + /* + * The Error bit '1' means COMRESET is finished successfully + * The device hardware has been initialized and the power-up + * diagnostics successfully completed. The device requests + * that the Transport layer transmit a Register - D2H FIS to + * the host. (SATA spec 11.5, v2.6) + */ + port_task_file = + ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, + (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port)); } while (((port_task_file & AHCI_TFD_ERR_MASK) - >> AHCI_TFD_ERR_SHIFT) != 0x1); + >> AHCI_TFD_ERR_SHIFT) != AHCI_TFD_ERR_SGS); - AHCIDBG3(AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: 2nd loop " - "count: %d, port_task_file = 0x%x port %d", + AHCIDBG3(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp, + "ahci_port_reset: 2nd loop count: %d, " + "port_task_file = 0x%x port %d", loop_count, port_task_file, port); - cmn_err(CE_WARN, "!ahci%d: ahci_port_reset port %d the device hardware " - "has been initialized and the power-up diagnostics failed", - instance, port); - - ahci_portp->ahciport_port_state |= SATA_PSTATE_FAILED; - rval = AHCI_FAILURE; - -out: /* Clear port serror register for the port */ ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port), AHCI_SERROR_CLEAR_ALL); - return (rval); + /* Set port as ready */ + ahci_portp->ahciport_port_state |= SATA_STATE_READY; -out_check: - /* - * Check device status, if keep busy or COMRESET error - * do device reset to patch some SATA disks' issue - * - * For VT8251, sometimes need to do the device reset - */ - if ((port_task_file & AHCI_TFD_STS_BSY) || - (port_task_file & AHCI_TFD_STS_DRQ)) { - AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "port %d keep BSY/DRQ set " - "need to do device reset", port); - - (void) ahci_software_reset(ahci_ctlp, ahci_portp, port); - - port_task_file = - ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, - (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port)); - - if (port_task_file & AHCI_TFD_STS_BSY || - port_task_file & AHCI_TFD_STS_DRQ) { - cmn_err(CE_WARN, "!ahci%d: ahci_port_reset: port %d " - "BSY/DRQ still set after device reset " - "port_task_file = 0x%x", instance, - port, port_task_file); - ahci_portp->ahciport_port_state |= SATA_PSTATE_FAILED; - rval = AHCI_FAILURE; - } - } - - goto out; + AHCIDBG1(AHCIDBG_INFO|AHCIDBG_ERRS, ahci_ctlp, + "ahci_port_reset: succeed at port %d.", port); + return (AHCI_SUCCESS); } /* @@ -3734,9 +3822,12 @@ ahci_hba_reset(ahci_ctl_t *ahci_ctlp) /* * This routine is only called from AHCI_ATTACH or phyrdy change - * case. It first calls port reset to initialize port, probe port and probe - * device, then try to read PxSIG register to find the type of device - * attached to the port. + * case. It first calls software reset, then stop the port and try to + * read PxSIG register to find the type of device attached to the port. + * + * The caller should make sure a valid device exists on specified port and + * physical communication has been established so that the signature could + * be retrieved by software reset. * * WARNING!!! ahciport_mutex should be acquired before the function * is called. And the port interrupt is disabled. @@ -3752,24 +3843,29 @@ ahci_find_dev_signature(ahci_ctl_t *ahci_ctlp, ahci_portp->ahciport_device_type = SATA_DTYPE_UNKNOWN; - /* Call port reset to check link status and get device signature */ - (void) ahci_port_reset(ahci_ctlp, ahci_portp, port); - - if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) { + /* Issue a software reset to get the signature */ + if (ahci_software_reset(ahci_ctlp, ahci_portp, port) + != AHCI_SUCCESS) { AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, - "ahci_find_dev_signature: No device is found " - "at port %d", port); + "ahci_find_dev_signature: software reset failed " + "at port %d. cannot get signature.", port); + ahci_portp->ahciport_port_state = SATA_PSTATE_FAILED; return; } - /* Check the port state */ - if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED) { - AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp, - "ahci_find_dev_signature: port %d state 0x%x", - port, ahci_portp->ahciport_port_state); + /* + * ahci_software_reset has started the port, so we need manually stop + * the port again. + */ + if (ahci_put_port_into_notrunning_state(ahci_ctlp, ahci_portp, port) + != AHCI_SUCCESS) { + AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, + "ahci_find_dev_signature: cannot stop port %d.", port); + ahci_portp->ahciport_port_state = SATA_PSTATE_FAILED; return; } + /* Now we can make sure that a valid signature is received. */ signature = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)AHCI_PORT_PxSIG(ahci_ctlp, port)); @@ -3893,6 +3989,9 @@ ahci_start_port(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, uint8_t port) ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_STARTED; + AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port: " + "PxCMD.ST set to '1' at port %d", port); + return (AHCI_SUCCESS); } @@ -5085,6 +5184,7 @@ ahci_intr_phyrdy_change(ahci_ctl_t *ahci_ctlp, "device link established", port); /* A new device has been detected. */ + (void) ahci_port_reset(ahci_ctlp, ahci_portp, port); ahci_find_dev_signature(ahci_ctlp, ahci_portp, port); /* Try to start the port */ @@ -6001,13 +6101,12 @@ ahci_put_port_into_notrunning_state(ahci_ctl_t *ahci_ctlp, * The fifth argument returns whether the port reset is involved during * the process. * - * The routine will be called under six scenarios: - * 1. Initialize the port - * 2. To abort the packet(s) - * 3. To reset the port - * 4. To activate the port - * 5. Fatal error recovery - * 6. To abort the timeout packet(s) + * The routine will be called under following scenarios: + * + To abort the packet(s) + * + To reset the port + * + To activate the port + * + Fatal error recovery + * + To abort the timeout packet(s) * * WARNING!!! ahciport_mutex should be acquired before the function * is called. And ahciport_mutex will be released before the reset @@ -6039,8 +6138,7 @@ ahci_restart_port_wait_till_ready(ahci_ctl_t *ahci_ctlp, AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, "ahci_restart_port_wait_till_ready: port %d enter", port); - if ((flag != AHCI_PORT_INIT) && - (ahci_portp->ahciport_device_type != SATA_DTYPE_NONE)) + if (ahci_portp->ahciport_device_type != SATA_DTYPE_NONE) dev_exists_begin = 1; /* First clear PxCMD.ST */ @@ -6112,10 +6210,6 @@ reset: } out: - /* Start the port if not in initialization phase */ - if (flag & AHCI_PORT_INIT) - return (rval); - (void) ahci_start_port(ahci_ctlp, ahci_portp, port); /* SStatus tells the presence of device. */ diff --git a/usr/src/uts/common/sys/sata/adapters/ahci/ahcireg.h b/usr/src/uts/common/sys/sata/adapters/ahci/ahcireg.h index 52027b6cbf..8eec6f9167 100644 --- a/usr/src/uts/common/sys/sata/adapters/ahci/ahcireg.h +++ b/usr/src/uts/common/sys/sata/adapters/ahci/ahcireg.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -210,6 +210,7 @@ extern "C" { #define AHCI_TFD_STS_DRQ (0x1 << 3) #define AHCI_TFD_STS_ERR (0x1 << 0) #define AHCI_TFD_ERR_SHIFT 8 +#define AHCI_TFD_ERR_SGS (0x1 << 0) /* DDR1: Send_good_status */ #define AHCI_SERROR_CLEAR_ALL 0xffffffff diff --git a/usr/src/uts/common/sys/sata/adapters/ahci/ahcivar.h b/usr/src/uts/common/sys/sata/adapters/ahci/ahcivar.h index ed6280d763..0804f09cde 100644 --- a/usr/src/uts/common/sys/sata/adapters/ahci/ahcivar.h +++ b/usr/src/uts/common/sys/sata/adapters/ahci/ahcivar.h @@ -212,6 +212,7 @@ typedef struct ahci_ctl { * AHCI_CAP_NCQ * AHCI_CAP_PM * AHCI_CAP_32BIT_DMA + * AHCI_CAP_SCLO */ int ahcictl_cap; @@ -284,11 +285,12 @@ _NOTE(MUTEX_PROTECTS_DATA(ahci_ctl_t::ahcictl_mutex, #define AHCI_CAP_PM 0x8 /* 32-bit DMA addressing */ #define AHCI_CAP_32BIT_DMA 0x10 +/* Supports Command List Override */ +#define AHCI_CAP_SCLO 0x20 /* Flags controlling the restart port behavior */ #define AHCI_PORT_RESET 0x0001 /* Reset the port */ -#define AHCI_PORT_INIT 0x0002 /* Initialize port */ -#define AHCI_RESET_NO_EVENTS_UP 0x0004 /* Don't send reset events up */ +#define AHCI_RESET_NO_EVENTS_UP 0x0002 /* Don't send reset events up */ #define ERR_RETRI_CMD_IN_PROGRESS(ahci_portp) \ (ahci_portp->ahciport_flags & \ @@ -323,7 +325,9 @@ _NOTE(MUTEX_PROTECTS_DATA(ahci_ctl_t::ahcictl_mutex, #define AHCI_10MS_TICKS (drv_usectohz(10000)) /* ticks in 10 ms */ #define AHCI_1MS_TICKS (drv_usectohz(1000)) /* ticks in 1 ms */ #define AHCI_100US_TICKS (drv_usectohz(100)) /* ticks in 100 us */ -#define AHCI_1MS_USECS (1000) /* usecs in 1 millisec */ +#define AHCI_10MS_USECS (10000) /* microsecs in 10 millisec */ +#define AHCI_1MS_USECS (1000) /* microsecs in 1 millisec */ +#define AHCI_100US_USECS (100) /* * The following values are the numbers of times to retry polled requests. @@ -364,7 +368,7 @@ _NOTE(MUTEX_PROTECTS_DATA(ahci_ctl_t::ahcictl_mutex, #define AHCIDBG_UNDERFLOW 0x10000 #define AHCIDBG_MSI 0x20000 -extern int ahci_debug_flag; +extern uint32_t ahci_debug_flags; #define AHCIDBG0(flag, ahci_ctlp, format) \ if (ahci_debug_flags & (flag)) { \ |