summaryrefslogtreecommitdiffstats
path: root/sys/dev/dpt/dpt_scsi.c
diff options
context:
space:
mode:
authoreivind <eivind@FreeBSD.org>1998-08-05 00:54:38 +0000
committereivind <eivind@FreeBSD.org>1998-08-05 00:54:38 +0000
commitf03826546dda8a7ceb4654dd24f3c23547bf5a30 (patch)
tree0665db6870e7ad529c2e975ebe1ced2688d8c652 /sys/dev/dpt/dpt_scsi.c
parent926810dcee72cabf9aeb2364563cd63a890a127b (diff)
downloadFreeBSD-src-f03826546dda8a7ceb4654dd24f3c23547bf5a30.zip
FreeBSD-src-f03826546dda8a7ceb4654dd24f3c23547bf5a30.tar.gz
Update DPT driver from 1.4.3 to 1.4.5
Submitted by: Simon Shapiro <shimon@simon-shapiro.org>
Diffstat (limited to 'sys/dev/dpt/dpt_scsi.c')
-rw-r--r--sys/dev/dpt/dpt_scsi.c323
1 files changed, 234 insertions, 89 deletions
diff --git a/sys/dev/dpt/dpt_scsi.c b/sys/dev/dpt/dpt_scsi.c
index 8f50f58..a0a2cc6 100644
--- a/sys/dev/dpt/dpt_scsi.c
+++ b/sys/dev/dpt/dpt_scsi.c
@@ -37,9 +37,9 @@
* Last but not least, many thanx to UCB and the FreeBSD
* team for creating and maintaining such a wonderful O/S.
*
- * TODO: * Add EISA and ISA probe code.
+ * TODO: * Add ISA probe code.
* * Add driver-level RSID-0. This will allow interoperability with
- * NiceTry, M$-Doze, Win-Dog, Slowlaris, etc. in recognizing RAID
+ * NiceTry, M$-Doze, Win-Dog, Slowlaris, etc., in recognizing RAID
* arrays that span controllers (Wow!).
*/
@@ -64,7 +64,8 @@
* 3. dpt_handle_timeouts potentially inserts into the queue
*/
-#ident "$Id: dpt_scsi.c,v 1.6 1998/06/02 00:32:38 eivind Exp $"
+#ident "$Id: dpt_scsi.c,v 1.32 1998/08/03 16:45:12 root Exp root $"
+
#define _DPT_C_
#include "opt_dpt.h"
@@ -83,6 +84,13 @@
#include <vm/vm.h>
#include <vm/pmap.h>
+/* The HBA reset option uses the same timer as the lost IRQ option*/
+#ifdef DPT_RESET_HBA
+#ifndef DPT_LOST_IRQ
+#define DPT_LOST_IRQ
+#endif
+#endif
+
#include <sys/dpt.h>
#ifdef INLINE
@@ -98,6 +106,8 @@ int dpt_controllers_present = 0;
/* Function Prototypes */
+#define microtime_now dpt_time_now()
+
static INLINE u_int32_t dpt_inl(dpt_softc_t * dpt, u_int32_t offset);
static INLINE u_int8_t dpt_inb(dpt_softc_t * dpt, u_int32_t offset);
static INLINE void
@@ -368,6 +378,117 @@ dpt_raid_busy(dpt_softc_t * dpt)
return (0);
}
+#ifdef DPT_RESET_HBA
+
+/*
+** Function name : dpt_reset_hba
+**
+** Description : Reset the HBA and properly discard all pending work
+** Input : Minor Device Number
+** Output : Nothing
+*/
+
+static void
+dpt_reset_hba(int minor)
+{
+ dpt_softc_t *dpt;
+ eata_ccb_t *ccb;
+ int ospl;
+ dpt_ccb_t dccb, *dccbp;
+ int result;
+ struct scsi_xfer *xs;
+
+ if ((dpt = dpt_minor2softc(minor)) == NULL) {
+ printf("DPT: Ignoring invalid minor %d in dpt_reset_hba\n", minor);
+ return;
+ }
+
+ /* Prepare a control block. The SCSI command part is immaterial */
+ dccb.xs = NULL;
+ dccb.flags = 0;
+ dccb.state = DPT_CCB_STATE_NEW;
+ dccb.std_callback = NULL;
+ dccb.wrbuff_callback = NULL;
+
+ ccb = &dccb.eata_ccb;
+ ccb->CP_OpCode = EATA_CMD_RESET;
+ ccb->SCSI_Reset = 0;
+ ccb->HBA_Init = 1;
+ ccb->Auto_Req_Sen = 1;
+ ccb->cp_id = 0; /* Should be ignored */
+ ccb->DataIn = 1;
+ ccb->DataOut = 0;
+ ccb->Interpret = 1;
+ ccb->reqlen = htonl(sizeof(struct scsi_sense_data));
+ ccb->cp_statDMA = htonl(vtophys(&ccb->cp_statDMA));
+ ccb->cp_reqDMA = htonl(vtophys(&ccb->cp_reqDMA));
+ ccb->cp_viraddr = (u_int32_t) & ccb;
+
+ ccb->cp_msg[0] = HA_IDENTIFY_MSG | HA_DISCO_RECO;
+ ccb->cp_scsi_cmd = 0; /* Should be ignored */
+
+ /* Lock up the submitted queue. We are very persistant here */
+ ospl = splcam();
+ while (dpt->queue_status & DPT_SUBMITTED_QUEUE_ACTIVE) {
+ DELAY(100);
+ }
+
+ dpt->queue_status |= DPT_SUBMITTED_QUEUE_ACTIVE;
+ splx(ospl);
+
+ /* Send the RESET message */
+ if ((result = dpt_send_eata_command(dpt, &dccb.eata_ccb,
+ EATA_CMD_RESET, 0, 0, 0, 0)) != 0) {
+ printf("dpt%d: Failed to send the RESET message.\n"
+ " Trying cold boot (ouch!)\n", dpt->unit);
+
+
+ if ((result = dpt_send_eata_command(dpt, &dccb.eata_ccb,
+ EATA_COLD_BOOT, 0, 0, 0, 0))
+ != 0) {
+ panic("dpt%d: Faild to cold boot the HBA\n", dpt->unit);
+ }
+#ifdef DPT_MEASURE_PERFORMANCE
+ dpt->performance.cold_boots++;
+#endif /* DPT_MEASURE_PERFORMANCE */
+ }
+
+#ifdef DPT_MEASURE_PERFORMANCE
+ dpt->performance.warm_starts++;
+#endif /* DPT_MEASURE_PERFORMANCE */
+
+ printf("dpt%d: Aborting pending requests. O/S should re-submit\n",
+ dpt->unit);
+
+ while ((dccbp = TAILQ_FIRST(&dpt->completed_ccbs)) != NULL) {
+ struct scsi_xfer *xs = dccbp->xs;
+
+ /* Not all transactions have xs structs */
+ if (xs != NULL) {
+ /* Tell the kernel proper this did not complete well */
+ xs->error |= XS_SELTIMEOUT;
+ xs->flags |= SCSI_ITSDONE;
+ scsi_done(xs);
+ }
+
+ dpt_Qremove_submitted(dpt, dccbp);
+
+ /* Remember, Callbacks are NOT in the standard queue */
+ if (dccbp->std_callback != NULL) {
+ (dccbp->std_callback) (dpt, dccbp->eata_ccb.cp_channel, dccbp);
+ } else {
+ ospl = splcam();
+ dpt_Qpush_free(dpt, dccbp);
+ splx(ospl);
+ }
+ }
+
+ printf("dpt%d: reset done aborting all pending commands\n", dpt->unit);
+ dpt->queue_status &= ~DPT_SUBMITTED_QUEUE_ACTIVE;
+}
+
+#endif /* DPT_RESET_HBA */
+
/**
* Build a Command Block for target mode READ/WRITE BUFFER,
* with the ``sync'' bit ON.
@@ -438,8 +559,6 @@ dpt_target_ccb(dpt_softc_t * dpt, int bus, u_int8_t target, u_int8_t lun,
/* Setup a target mode READ command */
-#define cmd_ct dpt->performance.command_count[(int)ccb->eata_ccb.cp_scsi_cmd];
-
static void
dpt_set_target(int redo, dpt_softc_t * dpt,
u_int8_t bus, u_int8_t target, u_int8_t lun, int mode,
@@ -447,10 +566,6 @@ dpt_set_target(int redo, dpt_softc_t * dpt,
{
int ospl;
-#ifdef DPT_MEASURE_PERFORMANCE
- struct timeval now;
-#endif
-
if (dpt->target_mode_enabled) {
ospl = splcam();
@@ -461,9 +576,8 @@ dpt_set_target(int redo, dpt_softc_t * dpt,
ccb->transaction_id = ++dpt->commands_processed;
#ifdef DPT_MEASURE_PERFORMANCE
- ++cmd_ct;
- microtime(&now);
- ccb->command_started = now;
+ dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd]++;
+ ccb->command_started = microtime_now;
#endif
dpt_Qadd_waiting(dpt, ccb);
dpt_sched_queue(dpt);
@@ -477,11 +591,11 @@ dpt_set_target(int redo, dpt_softc_t * dpt,
/**
* Schedule a buffer to be sent to another target.
- * The work will be scheduled and the callback provided will be called when the work is
- * actually done.
+ * The work will be scheduled and the callback provided will be called when
+ * the work is actually done.
*
- * Please NOTE: ``Anyone'' can send a buffer, but only registered clients get notified
- of receipt of buffers.
+ * Please NOTE: ``Anyone'' can send a buffer, but only registered clients
+ * get notified of receipt of buffers.
*/
int
@@ -498,9 +612,6 @@ dpt_send_buffer(int unit,
dpt_softc_t *dpt;
dpt_ccb_t *ccb = NULL;
int ospl;
-#ifdef DPT_MEASURE_PERFORMANCE
- struct timeval now;
-#endif
/* This is an external call. Be a bit paranoid */
for (dpt = TAILQ_FIRST(&dpt_softc_list);
@@ -540,18 +651,17 @@ valid_unit:
splx(ospl);
bcopy(dpt->rw_buffer[channel][target][lun] + offset, data, length);
- dpt_target_ccb(dpt, channel, target, lun, ccb, mode, SCSI_TM_WRITE_BUFFER,
- length, offset);
- ccb->std_callback = (ccb_callback) callback; /* A hack. Potential
- * trouble */
+ dpt_target_ccb(dpt, channel, target, lun, ccb, mode,
+ SCSI_TM_WRITE_BUFFER,
+ length, offset);
+ ccb->std_callback = (ccb_callback) callback; /* Potential trouble */
ospl = splcam();
ccb->transaction_id = ++dpt->commands_processed;
#ifdef DPT_MEASURE_PERFORMANCE
- ++cmd_ct;
- microtime(&now);
- ccb->command_started = now;
+ dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd]++;
+ ccb->command_started = microtime_now;
#endif
dpt_Qadd_waiting(dpt, ccb);
dpt_sched_queue(dpt);
@@ -748,9 +858,9 @@ dpt_send_eata_command(dpt_softc_t * dpt, eata_ccb_t * cmd_block,
u_int8_t result;
u_int32_t test;
u_int32_t swapped_cmdaddr;
-
+
if (!retries)
- retries = 1000;
+ retries = 10000;
/*
* I hate this polling nonsense. Wish there was a way to tell the DPT
@@ -780,6 +890,11 @@ dpt_send_eata_command(dpt_softc_t * dpt, eata_ccb_t * cmd_block,
return (1);
}
+ /* The controller is alive, advance the wedge timer */
+#ifdef DPT_RESET_HBA
+ dpt->last_contact = microtime_now;
+#endif
+
if (cmd_block != NULL) {
swapped_cmdaddr = vtophys(cmd_block);
@@ -865,7 +980,6 @@ dpt_user_cmd(dpt_softc_t * dpt, eata_pt_t * user_cmd,
int submitted;
dpt_ccb_t *ccb;
void *data;
- struct timeval now;
data = NULL;
channel = minor2hba(minor_no);
@@ -1013,9 +1127,8 @@ dpt_user_cmd(dpt_softc_t * dpt, eata_pt_t * user_cmd,
ccb->data = data;
#ifdef DPT_MEASURE_PERFORMANCE
- ++dpt->performance.command_count[(int) ccb->eata_ccb.cp_scsi_cmd];
- microtime(&now);
- ccb->command_started = now;
+ ++dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd];
+ ccb->command_started = microtime_now;
#endif
ospl = splcam();
dpt_Qadd_waiting(dpt, ccb);
@@ -1851,6 +1964,11 @@ dpt_scsi_cmd(struct scsi_xfer * xs)
ospl = splcam();
if ((dpt->state & DPT_LOST_IRQ_SET) == 0) {
printf("dpt%d: Initializing Lost IRQ Timer\n", dpt->unit);
+#ifdef DPT_RESET_HBA
+ printf("dpt%d: HBA will reset if irresponsive for %d seconds\n",
+ dpt->unit, DPT_RESET_HBA);
+ dpt->last_contact = microtime_now;
+#endif
dpt->state |= DPT_LOST_IRQ_SET;
timeout(dpt_irq_timeout, dpt, hz);
}
@@ -2109,13 +2227,20 @@ dpt_scsi_cmd(struct scsi_xfer * xs)
if ((status & HA_SERROR) || (ndx == xs->timeout)) {
xs->error = XS_DRIVER_STUFFUP;
}
+#ifdef DPT_RESET_HBA
+ else {
+ /*
+ * We received a reply and did not time out.
+ * Advance the wedge counter.
+ */
+ dpt->last_contact = microtime_now;
+ }
+#endif /* DPT_RESET_HBA */
dpt_Qpush_free(dpt, ccb);
splx(ospl);
return (COMPLETE);
} else {
- struct timeval junk;
-
/**
* Not a polled command.
* The command can be queued normally.
@@ -2129,10 +2254,8 @@ dpt_scsi_cmd(struct scsi_xfer * xs)
ccb->transaction_id = ++dpt->commands_processed;
#ifdef DPT_MEASURE_PERFORMANCE
-#define cmd_ndx (int)ccb->eata_ccb.cp_scsi_cmd
- ++dpt->performance.command_count[cmd_ndx];
- microtime(&junk);
- ccb->command_started = junk;
+ ++dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd];
+ ccb->command_started = microtime_now;
#endif
dpt_Qadd_waiting(dpt, ccb);
splx(ospl);
@@ -2275,12 +2398,7 @@ dpt_intr(void *arg)
#endif
#ifdef DPT_MEASURE_PERFORMANCE
- {
- struct timeval junk;
-
- microtime(&junk);
- dpt->performance.intr_started = junk;
- }
+ dpt->performance.intr_started = microtime_now;
#endif
/* First order of business is to check if this interrupt is for us */
@@ -2297,12 +2415,17 @@ dpt_intr(void *arg)
#endif
return;
}
+
+ /* The controller is alive, advance the wedge timer */
+#ifdef DPT_RESET_HBA
+ dpt->last_contact = microtime_now;
+#endif
+
if (!dpt->handle_interrupts) {
#ifdef DPT_MEASURE_PERFORMANCE
++dpt->performance.aborted_interrupts;
#endif
- status = dpt_inb(dpt, HA_RSTATUS); /* This CLEARS
- * interrupts */
+ status = dpt_inb(dpt, HA_RSTATUS); /* This CLEARS interrupts! */
return;
}
/**
@@ -2332,12 +2455,10 @@ dpt_intr(void *arg)
#ifdef DPT_HANDLE_TIMEOUTS
if (dccb->state & DPT_CCB_STATE_MARKED_LOST) {
- struct timeval now;
u_int32_t age;
struct scsi_xfer *xs = dccb->xs;
- microtime(&now);
- age = dpt_time_delta(dccb->command_started, now);
+ age = dpt_time_delta(dccb->command_started, microtime_now);
printf("dpt%d: Salvaging Tx %d from the jaws of destruction "
"(%d/%d)\n",
@@ -2484,11 +2605,8 @@ dpt_intr(void *arg)
#ifdef DPT_MEASURE_PERFORMANCE
{
u_int32_t result;
- struct timeval junk;
- microtime(&junk);
-
- result = dpt_time_delta(dpt->performance.intr_started, junk);
+ result = dpt_time_delta(dpt->performance.intr_started, microtime_now);
if (result != ~0) {
if (dpt->performance.max_intr_time < result)
@@ -2595,14 +2713,13 @@ dpt_complete(dpt_softc_t * dpt)
#ifdef DPT_MEASURE_PERFORMANCE
{
u_int32_t result;
- struct timeval junk;
- microtime(&junk);
- ccb->command_ended = junk;
#define time_delta dpt_time_delta(ccb->command_started, ccb->command_ended)
- result = time_delta;
#define maxctime dpt->performance.max_command_time[ccb->eata_ccb.cp_scsi_cmd]
#define minctime dpt->performance.min_command_time[ccb->eata_ccb.cp_scsi_cmd]
+
+ ccb->command_ended = microtime_now;
+ result = time_delta;
if (result != ~0) {
if (maxctime < result) {
@@ -2689,7 +2806,7 @@ dpt_process_completion(dpt_softc_t * dpt,
struct scsi_rw_big *cmd;
int op_type;
- cmd = (struct scsi_rw_big *) & ccb->eata_ccb.cp_scsi_cmd;
+ cmd = (struct scsi_rw_big *) &ccb->eata_ccb.cp_scsi_cmd;
switch (cmd->op_code) {
case 0xa8: /* 12-byte READ */
@@ -2865,6 +2982,10 @@ dpt_process_completion(dpt_softc_t * dpt,
* basis.
* It is a completely ugly hack which purpose is to handle the problem of
* missing interrupts on certain platforms..
+ *
+ * An additional task is to optionally check if the controller is wedged.
+ * A wedeged controller is one which has not accepted a command, nor sent
+ * an interrupt in the last DPT_RESET_HBA seconds.
*/
static void
@@ -2883,6 +3004,34 @@ dpt_irq_timeout(void *arg)
printf("dpt %d: %d lost Interrupts Recovered\n",
dpt->unit, ++dpt->lost_interrupts);
}
+#ifdef DPT_RESET_HBA
+ {
+ int max_wedge, contact_delta;
+
+ if (TAILQ_EMPTY(&dpt->waiting_ccbs)) {
+ dpt->last_contact = microtime_now;
+ } else {
+ /* If nothing is waiting, we cannot assume we are wedged */
+ if (DPT_RESET_HBA < 1)
+ max_wedge = 1000000;
+ else
+ max_wedge = 1000000 * DPT_RESET_HBA;
+
+ contact_delta = dpt_time_delta(dpt->last_contact,
+ microtime_now);
+
+ if (contact_delta > max_wedge) {
+ printf("dpt%d: Appears wedged for %d.%d (%d.0)seconds.\n"
+ " Resetting\n",
+ dpt->unit, contact_delta/1000000,
+ (contact_delta % 1000000) / 100000,
+ DPT_RESET_HBA);
+ dpt_reset_hba(dpt);
+ }
+ }
+ }
+#endif /* DPT_RESET_HBA */
+
dpt->state &= ~DPT_LOST_IRQ_ACTIVE;
}
timeout(dpt_irq_timeout, (caddr_t) dpt, hz * 1);
@@ -2933,13 +3082,10 @@ dpt_handle_timeouts(dpt_softc_t * dpt)
ccb != NULL;
ccb = TAILQ_NEXT(ccb, links)) {
struct scsi_xfer *xs;
- struct timeval now;
u_int32_t age, max_age;
xs = ccb->xs;
-
- microtime(&now);
- age = dpt_time_delta(ccb->command_started, now);
+ age = dpt_time_delta(ccb->command_started, microtime_now);
#define TenSec 10000000
@@ -3054,10 +3200,8 @@ dpt_Qremove_completed(dpt_softc_t * dpt, dpt_ccb_t * ccb)
{
#ifdef DPT_MEASURE_PERFORMANCE
u_int32_t complete_time;
- struct timeval now;
- microtime(&now);
- complete_time = dpt_time_delta(ccb->command_ended, now);
+ complete_time = dpt_time_delta(ccb->command_ended, microtime_now);
if (complete_time != ~0) {
if (dpt->performance.max_complete_time < complete_time)
@@ -3102,7 +3246,7 @@ static INLINE_Q void
dpt_Qpush_free(dpt_softc_t * dpt, dpt_ccb_t * ccb)
{
#ifdef DPT_FREELIST_IS_STACK
- TAILQ_INSERT_HEAD(&dpt->free_ccbs, ccb, links);
+ TAILQ_INSERT_HEAD(&dpt->free_ccbs, ccb, links)
#else
TAILQ_INSERT_TAIL(&dpt->free_ccbs, ccb, links);
#endif
@@ -3116,14 +3260,11 @@ dpt_Qpush_free(dpt_softc_t * dpt, dpt_ccb_t * ccb)
static INLINE_Q void
dpt_Qadd_waiting(dpt_softc_t * dpt, dpt_ccb_t * ccb)
{
- struct timeval junk;
-
TAILQ_INSERT_TAIL(&dpt->waiting_ccbs, ccb, links);
++dpt->waiting_ccbs_count;
#ifdef DPT_MEASURE_PERFORMANCE
- microtime(&junk);
- ccb->command_ended = junk;
+ ccb->command_ended = microtime_now;
if (dpt->waiting_ccbs_count > dpt->performance.max_waiting_count)
dpt->performance.max_waiting_count = dpt->waiting_ccbs_count;
#endif
@@ -3138,14 +3279,11 @@ dpt_Qadd_waiting(dpt_softc_t * dpt, dpt_ccb_t * ccb)
static INLINE_Q void
dpt_Qpush_waiting(dpt_softc_t * dpt, dpt_ccb_t * ccb)
{
- struct timeval junk;
-
TAILQ_INSERT_HEAD(&dpt->waiting_ccbs, ccb, links);
++dpt->waiting_ccbs_count;
#ifdef DPT_MEASURE_PERFORMANCE
- microtime(&junk);
- ccb->command_ended = junk;
+ ccb->command_ended = microtime_now;
if (dpt->performance.max_waiting_count < dpt->waiting_ccbs_count)
dpt->performance.max_waiting_count = dpt->waiting_ccbs_count;
@@ -3163,11 +3301,9 @@ static INLINE_Q void
dpt_Qremove_waiting(dpt_softc_t * dpt, dpt_ccb_t * ccb)
{
#ifdef DPT_MEASURE_PERFORMANCE
- struct timeval now;
u_int32_t waiting_time;
- microtime(&now);
- waiting_time = dpt_time_delta(ccb->command_ended, now);
+ waiting_time = dpt_time_delta(ccb->command_ended, microtime_now);
if (waiting_time != ~0) {
if (dpt->performance.max_waiting_time < waiting_time)
@@ -3190,14 +3326,11 @@ dpt_Qremove_waiting(dpt_softc_t * dpt, dpt_ccb_t * ccb)
static INLINE_Q void
dpt_Qadd_submitted(dpt_softc_t * dpt, dpt_ccb_t * ccb)
{
- struct timeval junk;
-
TAILQ_INSERT_TAIL(&dpt->submitted_ccbs, ccb, links);
++dpt->submitted_ccbs_count;
#ifdef DPT_MEASURE_PERFORMANCE
- microtime(&junk);
- ccb->command_ended = junk;
+ ccb->command_ended = microtime_now;
if (dpt->performance.max_submit_count < dpt->submitted_ccbs_count)
dpt->performance.max_submit_count = dpt->submitted_ccbs_count;
#endif
@@ -3212,14 +3345,11 @@ dpt_Qadd_submitted(dpt_softc_t * dpt, dpt_ccb_t * ccb)
static INLINE_Q void
dpt_Qadd_completed(dpt_softc_t * dpt, dpt_ccb_t * ccb)
{
- struct timeval junk;
-
TAILQ_INSERT_TAIL(&dpt->completed_ccbs, ccb, links);
++dpt->completed_ccbs_count;
#ifdef DPT_MEASURE_PERFORMANCE
- microtime(&junk);
- ccb->command_ended = junk;
+ ccb->command_ended = microtime_now;
if (dpt->performance.max_complete_count < dpt->completed_ccbs_count)
dpt->performance.max_complete_count =
dpt->completed_ccbs_count;
@@ -3236,11 +3366,9 @@ static INLINE_Q void
dpt_Qremove_submitted(dpt_softc_t * dpt, dpt_ccb_t * ccb)
{
#ifdef DPT_MEASURE_PERFORMANCE
- struct timeval now;
u_int32_t submit_time;
- microtime(&now);
- submit_time = dpt_time_delta(ccb->command_ended, now);
+ submit_time = dpt_time_delta(ccb->command_ended, microtime_now);
if (submit_time != ~0) {
ccb->submitted_time = submit_time;
@@ -3336,11 +3464,26 @@ checkit:
/**
* What we do for a shutdown, is give the DPT early power loss
* warning
- . */
+ */
+#ifdef DPT_SHUTDOWN_SLEEP
+ DELAY(DPT_SHUTDOWN_SLEEP * 1000);
+
+ if (dpt->state & DPT_HA_SHUTDOWN_ACTIVE) {
+ ospl = splcam();
+ dpt->state &= ~DPT_HA_SHUTDOWN_ACTIVE;
+ splx(ospl);
+ printf("dpt%d: WARNING: After sleeping for %d seconds, "
+ "I am re-enabled\n",
+ dpt->unit);
+ printf(" Any further I/O is NOT guranteed to "
+ "complete!\n");
+ }
+#else
(void) dpt_send_immediate(dpt, NULL, EATA_POWER_OFF_WARN, 0, 0);
printf("dpt%d: Controller was warned of shutdown and is now "
"disabled\n",
dpt->unit);
+#endif
return;
}
@@ -3692,3 +3835,5 @@ scsi_cmd_name(u_int8_t cmd)
* c++-friend-offset: 0
* End:
*/
+
+
OpenPOWER on IntegriCloud