aic7xxx_proc.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 2000-2001 Adaptec Inc.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions, and the following disclaimer,
  10.  *    without modification.
  11.  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  12.  *    substantially similar to the "NO WARRANTY" disclaimer below
  13.  *    ("Disclaimer") and any redistribution must be conditioned upon
  14.  *    including a substantially similar Disclaimer requirement for further
  15.  *    binary redistribution.
  16.  * 3. Neither the names of the above-listed copyright holders nor the names
  17.  *    of any contributors may be used to endorse or promote products derived
  18.  *    from this software without specific prior written permission.
  19.  *
  20.  * Alternatively, this software may be distributed under the terms of the
  21.  * GNU General Public License ("GPL") version 2 as published by the Free
  22.  * Software Foundation.
  23.  *
  24.  * NO WARRANTY
  25.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  26.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  27.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  28.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  29.  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  33.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  34.  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  35.  * POSSIBILITY OF SUCH DAMAGES.
  36.  *
  37.  * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
  38.  * sym driver.
  39.  *
  40.  * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#13 $
  41.  */
  42. #include "aic7xxx_osm.h"
  43. #include "aic7xxx_inline.h"
  44. static void copy_mem_info(struct info_str *info, char *data, int len);
  45. static int copy_info(struct info_str *info, char *fmt, ...);
  46. static u_int scsi_calc_syncsrate(u_int period_factor);
  47. static void ahc_dump_target_state(struct ahc_softc *ahc,
  48.       struct info_str *info,
  49.       u_int our_id, char channel,
  50.       u_int target_id, u_int target_offset);
  51. static void ahc_dump_device_state(struct info_str *info,
  52.       struct ahc_linux_device *dev);
  53. static void
  54. copy_mem_info(struct info_str *info, char *data, int len)
  55. {
  56. if (info->pos + len > info->offset + info->length)
  57. len = info->offset + info->length - info->pos;
  58. if (info->pos + len < info->offset) {
  59. info->pos += len;
  60. return;
  61. }
  62. if (info->pos < info->offset) {
  63. off_t partial;
  64. partial = info->offset - info->pos;
  65. data += partial;
  66. info->pos += partial;
  67. len  -= partial;
  68. }
  69. if (len > 0) {
  70. memcpy(info->buffer, data, len);
  71. info->pos += len;
  72. info->buffer += len;
  73. }
  74. }
  75. static int
  76. copy_info(struct info_str *info, char *fmt, ...)
  77. {
  78. va_list args;
  79. char buf[256];
  80. int len;
  81. va_start(args, fmt);
  82. len = vsprintf(buf, fmt, args);
  83. va_end(args);
  84. copy_mem_info(info, buf, len);
  85. return (len);
  86. }
  87. /*
  88.  * Table of syncrates that don't follow the "divisible by 4"
  89.  * rule. This table will be expanded in future SCSI specs.
  90.  */
  91. static struct {
  92. u_int period_factor;
  93. u_int period; /* in 10ths of ns */
  94. } scsi_syncrates[] = {
  95. { 0x09, 125 }, /* FAST-80 */
  96. { 0x0a, 250 }, /* FAST-40 40MHz */
  97. { 0x0b, 303 }, /* FAST-40 33MHz */
  98. { 0x0c, 500 } /* FAST-20 */
  99. };
  100.  
  101. /*
  102.  * Return the frequency in kHz corresponding to the given
  103.  * sync period factor.
  104.  */
  105. static u_int
  106. scsi_calc_syncsrate(u_int period_factor)
  107. {
  108. int i; 
  109. int num_syncrates;
  110.  
  111. num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
  112. /* See if the period is in the "exception" table */
  113. for (i = 0; i < num_syncrates; i++) {
  114. if (period_factor == scsi_syncrates[i].period_factor) {
  115.         /* Period in kHz */
  116. return (10000000 / scsi_syncrates[i].period);
  117. }
  118. }
  119. /*
  120.  * Wasn't in the table, so use the standard
  121.  * 4 times conversion.
  122.  */
  123. return (10000000 / (period_factor * 4 * 10));
  124. }
  125. void
  126. ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo)
  127. {
  128. u_int speed;
  129. u_int freq;
  130. u_int mb;
  131.         speed = 3300;
  132.         freq = 0;
  133. if (tinfo->offset != 0) {
  134. freq = scsi_calc_syncsrate(tinfo->period);
  135. speed = freq;
  136. }
  137. speed *= (0x01 << tinfo->width);
  138.         mb = speed / 1000;
  139.         if (mb > 0)
  140. copy_info(info, "%d.%03dMB/s transfers", mb, speed % 1000);
  141.         else
  142. copy_info(info, "%dKB/s transfers", speed);
  143. if (freq != 0) {
  144. copy_info(info, " (%d.%03dMHz%s, offset %d",
  145.  freq / 1000, freq % 1000,
  146.  (tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0
  147.  ? " DT" : "", tinfo->offset);
  148. }
  149. if (tinfo->width > 0) {
  150. if (freq != 0) {
  151. copy_info(info, ", ");
  152. } else {
  153. copy_info(info, " (");
  154. }
  155. copy_info(info, "%dbit)", 8 * (0x01 << tinfo->width));
  156. } else if (freq != 0) {
  157. copy_info(info, ")");
  158. }
  159. copy_info(info, "n");
  160. }
  161. static void
  162. ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
  163.       u_int our_id, char channel, u_int target_id,
  164.       u_int target_offset)
  165. {
  166. struct ahc_linux_target *targ;
  167. struct ahc_initiator_tinfo *tinfo;
  168. struct ahc_tmode_tstate *tstate;
  169. int lun;
  170. tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
  171.     target_id, &tstate);
  172. copy_info(info, "Channel %c Target %d Negotiation Settingsn",
  173.   channel, target_id);
  174. copy_info(info, "tUser: ");
  175. ahc_format_transinfo(info, &tinfo->user);
  176. targ = ahc->platform_data->targets[target_offset];
  177. if (targ == NULL)
  178. return;
  179. copy_info(info, "tGoal: ");
  180. ahc_format_transinfo(info, &tinfo->goal);
  181. copy_info(info, "tCurr: ");
  182. ahc_format_transinfo(info, &tinfo->curr);
  183. for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
  184. struct ahc_linux_device *dev;
  185. dev = targ->devices[lun];
  186. if (dev == NULL)
  187. continue;
  188. ahc_dump_device_state(info, dev);
  189. }
  190. }
  191. static void
  192. ahc_dump_device_state(struct info_str *info, struct ahc_linux_device *dev)
  193. {
  194. copy_info(info, "tChannel %c Target %d Lun %d Settingsn",
  195.   dev->target->channel + 'A', dev->target->target, dev->lun);
  196. copy_info(info, "ttCommands Queued %ldn", dev->commands_issued);
  197. copy_info(info, "ttCommands Active %dn", dev->active);
  198. copy_info(info, "ttCommand Openings %dn", dev->openings);
  199. copy_info(info, "ttMax Tagged Openings %dn", dev->maxtags);
  200. copy_info(info, "ttDevice Queue Frozen Count %dn", dev->qfrozen);
  201. }
  202. /*
  203.  * Return information to handle /proc support for the driver.
  204.  */
  205. int
  206. ahc_linux_proc_info(char *buffer, char **start, off_t offset,
  207.   int length, int hostno, int inout)
  208. {
  209. struct ahc_softc *ahc;
  210. struct info_str info;
  211. char ahc_info[256];
  212. u_int max_targ;
  213. u_int i;
  214. TAILQ_FOREACH(ahc, &ahc_tailq, links) {
  215. if (ahc->platform_data->host->host_no == hostno)
  216. break;
  217. }
  218. if (ahc == NULL)
  219. return (-EINVAL);
  220.  /* Has data been written to the file? */ 
  221. if (inout == TRUE)
  222. return (-ENOSYS);
  223. if (start)
  224. *start = buffer;
  225. info.buffer = buffer;
  226. info.length = length;
  227. info.offset = offset;
  228. info.pos = 0;
  229. copy_info(&info, "Adaptec AIC7xxx driver version: %sn",
  230.   AIC7XXX_DRIVER_VERSION);
  231. ahc_controller_info(ahc, ahc_info);
  232. copy_info(&info, "%sn", ahc_info);
  233. max_targ = 15;
  234. if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
  235. max_targ = 7;
  236. for (i = 0; i <= max_targ; i++) {
  237. u_int our_id;
  238. u_int target_id;
  239. char channel;
  240. channel = 'A';
  241. our_id = ahc->our_id;
  242. target_id = i;
  243. if (i > 7 && (ahc->features & AHC_TWIN) != 0) {
  244. channel = 'B';
  245. our_id = ahc->our_id_b;
  246. target_id = i % 8;
  247. }
  248. ahc_dump_target_state(ahc, &info, our_id,
  249.       channel, target_id, i);
  250. }
  251. return (info.pos > info.offset ? info.pos - info.offset : 0);
  252. }