diff options
author | eivind <eivind@FreeBSD.org> | 1998-08-05 00:54:38 +0000 |
---|---|---|
committer | eivind <eivind@FreeBSD.org> | 1998-08-05 00:54:38 +0000 |
commit | f03826546dda8a7ceb4654dd24f3c23547bf5a30 (patch) | |
tree | 0665db6870e7ad529c2e975ebe1ced2688d8c652 /sys/dev/dpt | |
parent | 926810dcee72cabf9aeb2364563cd63a890a127b (diff) | |
download | FreeBSD-src-f03826546dda8a7ceb4654dd24f3c23547bf5a30.zip FreeBSD-src-f03826546dda8a7ceb4654dd24f3c23547bf5a30.tar.gz |
Update DPT driver from 1.4.3 to 1.4.5
Submitted by: Simon Shapiro <shimon@simon-shapiro.org>
Diffstat (limited to 'sys/dev/dpt')
-rw-r--r-- | sys/dev/dpt/dpt_control.c | 97 | ||||
-rw-r--r-- | sys/dev/dpt/dpt_pci.c | 33 | ||||
-rw-r--r-- | sys/dev/dpt/dpt_scsi.c | 323 |
3 files changed, 294 insertions, 159 deletions
diff --git a/sys/dev/dpt/dpt_control.c b/sys/dev/dpt/dpt_control.c index f85c744..6de9f47 100644 --- a/sys/dev/dpt/dpt_control.c +++ b/sys/dev/dpt/dpt_control.c @@ -36,7 +36,7 @@ * future. */ -#ident "$Id: dpt_control.c,v 1.6 1998/06/07 17:09:42 dfr Exp $" +#ident "$Id: dpt_control.c,v 1.7 1998/07/13 09:52:51 bde Exp $" #include "opt_dpt.h" @@ -67,8 +67,6 @@ static vm_offset_t dpt_physmap(u_int32_t paddr, vm_size_t size); static void dpt_unphysmap(u_int8_t * vaddr, vm_size_t size); static void dpt_get_sysinfo(void); -static INLINE dpt_softc_t *dpt_minor2softc(int minor_no); -static INLINE int dpt_minor2unit(int minor_no); static int dpt_open(dev_t dev, int flags, int fmt, struct proc * p); static int dpt_close(dev_t dev, int flags, int fmt, struct proc * p); @@ -102,6 +100,52 @@ NULL, -1}; static struct buf *dpt_inbuf[DPT_MAX_ADAPTERS]; static char dpt_rw_command[DPT_MAX_ADAPTERS][DPT_RW_CMD_LEN + 1]; +#ifdef DPT_MEASURE_PERFORMANCE +void +dpt_reset_performance(dpt_softc_t *dpt) +{ + int ndx; + + /* Zero out all command counters */ + bzero(&dpt->performance, sizeof(dpt_perf_t)); + for ( ndx = 0; ndx < 256; ndx ++ ) + dpt->performance.min_command_time[ndx] = BIG_ENOUGH; + + dpt->performance.min_intr_time = BIG_ENOUGH; + dpt->performance.min_waiting_time = BIG_ENOUGH; + dpt->performance.min_submit_time = BIG_ENOUGH; + dpt->performance.min_complete_time = BIG_ENOUGH; + dpt->performance.min_eata_tries = BIG_ENOUGH; + + for (ndx = 0; ndx < 10; ndx++ ) { + dpt->performance.read_by_size_min_time[ndx] = BIG_ENOUGH; + dpt->performance.write_by_size_min_time[ndx] = BIG_ENOUGH; + } + +} + +#endif /* DPT_MEASURE_PERFORMANCE */ + +/** + * Given a minor device number, + * return the pointer to its softc structure + */ + +dpt_softc_t * +dpt_minor2softc(int minor_no) +{ + dpt_softc_t *dpt; + + if (dpt_minor2unit(minor_no & ~SCSI_CONTROL_MASK) == -1) + return (NULL); + + for (dpt = TAILQ_FIRST(&dpt_softc_list); + (dpt != NULL) && (dpt->unit != (minor_no & ~SCSI_CONTROL_MASK)); + dpt = TAILQ_NEXT(dpt, links)); + + return (dpt); +} + /** * Map a physical address to virtual one. * This is a first cut, experimental thing @@ -160,40 +204,6 @@ dpt_unphysmap(u_int8_t * vaddr, vm_size_t size) } /** - * Given a minor device number, get its SCSI Unit. - */ - -static INLINE int -dpt_minor2unit(int minor) -{ - int unit; - - unit = minor2hba(minor & ~SCSI_CONTROL_MASK); - - return (unit); -} - -/** - * Given a minor device number, - * return the pointer to its softc structure - */ - -static INLINE dpt_softc_t * -dpt_minor2softc(int minor_no) -{ - dpt_softc_t *dpt; - - if (dpt_minor2unit(minor_no & ~SCSI_CONTROL_MASK) == -1) - return (NULL); - - for (dpt = TAILQ_FIRST(&dpt_softc_list); - (dpt != NULL) && (dpt->unit != (minor_no & ~SCSI_CONTROL_MASK)); - dpt = TAILQ_NEXT(dpt, links)); - - return (dpt); -} - -/** * Collect interesting system information * The following is one of the worst hacks I have ever allowed my * name to be associated with. @@ -620,7 +630,7 @@ dpt_read(dev_t dev, struct uio * uio, int ioflag) wbp += x; } else if (strcmp(command, DPT_RW_CMD_CLEAR_METRICS) == 0) { #ifdef DPT_MEASURE_PERFORMANCE - bzero(&dpt->performance, sizeof(dpt->performance)); + dpt_reset_performance(dpt); #endif /* DPT_MEASURE_PERFORMANCE */ x = sprintf(wbp, "dpt%d: Metrics have been cleared\n", @@ -628,9 +638,6 @@ dpt_read(dev_t dev, struct uio * uio, int ioflag) work_size += x; wbp += x; } else if (strcmp(command, DPT_RW_CMD_SHOW_LED) == 0) { -#ifdef DPT_MEASURE_PERFORMANCE - bzero(&dpt->performance, sizeof(dpt->performance)); -#endif /* DPT_MEASURE_PERFORMANCE */ x = sprintf(wbp, "dpt%d:%s\n", dpt->unit, i2bin(dpt_blinking_led(dpt), 8)); @@ -697,8 +704,8 @@ dpt_ioctl(dev_t dev, u_long cmd, caddr_t cmdarg, int flags, struct proc * p) switch (cmd) { #ifdef DPT_MEASURE_PERFORMANCE - case DPT_IOCTL_INTERNAL_METRICS: - (void) memcpy(cmdarg, (char *) &dpt->performance, sizeof(dpt_perf_t)); + case DPT_IOCTL_INTERNAL_METRICS: + memcpy(cmdarg, &dpt->performance, sizeof(dpt->performance)); return (0); #endif /* DPT_MEASURE_PERFORMANCE */ case DPT_IOCTL_SOFTC: @@ -757,7 +764,7 @@ dpt_ioctl(dev_t dev, u_long cmd, caddr_t cmdarg, int flags, struct proc * p) udpt.cache_type = dpt->cache_type; udpt.cache_size = dpt->cache_size; - (void) memcpy(cmdarg, (char *) &udpt, sizeof(dpt_user_softc_t)); + memcpy(cmdarg, &udpt, sizeof(dpt_user_softc_t)); return (0); case SDI_SEND: case DPT_IOCTL_SEND: @@ -821,9 +828,7 @@ dpt_ioctl(dev_t dev, u_long cmd, caddr_t cmdarg, int flags, struct proc * p) (caddr_t *) eata_pass_thru->command_buffer, sizeof(dpt_sysinfo))); case EATAUSRCMD: - printf("%d\n", __LINE__); result = dpt_user_cmd(dpt, eata_pass_thru, cmdarg, minor_no); - printf("%d\n", __LINE__); return (result); case DPT_BLINKLED: result = dpt_blinking_led(dpt); diff --git a/sys/dev/dpt/dpt_pci.c b/sys/dev/dpt/dpt_pci.c index 11d02d7..f171c8a 100644 --- a/sys/dev/dpt/dpt_pci.c +++ b/sys/dev/dpt/dpt_pci.c @@ -34,7 +34,7 @@ * caveats: We may need an eisa and an isa files too */ -#ident "$Id: dpt_pci.c,v 1.5 1998/03/11 00:30:16 julian Exp $" +#ident "$Id: dpt_pci.c,v 1.6 1998/06/02 00:32:38 eivind Exp $" #include "opt_devfs.h" #include "opt_dpt.h" @@ -213,21 +213,7 @@ dpt_pci_attach(pcici_t config_id, int unit) dpt->commands_processed = 0; #ifdef DPT_MEASURE_PERFORMANCE - /* Zero out all command counters */ - bzero((void *)&dpt->performance, sizeof(dpt_perf_t)); - for ( ndx = 0; ndx < 256; ndx ++ ) - dpt->performance.min_command_time[ndx] = BIG_ENOUGH; - - dpt->performance.min_intr_time = BIG_ENOUGH; - dpt->performance.min_waiting_time = BIG_ENOUGH; - dpt->performance.min_submit_time = BIG_ENOUGH; - dpt->performance.min_complete_time = BIG_ENOUGH; - dpt->performance.min_eata_tries = BIG_ENOUGH; - - for (ndx = 0; ndx < 10; ndx++ ) { - dpt->performance.read_by_size_min_time[ndx] = BIG_ENOUGH; - dpt->performance.write_by_size_min_time[ndx] = BIG_ENOUGH; - } + dpt_reset_performance(dpt); #endif /* DPT_MEASURE_PERFORMANCE */ dpt->unit = unit; @@ -481,14 +467,13 @@ dpt_pci_attach(pcici_t config_id, int unit) * We never get the entries made. */ #ifdef DEVFS - dpt->devfs_data_token = devfs_add_devswf(&dpt_cdevsw, dpt->unit, DV_CHR, - UID_ROOT, GID_WHEEL, 0600, - "dpt%d", dpt->unit); - dpt->devfs_ctl_token = devfs_add_devswf(&dpt_cdevsw, - dpt->unit | SCSI_CONTROL_MASK, - DV_CHR, - UID_ROOT, GID_WHEEL, 0600, - "dpt%d.ctl", dpt->unit); + (void) devfs_add_devswf(&dpt_cdevsw, dpt->unit, DV_CHR, + UID_ROOT, GID_WHEEL, 0600, + "dpt%d", dpt->unit); + (void) devfs_add_devswf(&dpt_cdevsw, dpt->unit | SCSI_CONTROL_MASK, + DV_CHR, + UID_ROOT, GID_WHEEL, 0600, + "dpt%d.ctl", dpt->unit); #endif } } diff --git a/sys/dev/dpt/dpt_scsi.c b/sys/dev/dpt/dpt_scsi.c index 8f50f58..a0a2cc6 100644 --- a/sys/dev/dpt/dpt_scsi.c +++ b/sys/dev/dpt/dpt_scsi.c @@ -37,9 +37,9 @@ * Last but not least, many thanx to UCB and the FreeBSD * team for creating and maintaining such a wonderful O/S. * - * TODO: * Add EISA and ISA probe code. + * TODO: * Add ISA probe code. * * Add driver-level RSID-0. This will allow interoperability with - * NiceTry, M$-Doze, Win-Dog, Slowlaris, etc. in recognizing RAID + * NiceTry, M$-Doze, Win-Dog, Slowlaris, etc., in recognizing RAID * arrays that span controllers (Wow!). */ @@ -64,7 +64,8 @@ * 3. dpt_handle_timeouts potentially inserts into the queue */ -#ident "$Id: dpt_scsi.c,v 1.6 1998/06/02 00:32:38 eivind Exp $" +#ident "$Id: dpt_scsi.c,v 1.32 1998/08/03 16:45:12 root Exp root $" + #define _DPT_C_ #include "opt_dpt.h" @@ -83,6 +84,13 @@ #include <vm/vm.h> #include <vm/pmap.h> +/* The HBA reset option uses the same timer as the lost IRQ option*/ +#ifdef DPT_RESET_HBA +#ifndef DPT_LOST_IRQ +#define DPT_LOST_IRQ +#endif +#endif + #include <sys/dpt.h> #ifdef INLINE @@ -98,6 +106,8 @@ int dpt_controllers_present = 0; /* Function Prototypes */ +#define microtime_now dpt_time_now() + static INLINE u_int32_t dpt_inl(dpt_softc_t * dpt, u_int32_t offset); static INLINE u_int8_t dpt_inb(dpt_softc_t * dpt, u_int32_t offset); static INLINE void @@ -368,6 +378,117 @@ dpt_raid_busy(dpt_softc_t * dpt) return (0); } +#ifdef DPT_RESET_HBA + +/* +** Function name : dpt_reset_hba +** +** Description : Reset the HBA and properly discard all pending work +** Input : Minor Device Number +** Output : Nothing +*/ + +static void +dpt_reset_hba(int minor) +{ + dpt_softc_t *dpt; + eata_ccb_t *ccb; + int ospl; + dpt_ccb_t dccb, *dccbp; + int result; + struct scsi_xfer *xs; + + if ((dpt = dpt_minor2softc(minor)) == NULL) { + printf("DPT: Ignoring invalid minor %d in dpt_reset_hba\n", minor); + return; + } + + /* Prepare a control block. The SCSI command part is immaterial */ + dccb.xs = NULL; + dccb.flags = 0; + dccb.state = DPT_CCB_STATE_NEW; + dccb.std_callback = NULL; + dccb.wrbuff_callback = NULL; + + ccb = &dccb.eata_ccb; + ccb->CP_OpCode = EATA_CMD_RESET; + ccb->SCSI_Reset = 0; + ccb->HBA_Init = 1; + ccb->Auto_Req_Sen = 1; + ccb->cp_id = 0; /* Should be ignored */ + ccb->DataIn = 1; + ccb->DataOut = 0; + ccb->Interpret = 1; + ccb->reqlen = htonl(sizeof(struct scsi_sense_data)); + ccb->cp_statDMA = htonl(vtophys(&ccb->cp_statDMA)); + ccb->cp_reqDMA = htonl(vtophys(&ccb->cp_reqDMA)); + ccb->cp_viraddr = (u_int32_t) & ccb; + + ccb->cp_msg[0] = HA_IDENTIFY_MSG | HA_DISCO_RECO; + ccb->cp_scsi_cmd = 0; /* Should be ignored */ + + /* Lock up the submitted queue. We are very persistant here */ + ospl = splcam(); + while (dpt->queue_status & DPT_SUBMITTED_QUEUE_ACTIVE) { + DELAY(100); + } + + dpt->queue_status |= DPT_SUBMITTED_QUEUE_ACTIVE; + splx(ospl); + + /* Send the RESET message */ + if ((result = dpt_send_eata_command(dpt, &dccb.eata_ccb, + EATA_CMD_RESET, 0, 0, 0, 0)) != 0) { + printf("dpt%d: Failed to send the RESET message.\n" + " Trying cold boot (ouch!)\n", dpt->unit); + + + if ((result = dpt_send_eata_command(dpt, &dccb.eata_ccb, + EATA_COLD_BOOT, 0, 0, 0, 0)) + != 0) { + panic("dpt%d: Faild to cold boot the HBA\n", dpt->unit); + } +#ifdef DPT_MEASURE_PERFORMANCE + dpt->performance.cold_boots++; +#endif /* DPT_MEASURE_PERFORMANCE */ + } + +#ifdef DPT_MEASURE_PERFORMANCE + dpt->performance.warm_starts++; +#endif /* DPT_MEASURE_PERFORMANCE */ + + printf("dpt%d: Aborting pending requests. O/S should re-submit\n", + dpt->unit); + + while ((dccbp = TAILQ_FIRST(&dpt->completed_ccbs)) != NULL) { + struct scsi_xfer *xs = dccbp->xs; + + /* Not all transactions have xs structs */ + if (xs != NULL) { + /* Tell the kernel proper this did not complete well */ + xs->error |= XS_SELTIMEOUT; + xs->flags |= SCSI_ITSDONE; + scsi_done(xs); + } + + dpt_Qremove_submitted(dpt, dccbp); + + /* Remember, Callbacks are NOT in the standard queue */ + if (dccbp->std_callback != NULL) { + (dccbp->std_callback) (dpt, dccbp->eata_ccb.cp_channel, dccbp); + } else { + ospl = splcam(); + dpt_Qpush_free(dpt, dccbp); + splx(ospl); + } + } + + printf("dpt%d: reset done aborting all pending commands\n", dpt->unit); + dpt->queue_status &= ~DPT_SUBMITTED_QUEUE_ACTIVE; +} + +#endif /* DPT_RESET_HBA */ + /** * Build a Command Block for target mode READ/WRITE BUFFER, * with the ``sync'' bit ON. @@ -438,8 +559,6 @@ dpt_target_ccb(dpt_softc_t * dpt, int bus, u_int8_t target, u_int8_t lun, /* Setup a target mode READ command */ -#define cmd_ct dpt->performance.command_count[(int)ccb->eata_ccb.cp_scsi_cmd]; - static void dpt_set_target(int redo, dpt_softc_t * dpt, u_int8_t bus, u_int8_t target, u_int8_t lun, int mode, @@ -447,10 +566,6 @@ dpt_set_target(int redo, dpt_softc_t * dpt, { int ospl; -#ifdef DPT_MEASURE_PERFORMANCE - struct timeval now; -#endif - if (dpt->target_mode_enabled) { ospl = splcam(); @@ -461,9 +576,8 @@ dpt_set_target(int redo, dpt_softc_t * dpt, ccb->transaction_id = ++dpt->commands_processed; #ifdef DPT_MEASURE_PERFORMANCE - ++cmd_ct; - microtime(&now); - ccb->command_started = now; + dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd]++; + ccb->command_started = microtime_now; #endif dpt_Qadd_waiting(dpt, ccb); dpt_sched_queue(dpt); @@ -477,11 +591,11 @@ dpt_set_target(int redo, dpt_softc_t * dpt, /** * Schedule a buffer to be sent to another target. - * The work will be scheduled and the callback provided will be called when the work is - * actually done. + * The work will be scheduled and the callback provided will be called when + * the work is actually done. * - * Please NOTE: ``Anyone'' can send a buffer, but only registered clients get notified - of receipt of buffers. + * Please NOTE: ``Anyone'' can send a buffer, but only registered clients + * get notified of receipt of buffers. */ int @@ -498,9 +612,6 @@ dpt_send_buffer(int unit, dpt_softc_t *dpt; dpt_ccb_t *ccb = NULL; int ospl; -#ifdef DPT_MEASURE_PERFORMANCE - struct timeval now; -#endif /* This is an external call. Be a bit paranoid */ for (dpt = TAILQ_FIRST(&dpt_softc_list); @@ -540,18 +651,17 @@ valid_unit: splx(ospl); bcopy(dpt->rw_buffer[channel][target][lun] + offset, data, length); - dpt_target_ccb(dpt, channel, target, lun, ccb, mode, SCSI_TM_WRITE_BUFFER, - length, offset); - ccb->std_callback = (ccb_callback) callback; /* A hack. Potential - * trouble */ + dpt_target_ccb(dpt, channel, target, lun, ccb, mode, + SCSI_TM_WRITE_BUFFER, + length, offset); + ccb->std_callback = (ccb_callback) callback; /* Potential trouble */ ospl = splcam(); ccb->transaction_id = ++dpt->commands_processed; #ifdef DPT_MEASURE_PERFORMANCE - ++cmd_ct; - microtime(&now); - ccb->command_started = now; + dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd]++; + ccb->command_started = microtime_now; #endif dpt_Qadd_waiting(dpt, ccb); dpt_sched_queue(dpt); @@ -748,9 +858,9 @@ dpt_send_eata_command(dpt_softc_t * dpt, eata_ccb_t * cmd_block, u_int8_t result; u_int32_t test; u_int32_t swapped_cmdaddr; - + if (!retries) - retries = 1000; + retries = 10000; /* * I hate this polling nonsense. Wish there was a way to tell the DPT @@ -780,6 +890,11 @@ dpt_send_eata_command(dpt_softc_t * dpt, eata_ccb_t * cmd_block, return (1); } + /* The controller is alive, advance the wedge timer */ +#ifdef DPT_RESET_HBA + dpt->last_contact = microtime_now; +#endif + if (cmd_block != NULL) { swapped_cmdaddr = vtophys(cmd_block); @@ -865,7 +980,6 @@ dpt_user_cmd(dpt_softc_t * dpt, eata_pt_t * user_cmd, int submitted; dpt_ccb_t *ccb; void *data; - struct timeval now; data = NULL; channel = minor2hba(minor_no); @@ -1013,9 +1127,8 @@ dpt_user_cmd(dpt_softc_t * dpt, eata_pt_t * user_cmd, ccb->data = data; #ifdef DPT_MEASURE_PERFORMANCE - ++dpt->performance.command_count[(int) ccb->eata_ccb.cp_scsi_cmd]; - microtime(&now); - ccb->command_started = now; + ++dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd]; + ccb->command_started = microtime_now; #endif ospl = splcam(); dpt_Qadd_waiting(dpt, ccb); @@ -1851,6 +1964,11 @@ dpt_scsi_cmd(struct scsi_xfer * xs) ospl = splcam(); if ((dpt->state & DPT_LOST_IRQ_SET) == 0) { printf("dpt%d: Initializing Lost IRQ Timer\n", dpt->unit); +#ifdef DPT_RESET_HBA + printf("dpt%d: HBA will reset if irresponsive for %d seconds\n", + dpt->unit, DPT_RESET_HBA); + dpt->last_contact = microtime_now; +#endif dpt->state |= DPT_LOST_IRQ_SET; timeout(dpt_irq_timeout, dpt, hz); } @@ -2109,13 +2227,20 @@ dpt_scsi_cmd(struct scsi_xfer * xs) if ((status & HA_SERROR) || (ndx == xs->timeout)) { xs->error = XS_DRIVER_STUFFUP; } +#ifdef DPT_RESET_HBA + else { + /* + * We received a reply and did not time out. + * Advance the wedge counter. + */ + dpt->last_contact = microtime_now; + } +#endif /* DPT_RESET_HBA */ dpt_Qpush_free(dpt, ccb); splx(ospl); return (COMPLETE); } else { - struct timeval junk; - /** * Not a polled command. * The command can be queued normally. @@ -2129,10 +2254,8 @@ dpt_scsi_cmd(struct scsi_xfer * xs) ccb->transaction_id = ++dpt->commands_processed; #ifdef DPT_MEASURE_PERFORMANCE -#define cmd_ndx (int)ccb->eata_ccb.cp_scsi_cmd - ++dpt->performance.command_count[cmd_ndx]; - microtime(&junk); - ccb->command_started = junk; + ++dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd]; + ccb->command_started = microtime_now; #endif dpt_Qadd_waiting(dpt, ccb); splx(ospl); @@ -2275,12 +2398,7 @@ dpt_intr(void *arg) #endif #ifdef DPT_MEASURE_PERFORMANCE - { - struct timeval junk; - - microtime(&junk); - dpt->performance.intr_started = junk; - } + dpt->performance.intr_started = microtime_now; #endif /* First order of business is to check if this interrupt is for us */ @@ -2297,12 +2415,17 @@ dpt_intr(void *arg) #endif return; } + + /* The controller is alive, advance the wedge timer */ +#ifdef DPT_RESET_HBA + dpt->last_contact = microtime_now; +#endif + if (!dpt->handle_interrupts) { #ifdef DPT_MEASURE_PERFORMANCE ++dpt->performance.aborted_interrupts; #endif - status = dpt_inb(dpt, HA_RSTATUS); /* This CLEARS - * interrupts */ + status = dpt_inb(dpt, HA_RSTATUS); /* This CLEARS interrupts! */ return; } /** @@ -2332,12 +2455,10 @@ dpt_intr(void *arg) #ifdef DPT_HANDLE_TIMEOUTS if (dccb->state & DPT_CCB_STATE_MARKED_LOST) { - struct timeval now; u_int32_t age; struct scsi_xfer *xs = dccb->xs; - microtime(&now); - age = dpt_time_delta(dccb->command_started, now); + age = dpt_time_delta(dccb->command_started, microtime_now); printf("dpt%d: Salvaging Tx %d from the jaws of destruction " "(%d/%d)\n", @@ -2484,11 +2605,8 @@ dpt_intr(void *arg) #ifdef DPT_MEASURE_PERFORMANCE { u_int32_t result; - struct timeval junk; - microtime(&junk); - - result = dpt_time_delta(dpt->performance.intr_started, junk); + result = dpt_time_delta(dpt->performance.intr_started, microtime_now); if (result != ~0) { if (dpt->performance.max_intr_time < result) @@ -2595,14 +2713,13 @@ dpt_complete(dpt_softc_t * dpt) #ifdef DPT_MEASURE_PERFORMANCE { u_int32_t result; - struct timeval junk; - microtime(&junk); - ccb->command_ended = junk; #define time_delta dpt_time_delta(ccb->command_started, ccb->command_ended) - result = time_delta; #define maxctime dpt->performance.max_command_time[ccb->eata_ccb.cp_scsi_cmd] #define minctime dpt->performance.min_command_time[ccb->eata_ccb.cp_scsi_cmd] + + ccb->command_ended = microtime_now; + result = time_delta; if (result != ~0) { if (maxctime < result) { @@ -2689,7 +2806,7 @@ dpt_process_completion(dpt_softc_t * dpt, struct scsi_rw_big *cmd; int op_type; - cmd = (struct scsi_rw_big *) & ccb->eata_ccb.cp_scsi_cmd; + cmd = (struct scsi_rw_big *) &ccb->eata_ccb.cp_scsi_cmd; switch (cmd->op_code) { case 0xa8: /* 12-byte READ */ @@ -2865,6 +2982,10 @@ dpt_process_completion(dpt_softc_t * dpt, * basis. * It is a completely ugly hack which purpose is to handle the problem of * missing interrupts on certain platforms.. + * + * An additional task is to optionally check if the controller is wedged. + * A wedeged controller is one which has not accepted a command, nor sent + * an interrupt in the last DPT_RESET_HBA seconds. */ static void @@ -2883,6 +3004,34 @@ dpt_irq_timeout(void *arg) printf("dpt %d: %d lost Interrupts Recovered\n", dpt->unit, ++dpt->lost_interrupts); } +#ifdef DPT_RESET_HBA + { + int max_wedge, contact_delta; + + if (TAILQ_EMPTY(&dpt->waiting_ccbs)) { + dpt->last_contact = microtime_now; + } else { + /* If nothing is waiting, we cannot assume we are wedged */ + if (DPT_RESET_HBA < 1) + max_wedge = 1000000; + else + max_wedge = 1000000 * DPT_RESET_HBA; + + contact_delta = dpt_time_delta(dpt->last_contact, + microtime_now); + + if (contact_delta > max_wedge) { + printf("dpt%d: Appears wedged for %d.%d (%d.0)seconds.\n" + " Resetting\n", + dpt->unit, contact_delta/1000000, + (contact_delta % 1000000) / 100000, + DPT_RESET_HBA); + dpt_reset_hba(dpt); + } + } + } +#endif /* DPT_RESET_HBA */ + dpt->state &= ~DPT_LOST_IRQ_ACTIVE; } timeout(dpt_irq_timeout, (caddr_t) dpt, hz * 1); @@ -2933,13 +3082,10 @@ dpt_handle_timeouts(dpt_softc_t * dpt) ccb != NULL; ccb = TAILQ_NEXT(ccb, links)) { struct scsi_xfer *xs; - struct timeval now; u_int32_t age, max_age; xs = ccb->xs; - - microtime(&now); - age = dpt_time_delta(ccb->command_started, now); + age = dpt_time_delta(ccb->command_started, microtime_now); #define TenSec 10000000 @@ -3054,10 +3200,8 @@ dpt_Qremove_completed(dpt_softc_t * dpt, dpt_ccb_t * ccb) { #ifdef DPT_MEASURE_PERFORMANCE u_int32_t complete_time; - struct timeval now; - microtime(&now); - complete_time = dpt_time_delta(ccb->command_ended, now); + complete_time = dpt_time_delta(ccb->command_ended, microtime_now); if (complete_time != ~0) { if (dpt->performance.max_complete_time < complete_time) @@ -3102,7 +3246,7 @@ static INLINE_Q void dpt_Qpush_free(dpt_softc_t * dpt, dpt_ccb_t * ccb) { #ifdef DPT_FREELIST_IS_STACK - TAILQ_INSERT_HEAD(&dpt->free_ccbs, ccb, links); + TAILQ_INSERT_HEAD(&dpt->free_ccbs, ccb, links) #else TAILQ_INSERT_TAIL(&dpt->free_ccbs, ccb, links); #endif @@ -3116,14 +3260,11 @@ dpt_Qpush_free(dpt_softc_t * dpt, dpt_ccb_t * ccb) static INLINE_Q void dpt_Qadd_waiting(dpt_softc_t * dpt, dpt_ccb_t * ccb) { - struct timeval junk; - TAILQ_INSERT_TAIL(&dpt->waiting_ccbs, ccb, links); ++dpt->waiting_ccbs_count; #ifdef DPT_MEASURE_PERFORMANCE - microtime(&junk); - ccb->command_ended = junk; + ccb->command_ended = microtime_now; if (dpt->waiting_ccbs_count > dpt->performance.max_waiting_count) dpt->performance.max_waiting_count = dpt->waiting_ccbs_count; #endif @@ -3138,14 +3279,11 @@ dpt_Qadd_waiting(dpt_softc_t * dpt, dpt_ccb_t * ccb) static INLINE_Q void dpt_Qpush_waiting(dpt_softc_t * dpt, dpt_ccb_t * ccb) { - struct timeval junk; - TAILQ_INSERT_HEAD(&dpt->waiting_ccbs, ccb, links); ++dpt->waiting_ccbs_count; #ifdef DPT_MEASURE_PERFORMANCE - microtime(&junk); - ccb->command_ended = junk; + ccb->command_ended = microtime_now; if (dpt->performance.max_waiting_count < dpt->waiting_ccbs_count) dpt->performance.max_waiting_count = dpt->waiting_ccbs_count; @@ -3163,11 +3301,9 @@ static INLINE_Q void dpt_Qremove_waiting(dpt_softc_t * dpt, dpt_ccb_t * ccb) { #ifdef DPT_MEASURE_PERFORMANCE - struct timeval now; u_int32_t waiting_time; - microtime(&now); - waiting_time = dpt_time_delta(ccb->command_ended, now); + waiting_time = dpt_time_delta(ccb->command_ended, microtime_now); if (waiting_time != ~0) { if (dpt->performance.max_waiting_time < waiting_time) @@ -3190,14 +3326,11 @@ dpt_Qremove_waiting(dpt_softc_t * dpt, dpt_ccb_t * ccb) static INLINE_Q void dpt_Qadd_submitted(dpt_softc_t * dpt, dpt_ccb_t * ccb) { - struct timeval junk; - TAILQ_INSERT_TAIL(&dpt->submitted_ccbs, ccb, links); ++dpt->submitted_ccbs_count; #ifdef DPT_MEASURE_PERFORMANCE - microtime(&junk); - ccb->command_ended = junk; + ccb->command_ended = microtime_now; if (dpt->performance.max_submit_count < dpt->submitted_ccbs_count) dpt->performance.max_submit_count = dpt->submitted_ccbs_count; #endif @@ -3212,14 +3345,11 @@ dpt_Qadd_submitted(dpt_softc_t * dpt, dpt_ccb_t * ccb) static INLINE_Q void dpt_Qadd_completed(dpt_softc_t * dpt, dpt_ccb_t * ccb) { - struct timeval junk; - TAILQ_INSERT_TAIL(&dpt->completed_ccbs, ccb, links); ++dpt->completed_ccbs_count; #ifdef DPT_MEASURE_PERFORMANCE - microtime(&junk); - ccb->command_ended = junk; + ccb->command_ended = microtime_now; if (dpt->performance.max_complete_count < dpt->completed_ccbs_count) dpt->performance.max_complete_count = dpt->completed_ccbs_count; @@ -3236,11 +3366,9 @@ static INLINE_Q void dpt_Qremove_submitted(dpt_softc_t * dpt, dpt_ccb_t * ccb) { #ifdef DPT_MEASURE_PERFORMANCE - struct timeval now; u_int32_t submit_time; - microtime(&now); - submit_time = dpt_time_delta(ccb->command_ended, now); + submit_time = dpt_time_delta(ccb->command_ended, microtime_now); if (submit_time != ~0) { ccb->submitted_time = submit_time; @@ -3336,11 +3464,26 @@ checkit: /** * What we do for a shutdown, is give the DPT early power loss * warning - . */ + */ +#ifdef DPT_SHUTDOWN_SLEEP + DELAY(DPT_SHUTDOWN_SLEEP * 1000); + + if (dpt->state & DPT_HA_SHUTDOWN_ACTIVE) { + ospl = splcam(); + dpt->state &= ~DPT_HA_SHUTDOWN_ACTIVE; + splx(ospl); + printf("dpt%d: WARNING: After sleeping for %d seconds, " + "I am re-enabled\n", + dpt->unit); + printf(" Any further I/O is NOT guranteed to " + "complete!\n"); + } +#else (void) dpt_send_immediate(dpt, NULL, EATA_POWER_OFF_WARN, 0, 0); printf("dpt%d: Controller was warned of shutdown and is now " "disabled\n", dpt->unit); +#endif return; } @@ -3692,3 +3835,5 @@ scsi_cmd_name(u_int8_t cmd) * c++-friend-offset: 0 * End: */ + + |