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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * linux/drivers/scsi/scsi_proc.c
  3.  *
  4.  * The functions in this file provide an interface between
  5.  * the PROC file system and the SCSI device drivers
  6.  * It is mainly used for debugging, statistics and to pass 
  7.  * information directly to the lowlevel driver.
  8.  *
  9.  * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de 
  10.  * Version: 0.99.8   last change: 95/09/13
  11.  * 
  12.  * generic command parser provided by: 
  13.  * Andreas Heilwagen <crashcar@informatik.uni-koblenz.de>
  14.  *
  15.  * generic_proc_info() support of xxxx_info() by:
  16.  * Michael A. Griffith <grif@acm.org>
  17.  */
  18. #include <linux/config.h> /* for CONFIG_PROC_FS */
  19. #define __NO_VERSION__
  20. #include <linux/module.h>
  21. #include <linux/string.h>
  22. #include <linux/mm.h>
  23. #include <linux/slab.h>
  24. #include <linux/proc_fs.h>
  25. #include <linux/errno.h>
  26. #include <linux/stat.h>
  27. #include <linux/blk.h>
  28. #include <asm/uaccess.h>
  29. #include "scsi.h"
  30. #include "hosts.h"
  31. #ifndef TRUE
  32. #define TRUE  1
  33. #define FALSE 0
  34. #endif
  35. #ifdef CONFIG_PROC_FS
  36. /* generic_proc_info
  37.  * Used if the driver currently has no own support for /proc/scsi
  38.  */
  39. int generic_proc_info(char *buffer, char **start, off_t offset, int length, 
  40.       const char *(*info) (struct Scsi_Host *),
  41.       struct Scsi_Host *sh)
  42. {
  43. int len, pos, begin;
  44. begin = 0;
  45. if (info && sh) {
  46. pos = len = sprintf(buffer, "%sn", info(sh));
  47. } else {
  48. pos = len = sprintf(buffer,
  49. "The driver does not yet support the proc-fsn");
  50. }
  51. if (pos < offset) {
  52. len = 0;
  53. begin = pos;
  54. }
  55. *start = buffer + (offset - begin); /* Start of wanted data */
  56. len -= (offset - begin);
  57. if (len > length)
  58. len = length;
  59. return (len);
  60. }
  61. /* dispatch_scsi_info is the central dispatcher 
  62.  * It is the interface between the proc-fs and the SCSI subsystem code
  63.  */
  64. static int proc_scsi_read(char *buffer, char **start, off_t offset,
  65. int length, int *eof, void *data)
  66. {
  67. struct Scsi_Host *hpnt = data;
  68. int n;
  69. if (hpnt->hostt->proc_info == NULL)
  70. n = generic_proc_info(buffer, start, offset, length,
  71.       hpnt->hostt->info, hpnt);
  72. else
  73. n = (hpnt->hostt->proc_info(buffer, start, offset,
  74.    length, hpnt->host_no, 0));
  75. *eof = (n<length);
  76. return n;
  77. }
  78. #define PROC_BLOCK_SIZE (3*1024)     /* 4K page size, but our output routines 
  79.       * use some slack for overruns 
  80.       */
  81. static int proc_scsi_write(struct file * file, const char * buf,
  82.                            unsigned long count, void *data)
  83. {
  84. struct Scsi_Host *hpnt = data;
  85. ssize_t ret = 0;
  86. char * page;
  87. char *start;
  88.     
  89. if (hpnt->hostt->proc_info == NULL)
  90. ret = -ENOSYS;
  91. if (count > PROC_BLOCK_SIZE)
  92. return -EOVERFLOW;
  93. if (!(page = (char *) __get_free_page(GFP_KERNEL)))
  94. return -ENOMEM;
  95. if(copy_from_user(page, buf, count))
  96. {
  97. free_page((ulong) page);
  98. return -EFAULT;
  99. }
  100. ret = hpnt->hostt->proc_info(page, &start, 0, count,
  101.      hpnt->host_no, 1);
  102. free_page((ulong) page);
  103. return(ret);
  104. }
  105. void build_proc_dir_entries(Scsi_Host_Template * tpnt)
  106. {
  107. struct Scsi_Host *hpnt;
  108. char name[10]; /* see scsi_unregister_host() */
  109. tpnt->proc_dir = proc_mkdir(tpnt->proc_name, proc_scsi);
  110.         if (!tpnt->proc_dir) {
  111.                 printk(KERN_ERR "Unable to proc_mkdir in scsi.c/build_proc_dir_entries");
  112.                 return;
  113.         }
  114. tpnt->proc_dir->owner = tpnt->module;
  115. hpnt = scsi_hostlist;
  116. while (hpnt) {
  117. if (tpnt == hpnt->hostt) {
  118. struct proc_dir_entry *p;
  119. sprintf(name,"%d",hpnt->host_no);
  120. p = create_proc_read_entry(name,
  121. S_IFREG | S_IRUGO | S_IWUSR,
  122. tpnt->proc_dir,
  123. proc_scsi_read,
  124. (void *)hpnt);
  125. if (!p)
  126. panic("Not enough memory to register SCSI HBA in /proc/scsi !n");
  127. p->write_proc=proc_scsi_write;
  128. p->owner = tpnt->module;
  129. }
  130. hpnt = hpnt->next;
  131. }
  132. }
  133. /*
  134.  *  parseHandle *parseInit(char *buf, char *cmdList, int cmdNum); 
  135.  *              gets a pointer to a null terminated data buffer
  136.  *              and a list of commands with blanks as delimiter 
  137.  *      in between. 
  138.  *      The commands have to be alphanumerically sorted. 
  139.  *      cmdNum has to contain the number of commands.
  140.  *              On success, a pointer to a handle structure
  141.  *              is returned, NULL on failure
  142.  *
  143.  *      int parseOpt(parseHandle *handle, char **param);
  144.  *              processes the next parameter. On success, the
  145.  *              index of the appropriate command in the cmdList
  146.  *              is returned, starting with zero.
  147.  *              param points to the null terminated parameter string.
  148.  *              On failure, -1 is returned.
  149.  *
  150.  *      The databuffer buf may only contain pairs of commands
  151.  *          options, separated by blanks:
  152.  *              <Command> <Parameter> [<Command> <Parameter>]*
  153.  */
  154. typedef struct {
  155. char *buf, /* command buffer  */
  156. *cmdList, /* command list    */
  157. *bufPos, /* actual position */
  158. **cmdPos, /* cmdList index   */
  159.  cmdNum; /* cmd number      */
  160. } parseHandle;
  161. inline int parseFree(parseHandle * handle)
  162. { /* free memory     */
  163. kfree(handle->cmdPos);
  164. kfree(handle);
  165. return -1;
  166. }
  167. parseHandle *parseInit(char *buf, char *cmdList, int cmdNum)
  168. {
  169. char *ptr; /* temp pointer    */
  170. parseHandle *handle; /* new handle      */
  171. if (!buf || !cmdList) /* bad input ?     */
  172. return NULL;
  173. handle = (parseHandle *) kmalloc(sizeof(parseHandle), GFP_KERNEL);
  174. if (!handle)
  175. return NULL; /* out of memory   */
  176. handle->cmdPos = (char **) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL);
  177. if (!handle->cmdPos) {
  178. kfree(handle);
  179. return NULL; /* out of memory   */
  180. }
  181. handle->buf = handle->bufPos = buf; /* init handle     */
  182. handle->cmdList = cmdList;
  183. handle->cmdNum = cmdNum;
  184. handle->cmdPos[cmdNum = 0] = cmdList;
  185. for (ptr = cmdList; *ptr; ptr++) { /* scan command string */
  186. if (*ptr == ' ') { /* and insert zeroes   */
  187. *ptr++ = 0;
  188. handle->cmdPos[++cmdNum] = ptr++;
  189. }
  190. }
  191. return handle;
  192. }
  193. int parseOpt(parseHandle * handle, char **param)
  194. {
  195. int cmdIndex = 0, cmdLen = 0;
  196. char *startPos;
  197. if (!handle) /* invalid handle  */
  198. return (parseFree(handle));
  199. /* skip spaces     */
  200. for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
  201. if (!*(handle->bufPos))
  202. return (parseFree(handle)); /* end of data     */
  203. startPos = handle->bufPos; /* store cmd start */
  204. for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++) { /* no string end?  */
  205. for (;;) {
  206. if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen])
  207. break; /* char matches ?  */
  208. else if (memcmp(startPos, (char *) (handle->cmdPos[++cmdIndex]), cmdLen))
  209. return (parseFree(handle)); /* unknown command */
  210. if (cmdIndex >= handle->cmdNum)
  211. return (parseFree(handle)); /* unknown command */
  212. }
  213. cmdLen++; /* next char       */
  214. }
  215. /* Get param. First skip all blanks, then insert zero after param  */
  216. for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
  217. *param = handle->bufPos;
  218. for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++);
  219. *(handle->bufPos++) = 0;
  220. return (cmdIndex);
  221. }
  222. void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
  223. {
  224. int x, y = *size;
  225. extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
  226. y = sprintf(buffer + len,
  227.      "Host: scsi%d Channel: %02d Id: %02d Lun: %02dn  Vendor: ",
  228.     scd->host->host_no, scd->channel, scd->id, scd->lun);
  229. for (x = 0; x < 8; x++) {
  230. if (scd->vendor[x] >= 0x20)
  231. y += sprintf(buffer + len + y, "%c", scd->vendor[x]);
  232. else
  233. y += sprintf(buffer + len + y, " ");
  234. }
  235. y += sprintf(buffer + len + y, " Model: ");
  236. for (x = 0; x < 16; x++) {
  237. if (scd->model[x] >= 0x20)
  238. y += sprintf(buffer + len + y, "%c", scd->model[x]);
  239. else
  240. y += sprintf(buffer + len + y, " ");
  241. }
  242. y += sprintf(buffer + len + y, " Rev: ");
  243. for (x = 0; x < 4; x++) {
  244. if (scd->rev[x] >= 0x20)
  245. y += sprintf(buffer + len + y, "%c", scd->rev[x]);
  246. else
  247. y += sprintf(buffer + len + y, " ");
  248. }
  249. y += sprintf(buffer + len + y, "n");
  250. y += sprintf(buffer + len + y, "  Type:   %s ",
  251.      scd->type < MAX_SCSI_DEVICE_CODE ?
  252.        scsi_device_types[(int) scd->type] : "Unknown          ");
  253. y += sprintf(buffer + len + y, "               ANSI"
  254.      " SCSI revision: %02x", (scd->scsi_level - 1) ? scd->scsi_level - 1 : 1);
  255. if (scd->scsi_level == 2)
  256. y += sprintf(buffer + len + y, " CCSn");
  257. else
  258. y += sprintf(buffer + len + y, "n");
  259. *size = y;
  260. return;
  261. }
  262. #else /* if !CONFIG_PROC_FS */
  263. void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
  264. {
  265. }
  266. #endif /* CONFIG_PROC_FS */
  267. /*
  268.  * Overrides for Emacs so that we get a uniform tabbing style.
  269.  * Emacs will notice this stuff at the end of the file and automatically
  270.  * adjust the settings for this buffer only.  This must remain at the end
  271.  * of the file.
  272.  * ---------------------------------------------------------------------------
  273.  * Local variables:
  274.  * c-indent-level: 4
  275.  * c-brace-imaginary-offset: 0
  276.  * c-brace-offset: -4
  277.  * c-argdecl-indent: 4
  278.  * c-label-offset: -4
  279.  * c-continued-statement-offset: 4
  280.  * c-continued-brace-offset: 0
  281.  * indent-tabs-mode: nil
  282.  * tab-width: 8
  283.  * End:
  284.  */