summaryrefslogtreecommitdiffstats
path: root/sys/dev/buslogic
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1999-04-07 23:01:43 +0000
committergibbs <gibbs@FreeBSD.org>1999-04-07 23:01:43 +0000
commitbc169999cf27401ebbb14ee33e6fa2bc264d3ee5 (patch)
tree063ddd2149347be416e8db791e19d1f1f9ea5e2e /sys/dev/buslogic
parent0c39daf09dc2ddf892202ede4d9b0ca4516c8799 (diff)
downloadFreeBSD-src-bc169999cf27401ebbb14ee33e6fa2bc264d3ee5.zip
FreeBSD-src-bc169999cf27401ebbb14ee33e6fa2bc264d3ee5.tar.gz
Improve bt_cmd() so that it has a better chance of working when there
are pending I/O transactions. It is not clear that is works 100% of the time under SMP, but since the bt_cmds() that are sent after other CPUs are started are not critical, the driver will function until I can figure out why this is the case.
Diffstat (limited to 'sys/dev/buslogic')
-rw-r--r--sys/dev/buslogic/bt.c141
-rw-r--r--sys/dev/buslogic/btreg.h4
2 files changed, 84 insertions, 61 deletions
diff --git a/sys/dev/buslogic/bt.c b/sys/dev/buslogic/bt.c
index bafa819..7d177c6 100644
--- a/sys/dev/buslogic/bt.c
+++ b/sys/dev/buslogic/bt.c
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: bt.c,v 1.13 1998/12/11 03:50:35 gibbs Exp $
+ * $Id: bt.c,v 1.14 1999/03/08 21:36:33 gibbs Exp $
*/
/*
@@ -74,6 +74,10 @@
#include <dev/buslogic/btreg.h>
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
struct bt_softc *bt_softcs[NBT];
/* MailBox Management functions */
@@ -1467,7 +1471,7 @@ btexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
* timeout causing us to start recovery operations.
*/
printf("%s: Encountered busy mailbox with %d out of %d "
- "commands active!!!", bt_name(bt), bt->active_ccbs,
+ "commands active!!!\n", bt_name(bt), bt->active_ccbs,
bt->max_ccbs);
untimeout(bttimeout, bccb, ccb->ccb_h.timeout_ch);
if (nseg != 0)
@@ -1839,29 +1843,39 @@ bt_cmd(struct bt_softc *bt, bt_op_t opcode, u_int8_t *params, u_int param_len,
{
u_int timeout;
u_int status;
+ u_int saved_status;
u_int intstat;
u_int reply_buf_size;
int s;
int cmd_complete;
+ int error;
/* No data returned to start */
reply_buf_size = reply_len;
reply_len = 0;
intstat = 0;
cmd_complete = 0;
+ saved_status = 0;
+ error = 0;
bt->command_cmp = 0;
/*
- * Wait up to 1 sec. for the adapter to become
+ * Wait up to 10 sec. for the adapter to become
* ready to accept commands.
*/
- timeout = 10000;
+ timeout = 100000;
while (--timeout) {
-
status = bt_inb(bt, STATUS_REG);
if ((status & HA_READY) != 0
&& (status & CMD_REG_BUSY) == 0)
break;
+ /*
+ * Throw away any pending data which may be
+ * left over from earlier commands that we
+ * timedout on.
+ */
+ if ((status & DATAIN_REG_READY) != 0)
+ (void)bt_inb(bt, DATAIN_REG);
DELAY(100);
}
if (timeout == 0) {
@@ -1876,81 +1890,80 @@ bt_cmd(struct bt_softc *bt, bt_op_t opcode, u_int8_t *params, u_int param_len,
bt_outb(bt, COMMAND_REG, opcode);
/*
- * Wait for up to 1sec to get the parameter list sent
+ * Wait for up to 1sec for each byte of the the
+ * parameter list sent to be sent.
*/
timeout = 10000;
while (param_len && --timeout) {
DELAY(100);
+ s = splcam();
status = bt_inb(bt, STATUS_REG);
intstat = bt_inb(bt, INTSTAT_REG);
+ splx(s);
if ((intstat & (INTR_PENDING|CMD_COMPLETE))
== (INTR_PENDING|CMD_COMPLETE)) {
+ saved_status = status;
cmd_complete = 1;
break;
}
if (bt->command_cmp != 0) {
- status = bt->latched_status;
+ saved_status = bt->latched_status;
cmd_complete = 1;
break;
}
if ((status & DATAIN_REG_READY) != 0)
break;
+
if ((status & CMD_REG_BUSY) == 0) {
bt_outb(bt, COMMAND_REG, *params++);
param_len--;
+ timeout = 10000;
}
}
if (timeout == 0) {
printf("%s: bt_cmd: Timeout sending parameters, "
"status = 0x%x\n", bt_name(bt), status);
- return (ETIMEDOUT);
+ cmd_complete = 1;
+ saved_status = status;
+ error = ETIMEDOUT;
}
/*
- * The BOP_MODIFY_IO_ADDR does not issue a CMD_COMPLETE, but
- * it should update the status register. So, we wait for
- * the CMD_REG_BUSY status to clear and check for a command
- * failure.
- */
- if (cmd_complete == 0 && opcode == BOP_MODIFY_IO_ADDR) {
-
- while (--cmd_timeout) {
- status = bt_inb(bt, STATUS_REG);
- if ((status & CMD_REG_BUSY) == 0) {
- if ((status & CMD_INVALID) != 0) {
- printf("%s: bt_cmd - Modify I/O Address"
- " invalid\n", bt_name(bt));
- return (EINVAL);
- }
- return (0);
- }
- DELAY(100);
- }
- if (timeout == 0) {
- printf("%s: bt_cmd: Timeout on Modify I/O Address CMD, "
- "status = 0x%x\n", bt_name(bt), status);
- return (ETIMEDOUT);
- }
- }
-
- /*
- * For all other commands, we wait for any output data
- * and the final comand completion interrupt.
+ * Wait for the command to complete.
*/
while (cmd_complete == 0 && --cmd_timeout) {
+ s = splcam();
status = bt_inb(bt, STATUS_REG);
intstat = bt_inb(bt, INTSTAT_REG);
- if ((intstat & (INTR_PENDING|CMD_COMPLETE))
- == (INTR_PENDING|CMD_COMPLETE))
- break;
+ splx(s);
if (bt->command_cmp != 0) {
- status = bt->latched_status;
- break;
- }
-
- if ((status & DATAIN_REG_READY) != 0) {
+ /*
+ * Our interrupt handler saw CMD_COMPLETE
+ * status before we did.
+ */
+ cmd_complete = 1;
+ saved_status = bt->latched_status;
+ } else if ((intstat & (INTR_PENDING|CMD_COMPLETE))
+ == (INTR_PENDING|CMD_COMPLETE)) {
+ /*
+ * Our poll (in case interrupts are blocked)
+ * saw the CMD_COMPLETE interrupt.
+ */
+ cmd_complete = 1;
+ saved_status = status;
+ } else if (opcode == BOP_MODIFY_IO_ADDR
+ && (status & CMD_REG_BUSY) == 0) {
+ /*
+ * The BOP_MODIFY_IO_ADDR does not issue a CMD_COMPLETE,
+ * but it should update the status register. So, we
+ * consider this command complete when the CMD_REG_BUSY
+ * status clears.
+ */
+ saved_status = status;
+ cmd_complete = 1;
+ } else if ((status & DATAIN_REG_READY) != 0) {
u_int8_t data;
data = bt_inb(bt, DATAIN_REG);
@@ -1961,20 +1974,26 @@ bt_cmd(struct bt_softc *bt, bt_op_t opcode, u_int8_t *params, u_int param_len,
"for opcode 0x%x\n", bt_name(bt),
opcode);
}
+ /*
+ * Reset timeout to ensure at least a second
+ * between response bytes.
+ */
+ cmd_timeout = MAX(cmd_timeout, 10000);
reply_len++;
- }
- if ((opcode == BOP_FETCH_LRAM)
- && (status & HA_READY) != 0)
- break;
+ } else if ((opcode == BOP_FETCH_LRAM)
+ && (status & HA_READY) != 0) {
+ saved_status = status;
+ cmd_complete = 1;
+ }
DELAY(100);
}
- if (timeout == 0) {
- printf("%s: bt_cmd: Timeout waiting for reply data and "
- "command complete.\n%s: status = 0x%x, intstat = 0x%x, "
- "reply_len = %d\n", bt_name(bt), bt_name(bt), status,
- intstat, reply_len);
- return (ETIMEDOUT);
+ if (cmd_timeout == 0) {
+ printf("%s: bt_cmd: Timeout waiting for command (%x) "
+ "to complete.\n%s: status = 0x%x, intstat = 0x%x, "
+ "rlen %d\n", bt_name(bt), opcode, bt_name(bt),
+ status, intstat, reply_len);
+ error = (ETIMEDOUT);
}
/*
@@ -1985,10 +2004,13 @@ bt_cmd(struct bt_softc *bt, bt_op_t opcode, u_int8_t *params, u_int param_len,
bt_intr(bt);
splx(s);
+ if (error != 0)
+ return (error);
+
/*
* If the command was rejected by the controller, tell the caller.
*/
- if ((status & CMD_INVALID) != 0) {
+ if ((saved_status & CMD_INVALID) != 0) {
/*
* Some early adapters may not recover properly from
* an invalid command. If it appears that the controller
@@ -2009,7 +2031,6 @@ bt_cmd(struct bt_softc *bt, bt_op_t opcode, u_int8_t *params, u_int param_len,
return (EINVAL);
}
-
if (param_len > 0) {
/* The controller did not accept the full argument list */
return (E2BIG);
@@ -2104,8 +2125,9 @@ btfetchtransinfo(struct bt_softc *bt, struct ccb_trans_settings* cts)
DEFAULT_CMD_TIMEOUT);
if (error != 0) {
- printf("%s: btfetchtransinfo - Inquire Setup Info Failed\n",
- bt_name(bt));
+ printf("%s: btfetchtransinfo - Inquire Setup Info Failed %x\n",
+ bt_name(bt), error);
+ cts->valid = 0;
return;
}
@@ -2160,6 +2182,7 @@ btfetchtransinfo(struct bt_softc *bt, struct ccb_trans_settings* cts)
if (error != 0) {
printf("%s: btfetchtransinfo - Inquire Sync "
"Info Failed 0x%x\n", bt_name(bt), error);
+ cts->valid = 0;
return;
}
sync_period = sync_info.sync_rate[target] * 100;
diff --git a/sys/dev/buslogic/btreg.h b/sys/dev/buslogic/btreg.h
index fd16f5c..02ad301 100644
--- a/sys/dev/buslogic/btreg.h
+++ b/sys/dev/buslogic/btreg.h
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: btreg.h,v 1.3 1998/11/10 06:44:50 gibbs Exp $
+ * $Id: btreg.h,v 1.4 1999/03/08 21:36:34 gibbs Exp $
*/
#ifndef _BTREG_H_
@@ -683,7 +683,7 @@ void bt_find_probe_range(int ioport,
int bt_iop_from_bio(isa_compat_io_t bio_index);
-#define DEFAULT_CMD_TIMEOUT 10000 /* 1 sec */
+#define DEFAULT_CMD_TIMEOUT 100000 /* 10 sec */
int bt_cmd(struct bt_softc *bt, bt_op_t opcode,
u_int8_t *params, u_int param_len,
u_int8_t *reply_data, u_int reply_len,
OpenPOWER on IntegriCloud