Mercurial > illumos > illumos-gate
changeset 12609:2e69f035b60b
6957836 assertion failure in ahci_mop_commands
author | ying tian - Beijing China <Ying.Tian@Sun.COM> |
---|---|
date | Fri, 11 Jun 2010 10:44:25 +0800 |
parents | 708c1594201d |
children | 5daa5746f6ae |
files | usr/src/uts/common/io/sata/adapters/ahci/ahci.c usr/src/uts/common/sys/sata/adapters/ahci/ahcivar.h |
diffstat | 2 files changed, 142 insertions(+), 67 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/io/sata/adapters/ahci/ahci.c Thu Jun 10 18:47:15 2010 -0700 +++ b/usr/src/uts/common/io/sata/adapters/ahci/ahci.c Fri Jun 11 10:44:25 2010 +0800 @@ -154,6 +154,8 @@ static void ahci_copy_ncq_err_page(sata_cmd_t *, struct sata_ncq_error_recovery_page *); static void ahci_copy_out_regs(sata_cmd_t *, ahci_fis_d2h_register_t *); +static void ahci_add_doneq(ahci_port_t *, sata_pkt_t *, int); +static void ahci_flush_doneq(ahci_port_t *); static int ahci_software_reset(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *); static int ahci_hba_reset(ahci_ctl_t *); @@ -348,8 +350,8 @@ }; /* The following variables are watchdog handler related */ -static int ahci_watchdog_timeout = 5; /* 5 seconds */ -static int ahci_watchdog_tick; +static clock_t ahci_watchdog_timeout = 5; /* 5 seconds */ +static clock_t ahci_watchdog_tick; /* * This static variable indicates the size of command table, @@ -1831,27 +1833,6 @@ } } -#define SENDUP_PACKET(ahci_portp, satapkt, reason) \ - if (satapkt) { \ - satapkt->satapkt_reason = reason; \ - /* \ - * We set the satapkt_reason in both sync and \ - * non-sync cases. \ - */ \ - } \ - if (satapkt && \ - ! (satapkt->satapkt_op_mode & SATA_OPMODE_SYNCH) && \ - satapkt->satapkt_comp) { \ - mutex_exit(&ahci_portp->ahciport_mutex); \ - (*satapkt->satapkt_comp)(satapkt); \ - mutex_enter(&ahci_portp->ahciport_mutex); \ - } else { \ - if (satapkt && \ - (satapkt->satapkt_op_mode & SATA_OPMODE_SYNCH) && \ - ! (satapkt->satapkt_op_mode & SATA_OPMODE_POLLING)) \ - cv_broadcast(&ahci_portp->ahciport_cv); \ - } - /* * Searches for and claims a free command slot. * @@ -2309,10 +2290,18 @@ ahci_portp->ahciport_slot_pkts[cmd_slot] = spkt; /* - * We are overloading satapkt_hba_driver_private with - * watched_cycle count. - */ - spkt->satapkt_hba_driver_private = (void *)(intptr_t)0; + * Keep the timeout value + */ + ahci_portp->ahciport_slot_timeout[cmd_slot] = spkt->satapkt_time; + + /* + * If the intial timout is less than 1 tick, then make it longer by + * 1 tick to avoid immediate timeout + */ + if (ahci_portp->ahciport_slot_timeout[cmd_slot] <= + ahci_watchdog_timeout) + ahci_portp->ahciport_slot_timeout[cmd_slot] += + ahci_watchdog_timeout; #if AHCI_DEBUG if (ahci_debug_flags & AHCIDBG_ATACMD && @@ -6069,6 +6058,11 @@ if (ahci_portp->ahciport_event_args == NULL) goto err_case4; + /* Initialize the done queue */ + ahci_portp->ahciport_doneq = NULL; + ahci_portp->ahciport_doneqtail = &ahci_portp->ahciport_doneq; + ahci_portp->ahciport_doneq_len = 0; + mutex_exit(&ahci_portp->ahciport_mutex); return (AHCI_SUCCESS); @@ -6830,7 +6824,7 @@ "ahci_intr_cmd_cmplt: sending up pkt 0x%p " "with SATA_PKT_COMPLETED", (void *)satapkt); - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_COMPLETED); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED); goto out; } @@ -6852,7 +6846,7 @@ ahci_copy_out_regs(&satapkt->satapkt_cmd, rcvd_fisp); } - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_COMPLETED); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED); goto out; } @@ -6938,13 +6932,15 @@ CLEAR_BIT(finished_tags, finished_slot); ahci_portp->ahciport_slot_pkts[finished_slot] = NULL; - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_COMPLETED); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED); } out: AHCIDBG(AHCIDBG_PKTCOMP, ahci_ctlp, "ahci_intr_cmd_cmplt: pending_tags = 0x%x", ahci_portp->ahciport_pending_tags); + ahci_flush_doneq(ahci_portp); + mutex_exit(&ahci_portp->ahciport_mutex); return (AHCI_SUCCESS); @@ -7108,7 +7104,7 @@ CLEAR_BIT(finished_tags, finished_slot); ahci_portp->ahciport_slot_pkts[finished_slot] = NULL; - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_COMPLETED); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED); } out: AHCIDBG(AHCIDBG_PKTCOMP|AHCIDBG_NCQ, ahci_ctlp, @@ -7117,6 +7113,8 @@ port, ahci_portp->ahciport_pending_ncq_tags, ahci_portp->ahciport_pending_tags); + ahci_flush_doneq(ahci_portp); + mutex_exit(&ahci_portp->ahciport_mutex); return (AHCI_SUCCESS); @@ -8813,7 +8811,7 @@ CLEAR_BIT(finished_tags, tmp_slot); ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL; - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_COMPLETED); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED); } /* Send up failed packets with SATA_PKT_DEV_ERROR. */ @@ -8826,7 +8824,7 @@ AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " "sending up pkt 0x%p with SATA_PKT_DEV_ERROR", (void *)satapkt); - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_DEV_ERROR); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_DEV_ERROR); break; } if (rdwr_pmult_cmd_in_progress) { @@ -8836,7 +8834,7 @@ "ahci_mop_commands: sending up " "rdwr pmult pkt 0x%p with SATA_PKT_DEV_ERROR", (void *)satapkt); - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_DEV_ERROR); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_DEV_ERROR); break; } @@ -8859,7 +8857,7 @@ CLEAR_BIT(failed_tags, tmp_slot); ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL; - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_DEV_ERROR); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_DEV_ERROR); } /* Send up timeout packets with SATA_PKT_TIMEOUT. */ @@ -8872,7 +8870,7 @@ AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " "sending up pkt 0x%p with SATA_PKT_TIMEOUT", (void *)satapkt); - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_TIMEOUT); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_TIMEOUT); break; } if (rdwr_pmult_cmd_in_progress) { @@ -8882,7 +8880,7 @@ "ahci_mop_commands: sending up " "rdwr pmult pkt 0x%p with SATA_PKT_TIMEOUT", (void *)satapkt); - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_TIMEOUT); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_TIMEOUT); break; } @@ -8905,7 +8903,7 @@ CLEAR_BIT(timeout_tags, tmp_slot); ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL; - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_TIMEOUT); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_TIMEOUT); } /* Send up aborted packets with SATA_PKT_ABORTED */ @@ -8918,7 +8916,7 @@ AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: " "sending up pkt 0x%p with SATA_PKT_ABORTED", (void *)satapkt); - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_ABORTED); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_ABORTED); break; } if (rdwr_pmult_cmd_in_progress) { @@ -8929,7 +8927,7 @@ "ahci_mop_commands: sending up " "rdwr pmult pkt 0x%p with SATA_PKT_ABORTED", (void *)satapkt); - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_ABORTED); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_ABORTED); break; } @@ -8952,7 +8950,7 @@ CLEAR_BIT(aborted_tags, tmp_slot); ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL; - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_ABORTED); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_ABORTED); } /* Send up reset packets with SATA_PKT_RESET. */ @@ -8965,7 +8963,7 @@ "ahci_mop_commands: sending up " "rdwr pmult pkt 0x%p with SATA_PKT_RESET", (void *)satapkt); - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_RESET); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_RESET); break; } @@ -8988,7 +8986,7 @@ CLEAR_BIT(reset_tags, tmp_slot); ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL; - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_RESET); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_RESET); } /* Send up unfinished packets with SATA_PKT_RESET */ @@ -9012,7 +9010,7 @@ CLEAR_BIT(unfinished_tags, tmp_slot); ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL; - SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_RESET); + ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_RESET); } ahci_portp->ahciport_mop_in_progress--; @@ -9020,6 +9018,8 @@ if (ahci_portp->ahciport_mop_in_progress == 0) ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_MOPPING; + + ahci_flush_doneq(ahci_portp); } /* @@ -9708,11 +9708,6 @@ int current_slot; uint32_t current_tags; int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip); - /* max number of cycles this packet should survive */ - int max_life_cycles; - - /* how many cycles this packet survived so far */ - int watched_cycles; mutex_enter(&ahci_ctlp->ahcictl_mutex); @@ -9779,24 +9774,15 @@ if ((spkt != NULL) && spkt->satapkt_time && !(spkt->satapkt_op_mode & SATA_OPMODE_POLLING)) { /* - * We are overloading satapkt_hba_driver_private - * with watched_cycle count. - * * If a packet has survived for more than it's * max life cycles, it is a candidate for time * out. */ - watched_cycles = (int)(intptr_t) - spkt->satapkt_hba_driver_private; - watched_cycles++; - max_life_cycles = (spkt->satapkt_time + - ahci_watchdog_timeout - 1) / + ahci_portp->ahciport_slot_timeout[tmp_slot] -= ahci_watchdog_timeout; - spkt->satapkt_hba_driver_private = - (void *)(intptr_t)watched_cycles; - - if (watched_cycles <= max_life_cycles) + if (ahci_portp->ahciport_slot_timeout[tmp_slot] + > 0) goto next; #if AHCI_DEBUG @@ -9820,8 +9806,8 @@ (tmp_slot != current_slot) || NCQ_CMD_IN_PROGRESS(ahci_portp) && ((0x1 << tmp_slot) & current_tags)) { - spkt->satapkt_hba_driver_private = - (void *)(intptr_t)0; + ahci_portp->ahciport_slot_timeout \ + [tmp_slot] = spkt->satapkt_time; } else { timeout_tags |= (0x1 << tmp_slot); cmn_err(CE_WARN, "!ahci%d: watchdog " @@ -10193,3 +10179,72 @@ return (DDI_SUCCESS); } + +/* + * The function will add a sata packet to the done queue. + * + * WARNING!!! ahciport_mutex should be acquired before the function + * is called. + */ +static void +ahci_add_doneq(ahci_port_t *ahci_portp, sata_pkt_t *satapkt, int reason) +{ + ASSERT(satapkt != NULL); + + /* set the reason for all packets */ + satapkt->satapkt_reason = reason; + satapkt->satapkt_hba_driver_private = NULL; + + if (! (satapkt->satapkt_op_mode & SATA_OPMODE_SYNCH) && + satapkt->satapkt_comp) { + /* + * only add to queue when mode is not synch and there is + * completion callback + */ + *ahci_portp->ahciport_doneqtail = satapkt; + ahci_portp->ahciport_doneqtail = + (sata_pkt_t **)&(satapkt->satapkt_hba_driver_private); + ahci_portp->ahciport_doneq_len ++; + + } else if ((satapkt->satapkt_op_mode & SATA_OPMODE_SYNCH) && + ! (satapkt->satapkt_op_mode & SATA_OPMODE_POLLING)) + /* + * for sync/non-poll mode, just call cv_broadcast + */ + cv_broadcast(&ahci_portp->ahciport_cv); +} + +/* + * The function will call completion callback of sata packet on the + * completed queue + * + * WARNING!!! ahciport_mutex should be acquired before the function + * is called. + */ +static void +ahci_flush_doneq(ahci_port_t *ahci_portp) +{ + sata_pkt_t *satapkt, *next; + + if (ahci_portp->ahciport_doneq) { + satapkt = ahci_portp->ahciport_doneq; + + ahci_portp->ahciport_doneq = NULL; + ahci_portp->ahciport_doneqtail = &ahci_portp->ahciport_doneq; + ahci_portp->ahciport_doneq_len = 0; + + mutex_exit(&ahci_portp->ahciport_mutex); + + while (satapkt != NULL) { + next = satapkt->satapkt_hba_driver_private; + satapkt->satapkt_hba_driver_private = NULL; + + /* Call the callback */ + (*satapkt->satapkt_comp)(satapkt); + + satapkt = next; + } + + mutex_enter(&ahci_portp->ahciport_mutex); + } +}
--- a/usr/src/uts/common/sys/sata/adapters/ahci/ahcivar.h Thu Jun 10 18:47:15 2010 -0700 +++ b/usr/src/uts/common/sys/sata/adapters/ahci/ahcivar.h Fri Jun 11 10:44:25 2010 +0800 @@ -156,17 +156,17 @@ * AHCI_PORT_FLAG_NODEV: this flag will be set when a device is found gone * during ahci_restart_port_wait_till_ready process. * - * AHCI_PORT_FLAG_RDWR_PMULT: this flags will be set when a READ/WRITE + * AHCI_PORT_FLAG_RDWR_PMULT: this flag will be set when a READ/WRITE * PORTMULT command is being executed. * - * AHCI_PORT_FLAG_IGNORE_IPMS: this flags will be set when enumerating a port + * AHCI_PORT_FLAG_IGNORE_IPMS: this flag will be set when enumerating a port * multiplier. According AHCI spec, IPMS error should be ignore during * enumeration of port multiplier. * - * AHCI_PORT_FLAG_PMULT_SNTF: this flags will be set when the a asynchronous + * AHCI_PORT_FLAG_PMULT_SNTF: this flag will be set when the a asynchronous * notification event on the port multiplier is being handled. * - * AHCI_PORT_FLAG_HOTPLUG: this flags will be set when a hot plug event is + * AHCI_PORT_FLAG_HOTPLUG: this flag will be set when a hot plug event is * being handled. */ #define AHCI_PORT_FLAG_SPINUP 0x01 @@ -249,6 +249,18 @@ /* Keep all the pending sata packets */ sata_pkt_t *ahciport_slot_pkts[AHCI_PORT_MAX_CMD_SLOTS]; + /* Used to check whether corresponding packet is timeout */ + int ahciport_slot_timeout[AHCI_PORT_MAX_CMD_SLOTS]; + + /* Queue of completed (done) sata packet */ + sata_pkt_t *ahciport_doneq; + + /* Pointer of the tail of completed sata packet queue */ + sata_pkt_t **ahciport_doneqtail; + + /* the length of the completed sata packet queue */ + uint32_t ahciport_doneq_len; + /* Keep the byte count of all PRD entries for every sata packet */ uint32_t \ ahciport_prd_bytecounts[AHCI_PORT_MAX_CMD_SLOTS]; @@ -292,6 +304,14 @@ _NOTE(MUTEX_PROTECTS_DATA(ahci_port_t::ahciport_mutex, ahci_port_t::ahciport_slot_pkts)) _NOTE(MUTEX_PROTECTS_DATA(ahci_port_t::ahciport_mutex, + ahci_port_t::ahciport_slot_timeout)) +_NOTE(MUTEX_PROTECTS_DATA(ahci_port_t::ahciport_mutex, + ahci_port_t::ahciport_doneq)) +_NOTE(MUTEX_PROTECTS_DATA(ahci_port_t::ahciport_mutex, + ahci_port_t::ahciport_doneqtail)) +_NOTE(MUTEX_PROTECTS_DATA(ahci_port_t::ahciport_mutex, + ahci_port_t::ahciport_doneq_len)) +_NOTE(MUTEX_PROTECTS_DATA(ahci_port_t::ahciport_mutex, ahci_port_t::ahciport_reset_in_progress)) _NOTE(MUTEX_PROTECTS_DATA(ahci_port_t::ahciport_mutex, ahci_port_t::ahciport_mop_in_progress))