diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 85944b938637..1f9521dc6d8d 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2,7 +2,7 @@ # LINT -- config file for checking all the sources, tries to pull in # as much of the source tree as it can. # -# $Id: LINT,v 1.448 1998/08/03 19:14:31 msmith Exp $ +# $Id: LINT,v 1.449 1998/08/04 21:44:08 brian Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -1560,6 +1560,10 @@ options SPX_HACK # The 'dpt' driver provides support for DPT controllers (http://www.dpt.com/). # These have hardware RAID-{0,1,5} support, and do multi-initiator I/O. +# The DPT controllers are commonly re-licensed under other brand-names - +# some controllers by Olivetti, Dec, HP, AT&T, SNI, AST, Alphatronic, NEC and +# Compaq are actually DPT controllers. +# # See sys/dev/dpt for debugging and other subtle options. # DPT_VERIFY_HINTR Performs some strict hardware interrupts testing. # Only use if you suspect PCI bus corruption problems @@ -1569,9 +1573,9 @@ options SPX_HACK # slots to exactly what the DPT can hold at one time, # enable this option. # DPT_MEASURE_PERFORMANCE Enables a set of (semi)invasive metrics. Various -# instruments are enabled. Assumed to be enabled by -# /usr/sbin/dpt_* tools. -# DPT_FREELIST_IS_STACK For optimat L{1,2} CPU cache utilization, enable +# instruments are enabled. The tools in +# /usr/sbin/dpt_* assume these to be enabled. +# DPT_FREELIST_IS_STACK For optimal L{1,2} CPU cache utilization, enable # this option. Otherwise, the transaction queue is # a LIFO. I cannot measure the performance gain. # DPT_HANDLE_TIMEOUTS Normally device timeouts are handled by the DPT. @@ -1585,6 +1589,15 @@ options SPX_HACK # any interrupt that got lost. Seems to help in some # DPT-firmware/Motherboard combinations. Minimal # cost, great benefit. +# DPT_RESET_HBA Make "reset" actually reset the controller +# instead of fudging it. Only enable this if you +# are 100% certain you need it. +# DPT_SHUTDOWN_SLEEP Reset controller if a request take more than +# this number of seconds. Do NOT enable this +# unless you are really, really, really certain +# you need it. You are advised to call Simon (the +# driver author) before setting it, and NEVER, +# EVER set it to less than 300s (5 minutes). controller dpt0 @@ -1597,3 +1610,8 @@ options DPT_HANDLE_TIMEOUTS options DPT_TIMEOUT_FACTOR=4 options DPT_INTR_DELAY=200 # Some motherboards need that options DPT_LOST_IRQ +options DPT_RESET_HBA + +# Don't EVER set this without having talked to Simon Shapiro on the phone +# first. +options DPT_SHUTDOWN_SLEEP=500 diff --git a/sys/conf/options b/sys/conf/options index 315ad27d3722..e2b0d84bb36e 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -1,4 +1,4 @@ -# $Id: options,v 1.87 1998/07/06 04:55:22 julian Exp $ +# $Id: options,v 1.88 1998/07/12 01:48:14 bde Exp $ # # On the handling of kernel options # @@ -192,15 +192,17 @@ IPFILTER_LKM opt_ipfilter.h NATM opt_natm.h # DPT driver debug flags -DPT_VERIFY_HINTR opt_dpt.h -DPT_USE_SINTR opt_dpt.h -DPT_RESTRICTED_FREELIST opt_dpt.h -DPT_MEASURE_PERFORMANCE opt_dpt.h -DPT_FREELIST_IS_STACK opt_dpt.h -DPT_HANDLE_TIMEOUTS opt_dpt.h -DPT_TIMEOUT_FACTOR opt_dpt.h +DPT_VERIFY_HINTR opt_dpt.h +DPT_USE_SINTR opt_dpt.h +DPT_RESTRICTED_FREELIST opt_dpt.h +DPT_MEASURE_PERFORMANCE opt_dpt.h +DPT_FREELIST_IS_STACK opt_dpt.h +DPT_HANDLE_TIMEOUTS opt_dpt.h +DPT_TIMEOUT_FACTOR opt_dpt.h DPT_INTR_DELAY opt_dpt.h DPT_LOST_IRQ opt_dpt.h +DPT_SHUTDOWN_SLEEP opt_dpt.h +DPT_RESET_HBA opt_dpt.h # Misc debug flags. Most of these should probably be replaced with # 'DEBUG', and then let people recompile just the interesting modules diff --git a/sys/dev/dpt/dpt_control.c b/sys/dev/dpt/dpt_control.c index f85c7440e7bb..6de9f475eccd 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 @@ -159,40 +203,6 @@ dpt_unphysmap(u_int8_t * vaddr, vm_size_t size) kmem_free(kernel_map, (vm_offset_t) vaddr, 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 @@ -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 11d02d7c9fbd..f171c8a983ee 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 8f50f58ab09a..a0a2cc61d67c 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 #include +/* 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 #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: */ + + diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index 85944b938637..1f9521dc6d8d 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -2,7 +2,7 @@ # LINT -- config file for checking all the sources, tries to pull in # as much of the source tree as it can. # -# $Id: LINT,v 1.448 1998/08/03 19:14:31 msmith Exp $ +# $Id: LINT,v 1.449 1998/08/04 21:44:08 brian Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -1560,6 +1560,10 @@ options SPX_HACK # The 'dpt' driver provides support for DPT controllers (http://www.dpt.com/). # These have hardware RAID-{0,1,5} support, and do multi-initiator I/O. +# The DPT controllers are commonly re-licensed under other brand-names - +# some controllers by Olivetti, Dec, HP, AT&T, SNI, AST, Alphatronic, NEC and +# Compaq are actually DPT controllers. +# # See sys/dev/dpt for debugging and other subtle options. # DPT_VERIFY_HINTR Performs some strict hardware interrupts testing. # Only use if you suspect PCI bus corruption problems @@ -1569,9 +1573,9 @@ options SPX_HACK # slots to exactly what the DPT can hold at one time, # enable this option. # DPT_MEASURE_PERFORMANCE Enables a set of (semi)invasive metrics. Various -# instruments are enabled. Assumed to be enabled by -# /usr/sbin/dpt_* tools. -# DPT_FREELIST_IS_STACK For optimat L{1,2} CPU cache utilization, enable +# instruments are enabled. The tools in +# /usr/sbin/dpt_* assume these to be enabled. +# DPT_FREELIST_IS_STACK For optimal L{1,2} CPU cache utilization, enable # this option. Otherwise, the transaction queue is # a LIFO. I cannot measure the performance gain. # DPT_HANDLE_TIMEOUTS Normally device timeouts are handled by the DPT. @@ -1585,6 +1589,15 @@ options SPX_HACK # any interrupt that got lost. Seems to help in some # DPT-firmware/Motherboard combinations. Minimal # cost, great benefit. +# DPT_RESET_HBA Make "reset" actually reset the controller +# instead of fudging it. Only enable this if you +# are 100% certain you need it. +# DPT_SHUTDOWN_SLEEP Reset controller if a request take more than +# this number of seconds. Do NOT enable this +# unless you are really, really, really certain +# you need it. You are advised to call Simon (the +# driver author) before setting it, and NEVER, +# EVER set it to less than 300s (5 minutes). controller dpt0 @@ -1597,3 +1610,8 @@ options DPT_HANDLE_TIMEOUTS options DPT_TIMEOUT_FACTOR=4 options DPT_INTR_DELAY=200 # Some motherboards need that options DPT_LOST_IRQ +options DPT_RESET_HBA + +# Don't EVER set this without having talked to Simon Shapiro on the phone +# first. +options DPT_SHUTDOWN_SLEEP=500 diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 85944b938637..1f9521dc6d8d 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -2,7 +2,7 @@ # LINT -- config file for checking all the sources, tries to pull in # as much of the source tree as it can. # -# $Id: LINT,v 1.448 1998/08/03 19:14:31 msmith Exp $ +# $Id: LINT,v 1.449 1998/08/04 21:44:08 brian Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -1560,6 +1560,10 @@ options SPX_HACK # The 'dpt' driver provides support for DPT controllers (http://www.dpt.com/). # These have hardware RAID-{0,1,5} support, and do multi-initiator I/O. +# The DPT controllers are commonly re-licensed under other brand-names - +# some controllers by Olivetti, Dec, HP, AT&T, SNI, AST, Alphatronic, NEC and +# Compaq are actually DPT controllers. +# # See sys/dev/dpt for debugging and other subtle options. # DPT_VERIFY_HINTR Performs some strict hardware interrupts testing. # Only use if you suspect PCI bus corruption problems @@ -1569,9 +1573,9 @@ options SPX_HACK # slots to exactly what the DPT can hold at one time, # enable this option. # DPT_MEASURE_PERFORMANCE Enables a set of (semi)invasive metrics. Various -# instruments are enabled. Assumed to be enabled by -# /usr/sbin/dpt_* tools. -# DPT_FREELIST_IS_STACK For optimat L{1,2} CPU cache utilization, enable +# instruments are enabled. The tools in +# /usr/sbin/dpt_* assume these to be enabled. +# DPT_FREELIST_IS_STACK For optimal L{1,2} CPU cache utilization, enable # this option. Otherwise, the transaction queue is # a LIFO. I cannot measure the performance gain. # DPT_HANDLE_TIMEOUTS Normally device timeouts are handled by the DPT. @@ -1585,6 +1589,15 @@ options SPX_HACK # any interrupt that got lost. Seems to help in some # DPT-firmware/Motherboard combinations. Minimal # cost, great benefit. +# DPT_RESET_HBA Make "reset" actually reset the controller +# instead of fudging it. Only enable this if you +# are 100% certain you need it. +# DPT_SHUTDOWN_SLEEP Reset controller if a request take more than +# this number of seconds. Do NOT enable this +# unless you are really, really, really certain +# you need it. You are advised to call Simon (the +# driver author) before setting it, and NEVER, +# EVER set it to less than 300s (5 minutes). controller dpt0 @@ -1597,3 +1610,8 @@ options DPT_HANDLE_TIMEOUTS options DPT_TIMEOUT_FACTOR=4 options DPT_INTR_DELAY=200 # Some motherboards need that options DPT_LOST_IRQ +options DPT_RESET_HBA + +# Don't EVER set this without having talked to Simon Shapiro on the phone +# first. +options DPT_SHUTDOWN_SLEEP=500 diff --git a/sys/pci/dpt_pci.c b/sys/pci/dpt_pci.c index 11d02d7c9fbd..f171c8a983ee 100644 --- a/sys/pci/dpt_pci.c +++ b/sys/pci/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/sys/dpt.h b/sys/sys/dpt.h index b780875ebb88..3bc1c8d0a816 100644 --- a/sys/sys/dpt.h +++ b/sys/sys/dpt.h @@ -40,7 +40,7 @@ */ -#ident "$Id: dpt.h,v 1.2 1998/04/15 17:47:28 bde Exp $" +#ident "$Id: dpt.h,v 1.3 1998/06/02 00:32:37 eivind Exp $" #ifndef _DPT_H #define _DPT_H @@ -63,14 +63,14 @@ extern u_long dpt_unit; #define DPT_RELEASE 1 #define DPT_VERSION 4 -#define DPT_PATCH 3 -#define DPT_MONTH 6 -#define DPT_DAY 1 +#define DPT_PATCH 5 +#define DPT_MONTH 8 +#define DPT_DAY 3 #define DPT_YEAR 18 /* 1998 - 1980 */ #define DPT_CTL_RELEASE 1 #define DPT_CTL_VERSION 0 -#define DPT_CTL_PATCH 5 +#define DPT_CTL_PATCH 6 #ifndef PAGESIZ #define PAGESIZ 4096 @@ -229,6 +229,8 @@ typedef void *physaddr; #define EATA_CMD_PIO_TRUNC 0xf4 #define EATA_CMD_RESET 0xf9 +#define EATA_COLD_BOOT 0x06 /* Last resort only! */ + #define EATA_CMD_IMMEDIATE 0xfa #define EATA_CMD_DMA_READ_CONFIG 0xfd @@ -452,88 +454,88 @@ typedef struct eata_register { /* EATA register set */ * Everything back. */ typedef struct get_conf { /* Read Configuration Array */ - union { - struct { - u_int8_t foo_DevType; - u_int8_t foo_PageCode; - u_int8_t foo_Reserved0; - u_int8_t foo_len; - } foo; - u_int32_t foo_length; /* Should return 0x22, 0x24, etc */ - } bar; + union { + struct { + u_int8_t foo_DevType; + u_int8_t foo_PageCode; + u_int8_t foo_Reserved0; + u_int8_t foo_len; + } foo; + u_int32_t foo_length; /* Should return 0x22, 0x24, etc */ + } bar; #define gcs_length bar.foo_length #define gcs_PageCode bar.foo.foo_DevType #define gcs_reserved0 bar.foo.foo_Reserved0 #define gcs_len bar.foo.foo_len - u_int32_t signature; /* Signature MUST be "EATA". ntohl()`ed */ + u_int32_t signature; /* Signature MUST be "EATA". ntohl()`ed */ - u_int8_t version2:4, - version:4; /* EATA Version level */ + u_int8_t version2:4, + version:4; /* EATA Version level */ - u_int8_t OCS_enabled:1, /* Overlap Command Support enabled */ - TAR_support:1, /* SCSI Target Mode supported */ - TRNXFR:1, /* - * Truncate Transfer Cmd not necessary Only - * used in PIO Mode - */ - MORE_support:1, /* MORE supported (only PIO Mode) */ - DMA_support:1, /* DMA supported Driver uses only this mode */ - DMA_valid:1, /* DRQ value in Byte 30 is valid */ - ATA:1, /* ATA device connected (not supported) */ - HAA_valid:1; /* Hostadapter Address is valid */ + u_int8_t OCS_enabled:1, /* Overlap Command Support enabled */ + TAR_support:1, /* SCSI Target Mode supported */ + TRNXFR:1, /* + * Truncate Transfer Cmd not necessary Only + * used in PIO Mode + */ + MORE_support:1, /* MORE supported (only PIO Mode) */ + DMA_support:1, /* DMA supported Driver uses only this mode */ + DMA_valid:1, /* DRQ value in Byte 30 is valid */ + ATA:1, /* ATA device connected (not supported) */ + HAA_valid:1; /* Hostadapter Address is valid */ - u_int16_t cppadlen; /* - * Number of pad bytes send after CD data set - * to zero for DMA commands. Ntohl()`ed - */ - u_int8_t scsi_idS; /* SCSI ID of controller 2-0 Byte 0 res. */ - u_int8_t scsi_id2; /* If not, zero is returned */ - u_int8_t scsi_id1; - u_int8_t scsi_id0; - u_int32_t cplen; /* CP length: number of valid cp bytes */ + u_int16_t cppadlen; /* + * Number of pad bytes send after CD data set + * to zero for DMA commands. Ntohl()`ed + */ + u_int8_t scsi_idS; /* SCSI ID of controller 2-0 Byte 0 res. */ + u_int8_t scsi_id2; /* If not, zero is returned */ + u_int8_t scsi_id1; + u_int8_t scsi_id0; + u_int32_t cplen; /* CP length: number of valid cp bytes */ - u_int32_t splen; /* - * Number of bytes returned after we receive - * SP command - */ - u_int16_t queuesiz; /* max number of queueable CPs */ + u_int32_t splen; /* + * Number of bytes returned after we receive + * SP command + */ + u_int16_t queuesiz; /* max number of queueable CPs */ - u_int16_t dummy; - u_int16_t SGsiz; /* max number of SG table entrie */ + u_int16_t dummy; + u_int16_t SGsiz; /* max number of SG table entrie */ - u_int8_t IRQ:4, /* IRQ used this HBA */ - IRQ_TR:1, /* IRQ Trigger: 0=edge, 1=level */ - SECOND:1, /* This is a secondary controller */ - DMA_channel:2; /* DRQ index, DRQ is 2comp of DRQX */ + u_int8_t IRQ:4, /* IRQ used this HBA */ + IRQ_TR:1, /* IRQ Trigger: 0=edge, 1=level */ + SECOND:1, /* This is a secondary controller */ + DMA_channel:2; /* DRQ index, DRQ is 2comp of DRQX */ - u_int8_t sync; /* - * device at ID 7 tru 0 is running in - * synchronous mode, this will disappear - */ - u_int8_t DSBLE:1, /* ISA i/o addressing is disabled */ - FORCADR:1, /* i/o address has been forced */ - SG_64K:1, - SG_UAE:1,:4; + u_int8_t sync; /* + * device at ID 7 tru 0 is running in + * synchronous mode, this will disappear + */ + u_int8_t DSBLE:1, /* ISA i/o addressing is disabled */ + FORCADR:1, /* i/o address has been forced */ + SG_64K:1, + SG_UAE:1,:4; - u_int8_t MAX_ID:5, /* Max number of SCSI target IDs */ - MAX_CHAN:3; /* Number of SCSI busses on HBA */ + u_int8_t MAX_ID:5, /* Max number of SCSI target IDs */ + MAX_CHAN:3; /* Number of SCSI busses on HBA */ - u_int8_t MAX_LUN; /* Max number of LUNs */ - u_int8_t :3, - AUTOTRM:1, - M1_inst:1, - ID_qest:1, /* Raidnum ID is questionable */ - is_PCI:1, /* HBA is PCI */ - is_EISA:1; /* HBA is EISA */ + u_int8_t MAX_LUN; /* Max number of LUNs */ + u_int8_t :3, + AUTOTRM:1, + M1_inst:1, + ID_qest:1, /* Raidnum ID is questionable */ + is_PCI:1, /* HBA is PCI */ + is_EISA:1; /* HBA is EISA */ - u_int8_t RAIDNUM; /* unique HBA identifier */ - u_int8_t unused[4]; /* When doing PIO, you GET 512 bytes */ + u_int8_t RAIDNUM; /* unique HBA identifier */ + u_int8_t unused[4]; /* When doing PIO, you GET 512 bytes */ - /* >>------>> End of The DPT structure <<------<< */ + /* >>------>> End of The DPT structure <<------<< */ - u_int32_t length; /* True length, after ntohl conversion */ + u_int32_t length; /* True length, after ntohl conversion */ } dpt_conf_t; /* Scatter-Gather list entry */ @@ -1055,6 +1057,9 @@ typedef struct dpt_metrics { #define SIZE_OTHER 9 struct timeval intr_started; + + u_int32_t warm_starts; + u_int32_t cold_boots; } dpt_perf_t; #endif @@ -1186,14 +1191,13 @@ typedef struct dpt_softc { * This isi most visible with usr/sbin/dpt_softc(8) */ -#ifdef DEVFS - void *devfs_data_token; - void *devfs_ctl_token; -#endif #ifdef DPT_MEASURE_PERFORMANCE dpt_perf_t performance; #endif +#ifdef DPT_RESET_HBA + struct timeval last_contact; +#endif } dpt_softc_t; /* This structure is used to pass dpt_softc contents to userland via the @@ -1268,6 +1272,31 @@ typedef struct dpt_user_softc { * */ +#ifdef KERNEL +/* This function gets the current hi-res time and returns it to the caller */ +static __inline struct timeval +dpt_time_now(void) +{ + struct timeval now; + + microtime(&now); + return(now); +} + +/** + * Given a minor device number, get its SCSI Unit. + */ + +static __inline int +dpt_minor2unit(int minor) +{ + return(minor2hba(minor & ~SCSI_CONTROL_MASK)); +} + +dpt_softc_t *dpt_minor2softc(int minor_no); + +#endif /* KERNEL */ + /* * This function substracts one timval structure from another, * Returning the result in usec. @@ -1288,11 +1317,13 @@ dpt_time_delta(struct timeval start, return ( (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec) ); } + #ifndef _DPT_C_ extern TAILQ_HEAD(, dpt_softc) dpt_softc_list; extern int dpt_controllers_present; + extern void hex_dump(u_char * data, int length, char *name, int no); extern char *i2bin(unsigned int no, int length); @@ -1336,5 +1367,7 @@ extern int dpt_send_buffer(int unit, #endif /* _DPT_C_ */ +void dpt_reset_performance(dpt_softc_t *dpt); + #endif /* _DPT_H */ diff --git a/usr.sbin/dpt/dpt_ctlinfo/dpt_ctlinfo.c b/usr.sbin/dpt/dpt_ctlinfo/dpt_ctlinfo.c index 63073e869dd0..9a3e39b6161a 100644 --- a/usr.sbin/dpt/dpt_ctlinfo/dpt_ctlinfo.c +++ b/usr.sbin/dpt/dpt_ctlinfo/dpt_ctlinfo.c @@ -30,7 +30,7 @@ /* dpt_ctlinfo.c: Dunp a DPT HBA Information Block */ -#ident "$Id: dpt_ctlinfo.c,v 1.1 1998/01/22 23:32:27 ShimonR Exp ShimonR $" +#ident "$Id: dpt_ctlinfo.c,v 1.1 1998/01/26 06:20:37 julian Exp $" #include #include @@ -73,17 +73,19 @@ main(int argc, char **argv, char **argp) pass_thru.command_buffer = (u_int8_t *)&compat_softc; if ( (result = ioctl(fd, DPT_IOCTL_SEND, &pass_thru)) != 0 ) { - (void)fprintf(stderr, "%s ERROR: Failed to send IOCTL %x - %s\n", - argv[0], DPT_IOCTL_SEND, - strerror(errno)); + (void)fprintf(stderr, "%s ERROR: Failed to send IOCTL " + "%lx - %s\n", + argv[0], DPT_IOCTL_SEND, + strerror(errno)); exit(1); } (void)fprintf(stdout, "%x:", compat_softc.ha_state); for (ndx = 0; ndx < MAX_CHANNELS; ndx++) - (void)fprintf(stdout, (ndx == (MAX_CHANNELS - 1)) ? "%d:" : "%d,", - compat_softc.ha_id[ndx]); + (void)fprintf(stdout, (ndx == (MAX_CHANNELS - 1)) ? "%d:" : + "%d,", + compat_softc.ha_id[ndx]); (void)fprintf(stdout, "%d:", compat_softc.ha_vect); (void)fprintf(stdout, "%x:", compat_softc.ha_base); diff --git a/usr.sbin/dpt/dpt_ctls/dpt_ctls.c b/usr.sbin/dpt/dpt_ctls/dpt_ctls.c index d5ef550db106..3c66da50e386 100644 --- a/usr.sbin/dpt/dpt_ctls/dpt_ctls.c +++ b/usr.sbin/dpt/dpt_ctls/dpt_ctls.c @@ -30,7 +30,7 @@ /* dpt_ctls.c: Dunp a the number of configured DPT HBAs */ -#ident "$Id: dpt_ctls.c,v 1.1 1998/01/22 22:07:22 ShimonR Exp ShimonR $" +#ident "$Id: dpt_ctls.c,v 1.1 1998/01/26 06:20:39 julian Exp $" #include #include @@ -69,9 +69,10 @@ main(int argc, char **argv, char **argp) pass_thru.command_buffer = (u_int8_t *)&controllers_present; if ( (result = ioctl(fd, DPT_IOCTL_SEND, &pass_thru)) != 0 ) { - (void)fprintf(stderr, "%s ERROR: Failed to send IOCTL %x - %s\n", - argv[0], DPT_IOCTL_SEND, - strerror(errno)); + (void)fprintf(stderr, "%s ERROR: Failed to send IOCTL " + "%lx - %s\n", + argv[0], DPT_IOCTL_SEND, + strerror(errno)); exit(1); } diff --git a/usr.sbin/dpt/dpt_dm/dpt_dm.c b/usr.sbin/dpt/dpt_dm/dpt_dm.c index 869007b632a9..a2d1b12ab2d6 100644 --- a/usr.sbin/dpt/dpt_dm/dpt_dm.c +++ b/usr.sbin/dpt/dpt_dm/dpt_dm.c @@ -30,12 +30,13 @@ /* dpt_dm.c: Dump a DPT metrics structure */ -#ident "$Id: dpt_dm.c,v 1.8 1998/01/21 17:38:32 ShimonR Exp ShimonR $" +#ident "$Id: dpt_dm.c,v 1.1 1998/08/03 16:43:36 root Exp root $" #include #include #include #include +#include #include #include #include @@ -231,6 +232,19 @@ scsi_cmd_name(u_int8_t cmd) } } +static const char * +tmpsprintf(int buffer, const char *format, ...) +{ + static char buffers[16][16]; + va_list ap; + + va_start(ap, format); + vsnprintf(buffers[buffer], 16, format, ap); + va_end(ap); + return buffers[buffer]; +} + + int main(int argc, char **argv, char **argp) { @@ -246,27 +260,31 @@ main(int argc, char **argv, char **argp) } if ( (result = ioctl(fd, DPT_IOCTL_INTERNAL_METRICS, &metrics)) != 0 ) { - (void)fprintf(stderr, "%s ERROR: Failed to send IOCTL %x - %s\n", + (void)fprintf(stderr, "%s ERROR: Failed to send IOCTL %lx - %s\n", argv[0], DPT_IOCTL_INTERNAL_METRICS, strerror(errno)); exit(2); } /* Interrupt related measurements */ - (void)fprintf(stdout, "Interrupts:%d:%d:%d:%d\n\nCommands:\n", + (void)fprintf(stdout, "Interrupts:%u:%u:%s:%u\n\nCommands:\n", metrics.aborted_interrupts, metrics.spurious_interrupts, - metrics.min_intr_time, + metrics.min_intr_time == BIG_ENOUGH ? + "N/A" : + tmpsprintf(0, "%u", metrics.min_intr_time), metrics.max_intr_time); /* SCSI Commands, can be no more than 256 of them */ for (ndx = 0; ndx < 256; ndx++) { if (metrics.command_count[ndx] != 0) { - (void)fprintf(stdout, "%d:%s:%d:%d:%d\n", + (void)fprintf(stdout, "%u:%s:%u:%s:%d\n", ndx, scsi_cmd_name((u_int8_t)ndx), metrics.command_count[ndx], - metrics.min_command_time[ndx], + metrics.min_command_time[ndx] == BIG_ENOUGH ? + "N/A" : + tmpsprintf(0, "%u", metrics.min_command_time[ndx]), metrics.max_command_time[ndx]); } } @@ -370,22 +388,30 @@ main(int argc, char **argv, char **argp) } - (void)fprintf(stdout, "\nQueues:%u:%u:%u:%u:%u:%u:%u:%u:%u\n", + (void)fprintf(stdout, "\nQueues:%u:%s:%u:%u:%s:%u:%u:%s:%u\n", metrics.max_waiting_count, - metrics.min_waiting_time, + metrics.min_waiting_time == BIG_ENOUGH ? + "N/A" : + tmpsprintf(0, "%u", metrics.min_waiting_time), metrics.max_waiting_time, metrics.max_submit_count, - metrics.min_submit_time, + metrics.min_submit_time == BIG_ENOUGH ? + "N/A" : + tmpsprintf(1, "%u", metrics.min_submit_time), metrics.max_submit_time, metrics.max_complete_count, - metrics.min_complete_time, + metrics.min_complete_time == BIG_ENOUGH ? + "N/A" : + tmpsprintf(2, "%u", metrics.min_complete_time), metrics.max_complete_time); - (void)fprintf(stdout, "Hardware Ports:%u:%u:%u:%u\n", + (void)fprintf(stdout, "Hardware Ports:%u:%u:%u:%s\n", metrics.command_collisions, metrics.command_too_busy, metrics.max_eata_tries, - metrics.min_eata_tries); + metrics.min_eata_tries == BIG_ENOUGH ? + "N/A" : + tmpsprintf(0, "%u", metrics.min_eata_tries)); return(0); }