File: /usr/src/linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c

1     /*+M*************************************************************************
2      * Adaptec AIC7xxx device driver proc support for Linux.
3      *
4      * Copyright (c) 1995, 1996 Dean W. Gehnert
5      *
6      * This program is free software; you can redistribute it and/or modify
7      * it under the terms of the GNU General Public License as published by
8      * the Free Software Foundation; either version 2, or (at your option)
9      * any later version.
10      *
11      * This program is distributed in the hope that it will be useful,
12      * but WITHOUT ANY WARRANTY; without even the implied warranty of
13      * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14      * GNU General Public License for more details.
15      *
16      * You should have received a copy of the GNU General Public License
17      * along with this program; see the file COPYING.  If not, write to
18      * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19      *
20      * ----------------------------------------------------------------
21      *  o Modified from the EATA-DMA /proc support.
22      *  o Additional support for device block statistics provided by
23      *    Matthew Jacob.
24      *  o Correction of overflow by Heinz Mauelshagen
25      *  o Adittional corrections by Doug Ledford
26      *
27      *  Dean W. Gehnert, deang@teleport.com, 05/01/96
28      *
29      *  $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
30      *-M*************************************************************************/
31     
32     #include <linux/config.h>
33     
34     #define	BLS	(&aic7xxx_buffer[size])
35     #define HDRB \
36     "             < 2K      2K+     4K+     8K+    16K+    32K+    64K+   128K+"
37     
38     #ifdef PROC_DEBUG
39     extern int vsprintf(char *, const char *, va_list);
40     
41     static void
42     proc_debug(const char *fmt, ...)
43     {
44       va_list ap;
45       char buf[256];
46     
47       va_start(ap, fmt);
48       vsprintf(buf, fmt, ap);
49       printk(buf);
50       va_end(ap);
51     }
52     #else /* PROC_DEBUG */
53     #  define proc_debug(fmt, args...)
54     #endif /* PROC_DEBUG */
55     
56     static int aic7xxx_buffer_size = 0;
57     static char *aic7xxx_buffer = NULL;
58     
59     
60     /*+F*************************************************************************
61      * Function:
62      *   aic7xxx_set_info
63      *
64      * Description:
65      *   Set parameters for the driver from the /proc filesystem.
66      *-F*************************************************************************/
67     int
68     aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
69     {
70       proc_debug("aic7xxx_set_info(): %s\n", buffer);
71       return (-ENOSYS);  /* Currently this is a no-op */
72     }
73     
74     
75     /*+F*************************************************************************
76      * Function:
77      *   aic7xxx_proc_info
78      *
79      * Description:
80      *   Return information to handle /proc support for the driver.
81      *-F*************************************************************************/
82     int
83     aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, 
84                         int hostno, int inout)
85     {
86       struct Scsi_Host *HBAptr;
87       struct aic7xxx_host *p;
88       int    size = 0;
89       unsigned char i;
90       struct aic7xxx_xferstats *sp;
91       unsigned char target;
92     
93       HBAptr = NULL;
94     
95       for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next)
96         ;
97     
98       if (!p)
99       {
100         size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno);
101         if (size > length)
102         {
103           return (size);
104         }
105         else
106         {
107           return (length);
108         }
109       }
110     
111       HBAptr = p->host;
112     
113       if (inout == TRUE) /* Has data been written to the file? */ 
114       {
115         return (aic7xxx_set_info(buffer, length, HBAptr));
116       }
117     
118       p = (struct aic7xxx_host *) HBAptr->hostdata;
119     
120       /*
121        * It takes roughly 1K of space to hold all relevant card info, not
122        * counting any proc stats, so we start out with a 1.5k buffer size and
123        * if proc_stats is defined, then we sweep the stats structure to see
124        * how many drives we will be printing out for and add 384 bytes per
125        * device with active stats.
126        *
127        * Hmmmm...that 1.5k seems to keep growing as items get added so they
128        * can be easily viewed for debugging purposes.  So, we bumped that
129        * 1.5k to 4k so we can quit having to bump it all the time.
130        */
131     
132       size = 4096;
133       for (target = 0; target < MAX_TARGETS; target++)
134       {
135         if (p->dev_flags[target] & DEVICE_PRESENT)
136     #ifdef AIC7XXX_PROC_STATS
137           size += 512;
138     #else
139           size += 256;
140     #endif
141       }
142       if (aic7xxx_buffer_size != size)
143       {
144         if (aic7xxx_buffer != NULL) 
145         {
146           kfree(aic7xxx_buffer);
147           aic7xxx_buffer_size = 0;
148         }
149         aic7xxx_buffer = kmalloc(size, GFP_KERNEL);
150       }
151       if (aic7xxx_buffer == NULL)
152       {
153         size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n",
154             __LINE__);
155         return size;
156       }
157       aic7xxx_buffer_size = size;
158     
159       size = 0;
160       size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
161       size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
162       size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
163       size += sprintf(BLS, "\n");
164       size += sprintf(BLS, "Compile Options:\n");
165     #ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
166       size += sprintf(BLS, "  TCQ Enabled By Default : Enabled\n");
167     #else
168       size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
169     #endif
170     #ifdef AIC7XXX_PROC_STATS
171       size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
172     #else
173       size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Disabled\n");
174     #endif
175       size += sprintf(BLS, "\n");
176       size += sprintf(BLS, "Adapter Configuration:\n");
177       size += sprintf(BLS, "           SCSI Adapter: %s\n",
178           board_names[p->board_name_index]);
179       if (p->flags & AHC_TWIN)
180         size += sprintf(BLS, "                         Twin Channel Controller ");
181       else
182       {
183         char *channel = "";
184         char *ultra = "";
185         char *wide = "Narrow ";
186         if (p->flags & AHC_MULTI_CHANNEL)
187         {
188           channel = " Channel A";
189           if (p->flags & (AHC_CHNLB|AHC_CHNLC))
190             channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
191         }
192         if (p->features & AHC_WIDE)
193           wide = "Wide ";
194         if (p->features & AHC_ULTRA3)
195         {
196           switch(p->chip & AHC_CHIPID_MASK)
197           {
198             case AHC_AIC7892:
199             case AHC_AIC7899:
200               ultra = "Ultra-160/m LVD/SE ";
201               break;
202             default:
203               ultra = "Ultra-3 LVD/SE ";
204               break;
205           }
206         }
207         else if (p->features & AHC_ULTRA2)
208           ultra = "Ultra-2 LVD/SE ";
209         else if (p->features & AHC_ULTRA)
210           ultra = "Ultra ";
211         size += sprintf(BLS, "                           %s%sController%s ",
212           ultra, wide, channel);
213       }
214       switch(p->chip & ~AHC_CHIPID_MASK)
215       {
216         case AHC_VL:
217           size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn);
218           break;
219         case AHC_EISA:
220           size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn);
221           break;
222         default:
223           size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus,
224             PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn));
225           break;
226       }
227       if( !(p->maddr) )
228       {
229         size += sprintf(BLS, "    Programmed I/O Base: %lx\n", p->base);
230       }
231       else
232       {
233         size += sprintf(BLS, "    PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
234       }
235       if( (p->chip & (AHC_VL | AHC_EISA)) )
236       {
237         size += sprintf(BLS, "    BIOS Memory Address: 0x%08x\n", p->bios_address);
238       }
239       size += sprintf(BLS, " Adapter SEEPROM Config: %s\n",
240               (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
241              ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
242                "SEEPROM not found, using leftover BIOS values.") );
243       size += sprintf(BLS, "      Adaptec SCSI BIOS: %s\n",
244               (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
245       size += sprintf(BLS, "                    IRQ: %d\n", HBAptr->irq);
246       size += sprintf(BLS, "                   SCBs: Active %d, Max Active %d,\n",
247                 p->activescbs, p->max_activescbs);
248       size += sprintf(BLS, "                         Allocated %d, HW %d, "
249                 "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
250                 p->scb_data->maxscbs);
251       if (p->flags & AHC_EXTERNAL_SRAM)
252         size += sprintf(BLS, "                         Using External SCB SRAM\n");
253       size += sprintf(BLS, "             Interrupts: %ld", p->isr_count);
254       if (p->chip & AHC_EISA)
255       {
256         size += sprintf(BLS, " %s\n",
257             (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
258       }
259       else
260       {
261         size += sprintf(BLS, "\n");
262       }
263       size += sprintf(BLS, "      BIOS Control Word: 0x%04x\n",
264                 p->bios_control);
265       size += sprintf(BLS, "   Adapter Control Word: 0x%04x\n",
266                 p->adapter_control);
267       size += sprintf(BLS, "   Extended Translation: %sabled\n",
268           (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
269       size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
270       if (p->features & (AHC_ULTRA | AHC_ULTRA2))
271       {
272         size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
273       }
274       size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
275       size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
276       size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE);
277       size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
278                            "instance %d:\n", p->instance);
279       size += sprintf(BLS, "      {");
280       for(i=0; i < (MAX_TARGETS - 1); i++)
281         size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
282       size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
283       size += sprintf(BLS, "    Actual queue depth per device for aic7xxx host "
284                            "instance %d:\n", p->instance);
285       size += sprintf(BLS, "      {");
286       for(i=0; i < (MAX_TARGETS - 1); i++)
287         size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]);
288       size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
289     
290       size += sprintf(BLS, "\n");
291       size += sprintf(BLS, "Statistics:\n\n");
292       for (target = 0; target < MAX_TARGETS; target++)
293       {
294         sp = &p->stats[target];
295         if ((p->dev_flags[target] & DEVICE_PRESENT) == 0)
296         {
297           continue;
298         }
299         if (p->features & AHC_TWIN)
300         {
301           size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
302               p->host_no, (target >> 3), (target & 0x7), 0);
303         }
304         else
305         {
306           size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
307               p->host_no, 0, target, 0);
308         }
309         size += sprintf(BLS, "  Device using %s/%s",
310               (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ?
311               "Wide" : "Narrow",
312               (p->transinfo[target].cur_offset != 0) ?
313               "Sync transfers at " : "Async transfers.\n" );
314         if (p->transinfo[target].cur_offset != 0)
315         {
316           struct aic7xxx_syncrate *sync_rate;
317           unsigned char options = p->transinfo[target].cur_options;
318           int period = p->transinfo[target].cur_period;
319           int rate = (p->transinfo[target].cur_width ==
320                       MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
321     
322           sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
323           if (sync_rate != NULL)
324           {
325             size += sprintf(BLS, "%s MByte/sec, offset %d\n",
326                             sync_rate->rate[rate],
327                             p->transinfo[target].cur_offset );
328           }
329           else
330           {
331             size += sprintf(BLS, "3.3 MByte/sec, offset %d\n",
332                             p->transinfo[target].cur_offset );
333           }
334         }
335         size += sprintf(BLS, "  Transinfo settings: ");
336         size += sprintf(BLS, "current(%d/%d/%d/%d), ",
337                         p->transinfo[target].cur_period,
338                         p->transinfo[target].cur_offset,
339                         p->transinfo[target].cur_width,
340                         p->transinfo[target].cur_options);
341         size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
342                         p->transinfo[target].goal_period,
343                         p->transinfo[target].goal_offset,
344                         p->transinfo[target].goal_width,
345                         p->transinfo[target].goal_options);
346         size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
347                         p->transinfo[target].user_period,
348                         p->transinfo[target].user_offset,
349                         p->transinfo[target].user_width,
350                         p->transinfo[target].user_options);
351     #ifdef AIC7XXX_PROC_STATS
352         size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
353             sp->r_total + sp->w_total, sp->r_total, sp->w_total);
354         size += sprintf(BLS, "%s\n", HDRB);
355         size += sprintf(BLS, "   Reads:");
356         for (i = 0; i < NUMBER(sp->r_bins); i++)
357         {
358           size += sprintf(BLS, " %7ld", sp->r_bins[i]);
359         }
360         size += sprintf(BLS, "\n");
361         size += sprintf(BLS, "  Writes:");
362         for (i = 0; i < NUMBER(sp->w_bins); i++)
363         {
364           size += sprintf(BLS, " %7ld", sp->w_bins[i]);
365         }
366         size += sprintf(BLS, "\n");
367     #else
368         size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
369             sp->r_total + sp->w_total, sp->r_total, sp->w_total);
370     #endif /* AIC7XXX_PROC_STATS */
371         size += sprintf(BLS, "\n\n");
372       }
373     
374       if (size >= aic7xxx_buffer_size)
375       {
376         printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n");
377       }
378     
379       if (offset > size - 1)
380       {
381         kfree(aic7xxx_buffer);
382         aic7xxx_buffer = NULL;
383         aic7xxx_buffer_size = length = 0;
384         *start = NULL;
385       }
386       else
387       {
388         *start = buffer;
389         length = MIN(length, size - offset);
390         memcpy(buffer, &aic7xxx_buffer[offset], length);
391       }
392     
393       return (length);
394     }
395     
396     /*
397      * Overrides for Emacs so that we follow Linus's tabbing style.
398      * Emacs will notice this stuff at the end of the file and automatically
399      * adjust the settings for this buffer only.  This must remain at the end
400      * of the file.
401      * ---------------------------------------------------------------------------
402      * Local variables:
403      * c-indent-level: 2
404      * c-brace-imaginary-offset: 0
405      * c-brace-offset: -2
406      * c-argdecl-indent: 2
407      * c-label-offset: -2
408      * c-continued-statement-offset: 2
409      * c-continued-brace-offset: 0
410      * indent-tabs-mode: nil
411      * tab-width: 8
412      * End:
413      */
414