summaryrefslogtreecommitdiffstats
path: root/sys/i386/scsi
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1995-04-23 22:04:58 +0000
committergibbs <gibbs@FreeBSD.org>1995-04-23 22:04:58 +0000
commit08c21a38d32c40274e29f86a6d1b61acc9bd9093 (patch)
treed22772d2ab3012c5bd9a482a72488e466b861cd5 /sys/i386/scsi
parent8248293bc24f14fe38ce81a5fed8f088f18192ba (diff)
downloadFreeBSD-src-08c21a38d32c40274e29f86a6d1b61acc9bd9093.zip
FreeBSD-src-08c21a38d32c40274e29f86a6d1b61acc9bd9093.tar.gz
Don't arbitrarily set SCSI_NOSLEEP. It is now handled correctly by the
higher level scsi code. Spls should never be conditionalized, so don't do so here. Restructure the get_scb routine so that we can't get into an infinite loop if the ccbs are exhausted and we are are called with SCSI_NOSLEEP set. Other driver maintainer's that based their scb allocation routines on Julian's code should look at these changes and implement them for their driver. The aic7xxx driver inspired these changes because early revs of the aic7770 chips have so few SCBs that you can actually run out. If you have a rev C or aic7770 (as is reported by the driver probe) and had more than 2 drives, you could get into an infinite loop when using up all of the SCBs. Since the driver will only allow two SCBs per device and I only had two devices, I never saw this problem on my Rev C card. Bzero only 19 bytes of the scb instead of 2k (ack!). This was a hold over from when a struct SCB only contained the information downloaded to the board, but we now store kernel driver data in there as well. This greatly lowers the overhead for small transactions (I get ~1MB/sec for dds with a 512 byte block size). Submitted by: John Dyson with the aic7xxx specific optimization by me
Diffstat (limited to 'sys/i386/scsi')
-rw-r--r--sys/i386/scsi/aic7xxx.c49
-rw-r--r--sys/i386/scsi/aic7xxx.h12
2 files changed, 39 insertions, 22 deletions
diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c
index 5c34919..c6a739a 100644
--- a/sys/i386/scsi/aic7xxx.c
+++ b/sys/i386/scsi/aic7xxx.c
@@ -24,7 +24,7 @@
*
* commenced: Sun Sep 27 18:14:01 PDT 1992
*
- * $Id: aic7xxx.c,v 1.20 1995/04/09 06:39:01 gibbs Exp $
+ * $Id: aic7xxx.c,v 1.21 1995/04/15 21:37:32 gibbs Exp $
*/
/*
* TODO:
@@ -1081,6 +1081,7 @@ ahcintr(unit)
sg->addr = KVTOPHYS(&xs->sense);
sg->len = sizeof(struct scsi_sense_data);
+
scb->target_channel_lun = tcl;
scb->SG_segment_count = 1;
scb->SG_list_pointer = KVTOPHYS(sg);
@@ -1144,6 +1145,9 @@ ahcintr(unit)
scb->xs->resid = (inb(iobase+SCBARRAY+17) << 16) |
(inb(iobase+SCBARRAY+16) << 8) |
inb(iobase+SCBARRAY+15);
+#ifdef AHC_DEBUG
+ printf("ahc: Handled Residual\n");
+#endif
break;
}
case ABORT_TAG:
@@ -1675,8 +1679,6 @@ ahc_scsi_cmd(xs)
* then we can't allow it to sleep
*/
flags = xs->flags;
- if (xs->bp)
- flags |= (SCSI_NOSLEEP); /* just to be sure */
if (flags & ITSDONE) {
printf("ahc%d: Already done?", unit);
xs->flags &= ~ITSDONE;
@@ -1844,15 +1846,17 @@ ahc_free_scb(unit, scb, flags)
int unit, flags;
struct scb *scb;
{
- unsigned int opri = 0;
+ unsigned int opri;
struct ahc_data *ahc = ahcdata[unit];
- if (!(flags & SCSI_NOMASK))
- opri = splbio();
+ opri = splbio();
scb->flags = SCB_FREE;
scb->next = ahc->free_scb;
ahc->free_scb = scb;
+#ifdef AHC_DEBUG
+ ahc->activescbs--;
+#endif
/*
* If there were none, wake abybody waiting for
* one to come free, starting with queued entries
@@ -1860,8 +1864,7 @@ ahc_free_scb(unit, scb, flags)
if (!scb->next) {
wakeup((caddr_t)&ahc->free_scb);
}
- if (!(flags & SCSI_NOMASK))
- splx(opri);
+ splx(opri);
}
/*
@@ -1874,12 +1877,10 @@ ahc_get_scb(unit, flags)
int unit, flags;
{
struct ahc_data *ahc = ahcdata[unit];
- unsigned opri = 0;
+ unsigned opri;
struct scb *scbp;
- int position;
- if (!(flags & SCSI_NOMASK))
- opri = splbio();
+ opri = splbio();
/*
* If we can and have to, sleep waiting for one to come free
* but only if we can't allocate a new one.
@@ -1925,24 +1926,32 @@ ahc_get_scb(unit, flags)
} else {
printf("ahc%d: Can't malloc SCB\n", unit);
- } goto gottit;
+ }
+ break;
} else {
if (!(flags & SCSI_NOSLEEP)) {
tsleep((caddr_t)&ahc->free_scb, PRIBIO,
"ahcscb", 0);
+ continue;
}
+ break;
}
- } if (scbp) {
+ }
+
+ if (scbp) {
/* Get SCB from from free list */
ahc->free_scb = scbp->next;
- /* preserve the position */
- position = scbp->position;
- bzero(scbp, sizeof(struct scb));
+ bzero(scbp, SCB_BZERO_SIZE);
scbp->flags = SCB_ACTIVE;
- scbp->position = position;
+#ifdef AHC_DEBUG
+ ahc->activescbs++;
+ if( ahc->activescbs == ahc->maxscbs )
+ printf("ahc%d: Max SCBs active\n", unit);
+#endif
}
-gottit: if (!(flags & SCSI_NOMASK))
- splx(opri);
+
+gottit:
+ splx(opri);
return (scbp);
}
diff --git a/sys/i386/scsi/aic7xxx.h b/sys/i386/scsi/aic7xxx.h
index 5183735..c96c696 100644
--- a/sys/i386/scsi/aic7xxx.h
+++ b/sys/i386/scsi/aic7xxx.h
@@ -20,7 +20,7 @@
* 4. Modifications may be freely made to this file if the above conditions
* are met.
*
- * $Id: aic7xxx.h,v 1.4 1995/02/22 01:43:25 gibbs Exp $
+ * $Id: aic7xxx.h,v 1.5 1995/03/31 13:54:41 gibbs Exp $
*/
#ifndef _AIC7XXX_H_
@@ -88,9 +88,16 @@ struct scb {
/*18*/ u_char residual_data_count[3];
/*19*/ u_char residual_SG_segment_count;
#define SCB_DOWN_SIZE 19 /* amount to actually download */
+#define SCB_BZERO_SIZE 19 /*
+ * amount we need to clear between
+ * commands
+ */
/*23*/ physaddr data __attribute__ ((packed));
/*26*/ u_char datalen[3];
-#define SCB_UP_SIZE 26 /* amount to actually upload */
+#define SCB_UP_SIZE 26 /*
+ * amount we need to upload to perform
+ * a request sense.
+ */
/*30*/ physaddr host_scb __attribute__ ((packed));
#if 0
/*
@@ -136,6 +143,7 @@ struct ahc_data {
u_short wdtrpending; /* Pending WDTR to these targets */
u_short tagenable; /* Targets that can handle tagqueing */
int numscbs;
+ int activescbs;
u_char maxscbs;
u_char unpause;
u_char pause;
OpenPOWER on IntegriCloud