Update DPT driver from 1.4.3 to 1.4.5

Submitted by: Simon Shapiro <shimon@simon-shapiro.org>
This commit is contained in:
Eivind Eklund 1998-08-05 00:54:38 +00:00
parent 84dd0fd0bb
commit b755b88510
12 changed files with 536 additions and 298 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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
}
}

View File

@ -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:
*/

View File

@ -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

View File

@ -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

View File

@ -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
}
}

View File

@ -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 */

View File

@ -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 <fcntl.h>
#include <stdio.h>
@ -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);

View File

@ -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 <fcntl.h>
#include <stdio.h>
@ -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);
}

View File

@ -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 <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/queue.h>
@ -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);
}