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