patch-2.1.105 linux/drivers/scsi/NCR5380.c
Next file: linux/drivers/scsi/NCR5380.h
Previous file: linux/drivers/net/wd.c
Back to the patch index
Back to the overall index
- Lines: 407
- Date:
Sun Jun 7 10:37:41 1998
- Orig file:
v2.1.104/linux/drivers/scsi/NCR5380.c
- Orig date:
Thu May 14 19:47:40 1998
diff -u --recursive --new-file v2.1.104/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
@@ -31,6 +31,18 @@
/*
* $Log: NCR5380.c,v $
+
+ * Revision 1.9 1997/7/27 Ronald van Cuijlenborg
+ * (ronald.van.cuijlenborg@tip.nl or nutty@dds.nl)
+ * (hopefully) fixed and enhanced USLEEP
+ * added support for DTC3181E card (for Mustek scanner)
+ *
+
+ * Revision 1.8 Ingmar Baumgart
+ * (ingmar@gonzo.schwaben.de)
+ * added support for NCR53C400a card
+ *
+
* Revision 1.7 1996/3/2 Ray Van Tassle (rayvt@comm.mot.com)
* added proc_info
* added support needed for DTC 3180/3280
@@ -84,7 +96,6 @@
#ifndef notyet
#undef LINKED
-#undef USLEEP
#undef REAL_DMA
#endif
@@ -239,9 +250,6 @@
* bus, we will go to sleep so that the CPU can get real work done
* when we run a command that won't complete immediately.
*
- * Note that if USLEEP is defined, NCR5380_TIMER *must* also be
- * defined.
- *
* Defaults for these will be provided if USLEEP is defined, although
* the user may want to adjust these to allocate CPU resources to
* the SCSI driver or "real" code.
@@ -309,6 +317,10 @@
static struct Scsi_Host *first_instance = NULL;
static Scsi_Host_Template *the_template = NULL;
+#ifdef USLEEP
+struct timer_list usleep_timer;
+#endif
+
/*
* Function : void initialize_SCp(Scsi_Cmnd *cmd)
*
@@ -560,9 +572,6 @@
}
#ifdef USLEEP
-#ifndef NCR5380_TIMER
-#error "NCR5380_TIMER must be defined so that this type of NCR5380 driver gets a unique timer."
-#endif
/*
* These need tweaking, and would probably work best as per-device
@@ -582,6 +591,10 @@
#ifndef USLEEP_POLL
#define USLEEP_POLL (200*HZ/1000)
#endif
+#ifndef USLEEP_WAITLONG
+/* RvC: (reasonable time to wait on select error) */
+#define USLEEP_WAITLONG USLEEP_SLEEP
+#endif
static struct Scsi_Host *expires_first = NULL;
@@ -638,48 +651,48 @@
save_flags(flags);
cli();
- if (((struct NCR5380_hostdata *) (instance->host_data))->next_timer) {
+ if (((struct NCR5380_hostdata *) (instance->hostdata))->next_timer) {
restore_flags(flags);
return -1;
}
for (prev = &expires_first, tmp = expires_first; tmp;
- prev = &(((struct NCR5380_hostdata *) tmp->host_data)->next_timer),
- tmp = ((struct NCR5380_hostdata *) tmp->host_data)->next_timer)
- if (instance->time_expires < tmp->time_expires)
+ prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer),
+ tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer)
+ if (((struct NCR5380_hostdata *)instance->hostdata)->time_expires <
+ ((struct NCR5380_hostdata *)tmp->hostdata)->time_expires)
break;
- instance->next_timer = tmp;
+ ((struct NCR5380_hostdata *) instance->hostdata)->next_timer = tmp;
*prev = instance;
- timer_table[NCR5380_TIMER].expires = expires_first->time_expires;
- timer_active |= 1 << NCR5380_TIMER;
+
+ del_timer(&usleep_timer);
+ usleep_timer.expires = ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires;
+ add_timer(&usleep_timer);
restore_flags(flags);
return 0;
}
/* Doing something about unwanted reentrancy here might be useful */
-void NCR5380_timer_fn(void)
+void NCR5380_timer_fn(unsigned long surplus_to_requirements)
{
unsigned long flags;
struct Scsi_Host *instance;
save_flags(flags);
cli();
- for (; expires_first && expires_first->time_expires >= jiffies;) {
- instance = ((NCR5380_hostdata *) expires_first->host_data)->
- expires_next;
- ((NCR5380_hostdata *) expires_first->host_data)->expires_next =
- NULL;
- ((NCR5380_hostdata *) expires_first->host_data)->time_expires =
- 0;
+ for (; expires_first &&
+ ((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires <= jiffies; )
+ {
+ instance = ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer;
+ ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer = NULL;
+ ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires = 0;
expires_first = instance;
}
- if (expires_first) {
- timer_table[NCR5380_TIMER].expires = ((NCR5380_hostdata *)
- expires_first->host_data)->time_expires;
- timer_active |= (1 << NCR5380_TIMER);
- } else {
- timer_table[NCR5380_TIMER].expires = 0;
- timer_active &= ~(1 << MCR5380_TIMER);
+ del_timer(&usleep_timer);
+ if (expires_first)
+ {
+ usleep_timer.expires = ((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires;
+ add_timer(&usleep_timer);
}
restore_flags(flags);
@@ -696,8 +709,8 @@
#endif
done = 1;
#ifdef USLEEP
- timer_table[NCR5380_TIMER].expires = 0;
- timer_table[NCR5380_TIMER].fn = NCR5380_timer_fn;
+ init_timer(&usleep_timer);
+ usleep_timer.function = NCR5380_timer_fn;
#endif
}
}
@@ -1269,7 +1282,11 @@
hostdata = (struct NCR5380_hostdata *) instance->hostdata;
save_flags(flags);
cli();
+#ifdef USLEEP
+ if (!hostdata->connected && !hostdata->selecting) {
+#else
if (!hostdata->connected) {
+#endif
#if (NDEBUG & NDEBUG_MAIN)
printk("scsi%d : not connected\n", instance->host_no);
#endif
@@ -1326,6 +1343,10 @@
* and see if we can do an information transfer,
* with failures we will restart.
*/
+#ifdef USLEEP
+ hostdata->selecting = 0; /* RvC: have to preset this
+ to indicate a new command is being performed */
+#endif
if (!NCR5380_select(instance, tmp,
/*
@@ -1355,12 +1376,42 @@
} /* if target/lun is not busy */
} /* for */
} /* if (!hostdata->connected) */
+#ifdef USLEEP
+ if (hostdata->selecting)
+ {
+ tmp = (Scsi_Cmnd *)hostdata->selecting;
+ if (!NCR5380_select(instance, tmp,
+ (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT))
+ {
+ /* Ok ?? */
+ }
+ else
+ {
+ unsigned long flags;
+ /* RvC: device failed, so we wait a long time
+ this is needed for Mustek scanners, that
+ do not respond to commands immediately
+ after a scan */
+ printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n",
+ instance->host_no, tmp->target);
+ save_flags(flags);
+ cli();
+ LIST(tmp, hostdata->issue_queue);
+ tmp->host_scribble = (unsigned char *) hostdata->issue_queue;
+ hostdata->issue_queue = tmp;
+ restore_flags(flags);
+
+ hostdata->time_expires = jiffies + USLEEP_WAITLONG;
+ NCR5380_set_timer (instance);
+ }
+ } /* if hostdata->selecting */
+#endif
if (hostdata->connected
#ifdef REAL_DMA
&& !hostdata->dmalen
#endif
#ifdef USLEEP
- && (!hostdata->time_expires || hostdata->time_expires >= jiffies)
+ && (!hostdata->time_expires || hostdata->time_expires <= jiffies)
#endif
) {
restore_flags(flags);
@@ -1377,6 +1428,7 @@
break;
} /* for instance */
} while (!done);
+ cli();
main_running = 0;
}
@@ -1567,13 +1619,21 @@
NCR5380_local_declare();
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
unsigned char tmp[3], phase;
- unsigned char *data;
+ unsigned char *data, value;
int len;
unsigned long timeout;
unsigned long flags;
NCR5380_setup(instance);
+#ifdef USLEEP
+ if (hostdata->selecting)
+ {
+ goto part2; /* RvC: sorry prof. Dijkstra, but it keeps the
+ rest of the code nearly the same */
+ }
+#endif
+
hostdata->restart_select = 0;
#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION)
NCR5380_print(instance);
@@ -1646,7 +1706,13 @@
}
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL);
- if (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) {
+ if (!(hostdata->flags & FLAG_DTC3181E) &&
+ /* RvC: DTC3181E has some trouble with this
+ * so we simply removed it. Seems to work with
+ * only Mustek scanner attached
+ */
+ (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST))
+ {
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
#if (NDEBUG & NDEBUG_ARBITRATION)
@@ -1736,9 +1802,32 @@
* and it's detecting as true. Sigh.
*/
+#ifdef USLEEP
+ hostdata->select_time = 0; /* we count the clock ticks at which we polled */
+ hostdata->selecting = cmd;
+
+part2:
+ /* RvC: here we enter after a sleeping period, or immediately after
+ execution of part 1
+ we poll only once ech clock tick */
+ value = NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO);
+
+ if (!value && (hostdata->select_time < 25))
+ {
+ /* RvC: we still must wait for a device response */
+ hostdata->select_time++; /* after 25 ticks the device has failed */
+ hostdata->time_expires = jiffies + 1;
+ NCR5380_set_timer(instance);
+ return 0; /* RvC: we return here with hostdata->selecting set,
+ to go to sleep */
+ }
+
+ hostdata->selecting = 0; /* clear this pointer, because we passed the
+ waiting period */
+#else
while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) &
(SR_BSY | SR_IO)));
-
+#endif
if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) ==
(SR_SEL | SR_IO)) {
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@@ -1764,7 +1853,7 @@
printk("scsi%d : weirdness\n", instance->host_no);
if (hostdata->restart_select)
printk("\trestart select\n");
-#ifdef NDEBUG
+#if (NDEBUG & NDEBUG_SELECTION)
NCR5380_print(instance);
#endif
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -1896,7 +1985,14 @@
register unsigned char p = *phase, tmp;
register int c = *count;
register unsigned char *d = *data;
- NCR5380_setup(instance);
+#ifdef USLEEP
+ /*
+ * RvC: some administrative data to process polling time
+ */
+ int break_allowed = 0;
+ struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+#endif
+ NCR5380_setup(instance);
#if (NDEBUG & NDEBUG_PIO)
if (!(p & SR_IO))
@@ -1913,12 +2009,41 @@
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+#ifdef USLEEP
+ /* RvC: don't know if this is necessary, but other SCSI I/O is short
+ * so breaks are not necessary there
+ */
+ if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT))
+ {
+ break_allowed = 1;
+ }
+#endif
+
+
do {
/*
* Wait for assertion of REQ, after which the phase bits will be
* valid
*/
- while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
+
+#ifdef USLEEP
+ /* RvC: we simply poll once, after that we stop temporarily
+ * and let the device buffer fill up
+ * if breaking is not allowed, we keep polling as long as needed
+ */
+
+ while ( !((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) &&
+ !break_allowed );
+ if (!(tmp & SR_REQ))
+ {
+ /* timeout condition */
+ hostdata->time_expires = jiffies + USLEEP_SLEEP;
+ NCR5380_set_timer (instance);
+ break;
+ }
+#else
+ while ( !((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) );
+#endif
#if (NDEBUG & NDEBUG_HANDSHAKE)
printk("scsi%d : REQ detected\n", instance->host_no);
@@ -2468,7 +2593,12 @@
unsigned char *data;
unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
- NCR5380_setup(instance);
+#ifdef USLEEP
+ /* RvC: we need to set the end of the polling time */
+ unsigned long poll_time = jiffies + USLEEP_POLL;
+#endif
+
+ NCR5380_setup(instance);
while (1) {
tmp = NCR5380_read(STATUS_REG);
@@ -2899,7 +3029,9 @@
NCR5380_transfer_pio(instance, &phase, &len,
&data);
#ifdef USLEEP
- if (!disconnect && should_disconnect(cmd->cmnd[0])) {
+ if (!cmd->device->disconnect &&
+ should_disconnect(cmd->cmnd[0]))
+ {
hostdata->time_expires = jiffies + USLEEP_SLEEP;
#if (NDEBUG & NDEBUG_USLEEP)
printk("scsi%d : issued command, sleeping until %ul\n", instance->host_no,
@@ -2924,9 +3056,12 @@
} /* switch(phase) */
} /* if (tmp * SR_REQ) */
#ifdef USLEEP
- else {
- if (!disconnect && hostdata->time_expires && jiffies >
- hostdata->time_expires) {
+ else
+ {
+ /* RvC: go to sleep if polling time expired
+ */
+ if (!cmd->device->disconnect && jiffies >= poll_time)
+ {
hostdata->time_expires = jiffies + USLEEP_SLEEP;
#if (NDEBUG & NDEBUG_USLEEP)
printk("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no,
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov