aic7xxx_proc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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. #include <linux/config.h>
  32. #define BLS (&aic7xxx_buffer[size])
  33. #define HDRB \
  34. " 0 - 4K 4 - 16K 16 - 64K 64 - 256K 256K - 1M 1M+"
  35. #ifdef PROC_DEBUG
  36. extern int vsprintf(char *, const char *, va_list);
  37. static void
  38. proc_debug(const char *fmt, ...)
  39. {
  40. va_list ap;
  41. char buf[256];
  42. va_start(ap, fmt);
  43. vsprintf(buf, fmt, ap);
  44. printk(buf);
  45. va_end(ap);
  46. }
  47. #else /* PROC_DEBUG */
  48. # define proc_debug(fmt, args...)
  49. #endif /* PROC_DEBUG */
  50. static int aic7xxx_buffer_size = 0;
  51. static char *aic7xxx_buffer = NULL;
  52. /*+F*************************************************************************
  53. * Function:
  54. * aic7xxx_set_info
  55. *
  56. * Description:
  57. * Set parameters for the driver from the /proc filesystem.
  58. *-F*************************************************************************/
  59. static int
  60. aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
  61. {
  62. proc_debug("aic7xxx_set_info(): %s\n", buffer);
  63. return (-ENOSYS); /* Currently this is a no-op */
  64. }
  65. /*+F*************************************************************************
  66. * Function:
  67. * aic7xxx_proc_info
  68. *
  69. * Description:
  70. * Return information to handle /proc support for the driver.
  71. *-F*************************************************************************/
  72. int
  73. aic7xxx_proc_info ( struct Scsi_Host *HBAptr, char *buffer, char **start, off_t offset, int length,
  74. int inout)
  75. {
  76. struct aic7xxx_host *p;
  77. struct aic_dev_data *aic_dev;
  78. struct scsi_device *sdptr;
  79. int size = 0;
  80. unsigned char i;
  81. unsigned char tindex;
  82. for(p=first_aic7xxx; p && p->host != HBAptr; p=p->next)
  83. ;
  84. if (!p)
  85. {
  86. size += sprintf(buffer, "Can't find adapter for host number %d\n", HBAptr->host_no);
  87. if (size > length)
  88. {
  89. return (size);
  90. }
  91. else
  92. {
  93. return (length);
  94. }
  95. }
  96. if (inout == TRUE) /* Has data been written to the file? */
  97. {
  98. return (aic7xxx_set_info(buffer, length, HBAptr));
  99. }
  100. p = (struct aic7xxx_host *) HBAptr->hostdata;
  101. /*
  102. * It takes roughly 1K of space to hold all relevant card info, not
  103. * counting any proc stats, so we start out with a 1.5k buffer size and
  104. * if proc_stats is defined, then we sweep the stats structure to see
  105. * how many drives we will be printing out for and add 384 bytes per
  106. * device with active stats.
  107. *
  108. * Hmmmm...that 1.5k seems to keep growing as items get added so they
  109. * can be easily viewed for debugging purposes. So, we bumped that
  110. * 1.5k to 4k so we can quit having to bump it all the time.
  111. */
  112. size = 4096;
  113. list_for_each_entry(aic_dev, &p->aic_devs, list)
  114. size += 512;
  115. if (aic7xxx_buffer_size != size)
  116. {
  117. if (aic7xxx_buffer != NULL)
  118. {
  119. kfree(aic7xxx_buffer);
  120. aic7xxx_buffer_size = 0;
  121. }
  122. aic7xxx_buffer = kmalloc(size, GFP_KERNEL);
  123. }
  124. if (aic7xxx_buffer == NULL)
  125. {
  126. size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n",
  127. __LINE__);
  128. return size;
  129. }
  130. aic7xxx_buffer_size = size;
  131. size = 0;
  132. size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
  133. size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
  134. size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
  135. size += sprintf(BLS, "\n");
  136. size += sprintf(BLS, "Adapter Configuration:\n");
  137. size += sprintf(BLS, " SCSI Adapter: %s\n",
  138. board_names[p->board_name_index]);
  139. if (p->flags & AHC_TWIN)
  140. size += sprintf(BLS, " Twin Channel Controller ");
  141. else
  142. {
  143. char *channel = "";
  144. char *ultra = "";
  145. char *wide = "Narrow ";
  146. if (p->flags & AHC_MULTI_CHANNEL)
  147. {
  148. channel = " Channel A";
  149. if (p->flags & (AHC_CHNLB|AHC_CHNLC))
  150. channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
  151. }
  152. if (p->features & AHC_WIDE)
  153. wide = "Wide ";
  154. if (p->features & AHC_ULTRA3)
  155. {
  156. switch(p->chip & AHC_CHIPID_MASK)
  157. {
  158. case AHC_AIC7892:
  159. case AHC_AIC7899:
  160. ultra = "Ultra-160/m LVD/SE ";
  161. break;
  162. default:
  163. ultra = "Ultra-3 LVD/SE ";
  164. break;
  165. }
  166. }
  167. else if (p->features & AHC_ULTRA2)
  168. ultra = "Ultra-2 LVD/SE ";
  169. else if (p->features & AHC_ULTRA)
  170. ultra = "Ultra ";
  171. size += sprintf(BLS, " %s%sController%s ",
  172. ultra, wide, channel);
  173. }
  174. switch(p->chip & ~AHC_CHIPID_MASK)
  175. {
  176. case AHC_VL:
  177. size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn);
  178. break;
  179. case AHC_EISA:
  180. size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn);
  181. break;
  182. default:
  183. size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus,
  184. PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn));
  185. break;
  186. }
  187. if( !(p->maddr) )
  188. {
  189. size += sprintf(BLS, " Programmed I/O Base: %lx\n", p->base);
  190. }
  191. else
  192. {
  193. size += sprintf(BLS, " PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
  194. }
  195. if( (p->chip & (AHC_VL | AHC_EISA)) )
  196. {
  197. size += sprintf(BLS, " BIOS Memory Address: 0x%08x\n", p->bios_address);
  198. }
  199. size += sprintf(BLS, " Adapter SEEPROM Config: %s\n",
  200. (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
  201. ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
  202. "SEEPROM not found, using leftover BIOS values.") );
  203. size += sprintf(BLS, " Adaptec SCSI BIOS: %s\n",
  204. (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
  205. size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq);
  206. size += sprintf(BLS, " SCBs: Active %d, Max Active %d,\n",
  207. p->activescbs, p->max_activescbs);
  208. size += sprintf(BLS, " Allocated %d, HW %d, "
  209. "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
  210. p->scb_data->maxscbs);
  211. if (p->flags & AHC_EXTERNAL_SRAM)
  212. size += sprintf(BLS, " Using External SCB SRAM\n");
  213. size += sprintf(BLS, " Interrupts: %ld", p->isr_count);
  214. if (p->chip & AHC_EISA)
  215. {
  216. size += sprintf(BLS, " %s\n",
  217. (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
  218. }
  219. else
  220. {
  221. size += sprintf(BLS, "\n");
  222. }
  223. size += sprintf(BLS, " BIOS Control Word: 0x%04x\n",
  224. p->bios_control);
  225. size += sprintf(BLS, " Adapter Control Word: 0x%04x\n",
  226. p->adapter_control);
  227. size += sprintf(BLS, " Extended Translation: %sabled\n",
  228. (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
  229. size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
  230. if (p->features & (AHC_ULTRA | AHC_ULTRA2))
  231. {
  232. size += sprintf(BLS, " Ultra Enable Flags: 0x%04x\n", p->ultraenb);
  233. }
  234. size += sprintf(BLS, "Default Tag Queue Depth: %d\n", aic7xxx_default_queue_depth);
  235. size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host "
  236. "instance %d:\n", p->instance);
  237. size += sprintf(BLS, " {");
  238. for(i=0; i < (MAX_TARGETS - 1); i++)
  239. size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
  240. size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
  241. size += sprintf(BLS, "\n");
  242. size += sprintf(BLS, "Statistics:\n\n");
  243. list_for_each_entry(aic_dev, &p->aic_devs, list)
  244. {
  245. sdptr = aic_dev->SDptr;
  246. tindex = sdptr->channel << 3 | sdptr->id;
  247. size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
  248. p->host_no, sdptr->channel, sdptr->id, sdptr->lun);
  249. size += sprintf(BLS, " Device using %s/%s",
  250. (aic_dev->cur.width == MSG_EXT_WDTR_BUS_16_BIT) ?
  251. "Wide" : "Narrow",
  252. (aic_dev->cur.offset != 0) ?
  253. "Sync transfers at " : "Async transfers.\n" );
  254. if (aic_dev->cur.offset != 0)
  255. {
  256. struct aic7xxx_syncrate *sync_rate;
  257. unsigned char options = aic_dev->cur.options;
  258. int period = aic_dev->cur.period;
  259. int rate = (aic_dev->cur.width ==
  260. MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
  261. sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
  262. if (sync_rate != NULL)
  263. {
  264. size += sprintf(BLS, "%s MByte/sec, offset %d\n",
  265. sync_rate->rate[rate],
  266. aic_dev->cur.offset );
  267. }
  268. else
  269. {
  270. size += sprintf(BLS, "3.3 MByte/sec, offset %d\n",
  271. aic_dev->cur.offset );
  272. }
  273. }
  274. size += sprintf(BLS, " Transinfo settings: ");
  275. size += sprintf(BLS, "current(%d/%d/%d/%d), ",
  276. aic_dev->cur.period,
  277. aic_dev->cur.offset,
  278. aic_dev->cur.width,
  279. aic_dev->cur.options);
  280. size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
  281. aic_dev->goal.period,
  282. aic_dev->goal.offset,
  283. aic_dev->goal.width,
  284. aic_dev->goal.options);
  285. size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
  286. p->user[tindex].period,
  287. p->user[tindex].offset,
  288. p->user[tindex].width,
  289. p->user[tindex].options);
  290. if(sdptr->simple_tags)
  291. {
  292. size += sprintf(BLS, " Tagged Command Queueing Enabled, Ordered Tags %s, Depth %d/%d\n", sdptr->ordered_tags ? "Enabled" : "Disabled", sdptr->queue_depth, aic_dev->max_q_depth);
  293. }
  294. if(aic_dev->barrier_total)
  295. size += sprintf(BLS, " Total transfers %ld:\n (%ld/%ld/%ld/%ld reads/writes/REQ_BARRIER/Ordered Tags)\n",
  296. aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total,
  297. aic_dev->barrier_total, aic_dev->ordered_total);
  298. else
  299. size += sprintf(BLS, " Total transfers %ld:\n (%ld/%ld reads/writes)\n",
  300. aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total);
  301. size += sprintf(BLS, "%s\n", HDRB);
  302. size += sprintf(BLS, " Reads:");
  303. for (i = 0; i < ARRAY_SIZE(aic_dev->r_bins); i++)
  304. {
  305. size += sprintf(BLS, " %10ld", aic_dev->r_bins[i]);
  306. }
  307. size += sprintf(BLS, "\n");
  308. size += sprintf(BLS, " Writes:");
  309. for (i = 0; i < ARRAY_SIZE(aic_dev->w_bins); i++)
  310. {
  311. size += sprintf(BLS, " %10ld", aic_dev->w_bins[i]);
  312. }
  313. size += sprintf(BLS, "\n");
  314. size += sprintf(BLS, "\n\n");
  315. }
  316. if (size >= aic7xxx_buffer_size)
  317. {
  318. printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n");
  319. }
  320. if (offset > size - 1)
  321. {
  322. kfree(aic7xxx_buffer);
  323. aic7xxx_buffer = NULL;
  324. aic7xxx_buffer_size = length = 0;
  325. *start = NULL;
  326. }
  327. else
  328. {
  329. *start = buffer;
  330. length = min_t(int, length, size - offset);
  331. memcpy(buffer, &aic7xxx_buffer[offset], length);
  332. }
  333. return (length);
  334. }
  335. /*
  336. * Overrides for Emacs so that we follow Linus's tabbing style.
  337. * Emacs will notice this stuff at the end of the file and automatically
  338. * adjust the settings for this buffer only. This must remain at the end
  339. * of the file.
  340. * ---------------------------------------------------------------------------
  341. * Local variables:
  342. * c-indent-level: 2
  343. * c-brace-imaginary-offset: 0
  344. * c-brace-offset: -2
  345. * c-argdecl-indent: 2
  346. * c-label-offset: -2
  347. * c-continued-statement-offset: 2
  348. * c-continued-brace-offset: 0
  349. * indent-tabs-mode: nil
  350. * tab-width: 8
  351. * End:
  352. */