diff options
Diffstat (limited to 'drivers/scsi/aic7xxx_proc.c')
-rw-r--r-- | drivers/scsi/aic7xxx_proc.c | 254 |
1 files changed, 132 insertions, 122 deletions
diff --git a/drivers/scsi/aic7xxx_proc.c b/drivers/scsi/aic7xxx_proc.c index dee247534..8ad2cfb03 100644 --- a/drivers/scsi/aic7xxx_proc.c +++ b/drivers/scsi/aic7xxx_proc.c @@ -21,13 +21,15 @@ * o Modified from the EATA-DMA /proc support. * o Additional support for device block statistics provided by * Matthew Jacob. + * o Correction of overflow by Heinz Mauelshagen + * o Adittional corrections by Doug Ledford * * Dean W. Gehnert, deang@teleport.com, 05/01/96 * * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $ *-M*************************************************************************/ -#define BLS buffer + len + size +#define BLS (&aic7xxx_buffer[size]) #define HDRB \ " < 512 512-1K 1-2K 2-4K 4-8K 8-16K 16-32K 32-64K 64-128K >128K" @@ -49,6 +51,13 @@ proc_debug(const char *fmt, ...) # define proc_debug(fmt, args...) #endif /* PROC_DEBUG */ +static int aic7xxx_buffer_size = 0; +static char *aic7xxx_buffer = NULL; +static const char *bus_names[] = { "Single", "Twin", "Wide" }; +static const char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x", + "AIC-787x", "AIC-788x" }; + + /*+F************************************************************************* * Function: * aic7xxx_set_info @@ -63,6 +72,7 @@ aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) return (-ENOSYS); /* Currently this is a no-op */ } + /*+F************************************************************************* * Function: * aic7xxx_proc_info @@ -71,20 +81,18 @@ aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) * Return information to handle /proc support for the driver. *-F*************************************************************************/ int -aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout) +aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, + int hostno, int inout) { struct Scsi_Host *HBAptr; struct aic7xxx_host *p; - int i; - int found = FALSE; - int size = 0; - int len = 0; - off_t begin = 0; - off_t pos = 0; - static char *bus_names[] = { "Single", "Twin", "Wide" }; - static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x", - "AIC-787x", "AIC-788x" }; + int found = FALSE; + int size = 0; + unsigned char i; +#ifdef AIC7XXX_PROC_STATS + struct aic7xxx_xferstats *sp; + unsigned char target, lun; +#endif HBAptr = NULL; for (i=0; i < NUMBER(aic7xxx_boards); i++) @@ -118,9 +126,15 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length, if (HBAptr == NULL) { - size += sprintf(BLS, "Can't find adapter for host number %d\n", hostno); - len += size; pos = begin + len; size = 0; - goto stop_output; + size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno); + if (size > length) + { + return (size); + } + else + { + return (length); + } } if (inout == TRUE) /* Has data been written to the file? */ @@ -130,21 +144,49 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length, p = (struct aic7xxx_host *) HBAptr->hostdata; + /* + * It takes roughly 1K of space to hold all relevant card info, not + * counting any proc stats, so we start out with a 1.5k buffer size and + * if proc_stats is defined, then we sweep the stats structure to see + * how many drives we will be printing out for and add 384 bytes per + * device with active stats. + */ + + size = 1536; +#ifdef AIC7XXX_PROC_STATS + for (target = 0; target < MAX_TARGETS; target++) + { + for (lun = 0; lun < MAX_LUNS; lun++) + { + if (p->stats[target][lun].xfers != 0) + size += 384; + } + } +#endif + if (aic7xxx_buffer_size != size) + { + if (aic7xxx_buffer != NULL) + { + kfree(aic7xxx_buffer); + aic7xxx_buffer_size = 0; + } + aic7xxx_buffer = kmalloc(size, GFP_KERNEL); + } + if (aic7xxx_buffer == NULL) + { + size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n", + __LINE__); + return size; + } + aic7xxx_buffer_size = size; + + size = 0; size += sprintf(BLS, "Adaptec AIC7xxx driver version: "); size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_C_VERSION)); size += sprintf(BLS, "%s", rcs_version(AIC7XXX_H_VERSION)); #if 0 size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER)); #endif - if (size > 512) - printk(KERN_CRIT "aic7xxx: possible overflow at first position\n"); - len += size; pos = begin + len; size = 0; - if (pos < offset) - { - begin = pos; - len = 0; - } - size += sprintf(BLS, "\n"); size += sprintf(BLS, "Compile Options:\n"); #ifdef AIC7XXX_RESET_DELAY @@ -168,30 +210,19 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length, #else size += sprintf(BLS, " AIC7XXX_PROC_STATS : Disabled\n"); #endif - if (size > 512) - printk(KERN_CRIT "aic7xxx: possible overflow at second position\n"); - len += size; pos = begin + len; size = 0; - if (pos < offset) - { - begin = pos; - len = 0; - } - else if (pos >= offset + length) - goto stop_output; - size += sprintf(BLS, "\n"); size += sprintf(BLS, "Adapter Configuration:\n"); - size += sprintf(BLS, " SCSI Adapter: %s\n", + size += sprintf(BLS, " SCSI Adapter: %s\n", board_names[p->chip_type]); - size += sprintf(BLS, " (%s chipset)\n", + size += sprintf(BLS, " (%s chipset)\n", chip_names[p->chip_class]); - size += sprintf(BLS, " Host Bus: %s\n", bus_names[p->bus_type]); - size += sprintf(BLS, " Base IO: %#.4x\n", p->base); - size += sprintf(BLS, " Base IO Memory: 0x%x\n", p->mbase); - size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); - size += sprintf(BLS, " SCBs: Used %d, HW %d, Page %d\n", + size += sprintf(BLS, " Host Bus: %s\n", bus_names[p->bus_type]); + size += sprintf(BLS, " Base IO: %#.4x\n", p->base); + size += sprintf(BLS, " Base IO Memory: 0x%x\n", p->mbase); + size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); + size += sprintf(BLS, " SCBs: Used %d, HW %d, Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs); - size += sprintf(BLS, " Interrupts: %d", p->isr_count); + size += sprintf(BLS, " Interrupts: %d", p->isr_count); if (p->chip_class == AIC_777x) { size += sprintf(BLS, " %s\n", @@ -201,102 +232,81 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length, { size += sprintf(BLS, "\n"); } - size += sprintf(BLS, " Serial EEPROM: %s\n", + size += sprintf(BLS, " Serial EEPROM: %s\n", (p->flags & HAVE_SEEPROM) ? "True" : "False"); - size += sprintf(BLS, " Extended Translation: %sabled\n", + size += sprintf(BLS, " Extended Translation: %sabled\n", (p->flags & EXTENDED_TRANSLATION) ? "En" : "Dis"); - size += sprintf(BLS, " SCSI Bus Reset: %sabled\n", + size += sprintf(BLS, " SCSI Bus Reset: %sabled\n", aic7xxx_no_reset ? "Dis" : "En"); - size += sprintf(BLS, " Ultra SCSI: %sabled\n", + size += sprintf(BLS, " Ultra SCSI: %sabled\n", (p->flags & ULTRA_ENABLED) ? "En" : "Dis"); - size += sprintf(BLS, " Target Disconnect: %sabled\n", - p->discenable ? "En" : "Dis"); - if (size > 512) - printk(KERN_CRIT "aic7xxx: possible overflow at third position\n"); - len += size; pos = begin + len; size = 0; - if (pos < offset) - { - begin = pos; - len = 0; - } - else if (pos >= offset + length) - goto stop_output; - + size += sprintf(BLS, "Disconnect Enable Flags: 0x%x\n", p->discenable); + #ifdef AIC7XXX_PROC_STATS + size += sprintf(BLS, "\n"); + size += sprintf(BLS, "Statistics:\n"); + for (target = 0; target < MAX_TARGETS; target++) { - struct aic7xxx_xferstats *sp; - int channel, target, lun; - - /* - * XXX: Need to fix this to avoid overflow... - * Fixed - gordo. - */ - size += sprintf(BLS, "\n"); - size += sprintf(BLS, "Statistics:\n"); - for (channel = 0; channel < 2; channel++) + for (lun = 0; lun < MAX_LUNS; lun++) { - for (target = 0; target < 16; target++) + sp = &p->stats[target][lun]; + if (sp->xfers == 0) { - for (lun = 0; lun < 8; lun++) - { - sp = &p->stats[channel][target][lun]; - if (sp->xfers == 0) - { - continue; - } - size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n", - 'A' + channel, target, lun); - size += sprintf(BLS, "nxfers %ld (%ld read;%ld written)\n", - sp->xfers, sp->r_total, sp->w_total); - size += sprintf(BLS, "blks(512) rd=%ld; blks(512) wr=%ld\n", - sp->r_total512, sp->w_total512); - size += sprintf(BLS, "%s\n", HDRB); - size += sprintf(BLS, " Reads:"); - size += sprintf(BLS, "%6ld %6ld %6ld %6ld ", sp->r_bins[0], - sp->r_bins[1], sp->r_bins[2], sp->r_bins[3]); - size += sprintf(BLS, "%6ld %6ld %6ld %6ld ", sp->r_bins[4], - sp->r_bins[5], sp->r_bins[6], sp->r_bins[7]); - size += sprintf(BLS, "%6ld %6ld\n", sp->r_bins[8], - sp->r_bins[9]); - size += sprintf(BLS, "Writes:"); - size += sprintf(BLS, "%6ld %6ld %6ld %6ld ", sp->w_bins[0], - sp->w_bins[1], sp->w_bins[2], sp->w_bins[3]); - size += sprintf(BLS, "%6ld %6ld %6ld %6ld ", sp->w_bins[4], - sp->w_bins[5], sp->w_bins[6], sp->w_bins[7]); - size += sprintf(BLS, "%6ld %6ld\n", sp->w_bins[8], - sp->w_bins[9]); - size += sprintf(BLS, "\n"); - } - if (size > 512) - printk(KERN_CRIT "aic7xxx: possible overflow at loop %d:%d\n", target, lun); - len += size; pos = begin + len; size = 0; - if (pos < offset) - { - begin = pos; - len = 0; - } - else if (pos >= offset + length) - goto stop_output; + continue; } + if (p->bus_type == AIC_TWIN) + { + size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n", + 'A' + (target >> 3), (target & 0x7), lun); + } + else + { + size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n", + 'A', target, lun); + } + size += sprintf(BLS, "nxfers %ld (%ld read;%ld written)\n", + sp->xfers, sp->r_total, sp->w_total); + size += sprintf(BLS, "blks(512) rd=%ld; blks(512) wr=%ld\n", + sp->r_total512, sp->w_total512); + size += sprintf(BLS, "%s\n", HDRB); + size += sprintf(BLS, " Reads:"); + for (i = 0; i < NUMBER(sp->r_bins); i++) + { + size += sprintf(BLS, "%6ld ", sp->r_bins[i]); + } + size += sprintf(BLS, "\n"); + size += sprintf(BLS, "Writes:"); + for (i = 0; i < NUMBER(sp->w_bins); i++) + { + size += sprintf(BLS, "%6ld ", sp->w_bins[i]); + } + size += sprintf(BLS, "\n\n"); } } #endif /* AIC7XXX_PROC_STATS */ -stop_output: - proc_debug("2pos: %ld offset: %ld len: %d\n", pos, offset, len); - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); /* Start slop */ - if (len < 0) + if (size >= aic7xxx_buffer_size) { - len = 0; /* off end of file */ + printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n"); } - else if (len > length) + + if (offset > size - 1) { - len = length; /* Ending slop */ + kfree(aic7xxx_buffer); + aic7xxx_buffer = NULL; + aic7xxx_buffer_size = length = 0; + *start = NULL; } - proc_debug("3pos: %ld offset: %ld len: %d\n", pos, offset, len); - - return (len); + else + { + *start = &aic7xxx_buffer[offset]; /* Start of wanted data */ + if (size - offset < length) + { + length = size - offset; + } + } + + return (length); } /* |