|
|
1.1 ! root 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 [email protected] ! 10: * Version: 0.99.8 last change: 95/09/13 ! 11: * ! 12: * generic command parser provided by: ! 13: * Andreas Heilwagen <[email protected]> ! 14: */ ! 15: ! 16: /* ! 17: * Don't import our own symbols, as this would severely mess up our ! 18: * symbol tables. ! 19: */ ! 20: #define _SCSI_SYMS_VER_ ! 21: #define __NO_VERSION__ ! 22: #include <linux/module.h> ! 23: ! 24: #include <linux/string.h> ! 25: #include <linux/mm.h> ! 26: #include <linux/malloc.h> ! 27: #include <linux/proc_fs.h> ! 28: #include <linux/errno.h> ! 29: #include <linux/stat.h> ! 30: #include <linux/blk.h> ! 31: #include "scsi.h" ! 32: #include "hosts.h" ! 33: ! 34: #ifndef TRUE ! 35: #define TRUE 1 ! 36: #define FALSE 0 ! 37: #endif ! 38: ! 39: extern int scsi_proc_info(char *, char **, off_t, int, int, int); ! 40: ! 41: struct scsi_dir { ! 42: struct proc_dir_entry entry; ! 43: char name[4]; ! 44: }; ! 45: ! 46: ! 47: /* generic_proc_info ! 48: * Used if the driver currently has no own support for /proc/scsi ! 49: */ ! 50: int generic_proc_info(char *buffer, char **start, off_t offset, ! 51: int length, int inode, int inout) ! 52: { ! 53: int len, pos, begin; ! 54: ! 55: if(inout == TRUE) ! 56: return(-ENOSYS); /* This is a no-op */ ! 57: ! 58: begin = 0; ! 59: pos = len = sprintf(buffer, ! 60: "The driver does not yet support the proc-fs\n"); ! 61: if(pos < offset) { ! 62: len = 0; ! 63: begin = pos; ! 64: } ! 65: ! 66: *start = buffer + (offset - begin); /* Start of wanted data */ ! 67: len -= (offset - begin); ! 68: if(len > length) ! 69: len = length; ! 70: ! 71: return(len); ! 72: } ! 73: ! 74: /* dispatch_scsi_info is the central dispatcher ! 75: * It is the interface between the proc-fs and the SCSI subsystem code ! 76: */ ! 77: extern int dispatch_scsi_info(int ino, char *buffer, char **start, ! 78: off_t offset, int length, int func) ! 79: { ! 80: struct Scsi_Host *hpnt = scsi_hostlist; ! 81: ! 82: if(ino == PROC_SCSI_SCSI) { ! 83: /* ! 84: * This is for the scsi core, rather than any specific ! 85: * lowlevel driver. ! 86: */ ! 87: return(scsi_proc_info(buffer, start, offset, length, 0, func)); ! 88: } ! 89: ! 90: while(hpnt) { ! 91: if (ino == (hpnt->host_no + PROC_SCSI_FILE)) { ! 92: if(hpnt->hostt->proc_info == NULL) ! 93: return generic_proc_info(buffer, start, offset, length, ! 94: hpnt->host_no, func); ! 95: else ! 96: return(hpnt->hostt->proc_info(buffer, start, offset, ! 97: length, hpnt->host_no, func)); ! 98: } ! 99: hpnt = hpnt->next; ! 100: } ! 101: return(-EBADF); ! 102: } ! 103: ! 104: void build_proc_dir_entries(Scsi_Host_Template *tpnt) ! 105: { ! 106: struct Scsi_Host *hpnt; ! 107: ! 108: struct scsi_dir *scsi_hba_dir; ! 109: ! 110: proc_scsi_register(0, tpnt->proc_dir); ! 111: ! 112: hpnt = scsi_hostlist; ! 113: while (hpnt) { ! 114: if (tpnt == hpnt->hostt) { ! 115: scsi_hba_dir = scsi_init_malloc(sizeof(struct scsi_dir), GFP_KERNEL); ! 116: if(scsi_hba_dir == NULL) ! 117: panic("Not enough memory to register SCSI HBA in /proc/scsi !\n"); ! 118: memset(scsi_hba_dir, 0, sizeof(struct scsi_dir)); ! 119: scsi_hba_dir->entry.low_ino = PROC_SCSI_FILE + hpnt->host_no; ! 120: scsi_hba_dir->entry.namelen = sprintf(scsi_hba_dir->name,"%d", ! 121: hpnt->host_no); ! 122: scsi_hba_dir->entry.name = scsi_hba_dir->name; ! 123: scsi_hba_dir->entry.mode = S_IFREG | S_IRUGO | S_IWUSR; ! 124: proc_scsi_register(tpnt->proc_dir, &scsi_hba_dir->entry); ! 125: } ! 126: hpnt = hpnt->next; ! 127: } ! 128: } ! 129: ! 130: /* ! 131: * parseHandle *parseInit(char *buf, char *cmdList, int cmdNum); ! 132: * gets a pointer to a null terminated data buffer ! 133: * and a list of commands with blanks as delimiter ! 134: * in between. ! 135: * The commands have to be alphanumerically sorted. ! 136: * cmdNum has to contain the number of commands. ! 137: * On success, a pointer to a handle structure ! 138: * is returned, NULL on failure ! 139: * ! 140: * int parseOpt(parseHandle *handle, char **param); ! 141: * processes the next parameter. On success, the ! 142: * index of the appropriate command in the cmdList ! 143: * is returned, starting with zero. ! 144: * param points to the null terminated parameter string. ! 145: * On failure, -1 is returned. ! 146: * ! 147: * The databuffer buf may only contain pairs of commands ! 148: * options, separated by blanks: ! 149: * <Command> <Parameter> [<Command> <Parameter>]* ! 150: */ ! 151: ! 152: typedef struct ! 153: { ! 154: char *buf, /* command buffer */ ! 155: *cmdList, /* command list */ ! 156: *bufPos, /* actual position */ ! 157: **cmdPos, /* cmdList index */ ! 158: cmdNum; /* cmd number */ ! 159: } parseHandle; ! 160: ! 161: ! 162: inline int parseFree (parseHandle *handle) /* free memory */ ! 163: { ! 164: kfree (handle->cmdPos); ! 165: kfree (handle); ! 166: ! 167: return(-1); ! 168: } ! 169: ! 170: ! 171: parseHandle *parseInit(char *buf, char *cmdList, int cmdNum) ! 172: { ! 173: char *ptr; /* temp pointer */ ! 174: parseHandle *handle; /* new handle */ ! 175: ! 176: if (!buf || !cmdList) /* bad input ? */ ! 177: return(NULL); ! 178: if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), GFP_KERNEL)) == 0) ! 179: return(NULL); /* out of memory */ ! 180: if ((handle->cmdPos = (char**) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL)) == 0) { ! 181: kfree(handle); ! 182: return(NULL); /* out of memory */ ! 183: } ! 184: ! 185: handle->buf = handle->bufPos = buf; /* init handle */ ! 186: handle->cmdList = cmdList; ! 187: handle->cmdNum = cmdNum; ! 188: ! 189: handle->cmdPos[cmdNum = 0] = cmdList; ! 190: for (ptr = cmdList; *ptr; ptr++) { /* scan command string */ ! 191: if(*ptr == ' ') { /* and insert zeroes */ ! 192: *ptr++ = 0; ! 193: handle->cmdPos[++cmdNum] = ptr++; ! 194: } ! 195: } ! 196: return(handle); ! 197: } ! 198: ! 199: ! 200: int parseOpt(parseHandle *handle, char **param) ! 201: { ! 202: int cmdIndex = 0, ! 203: cmdLen = 0; ! 204: char *startPos; ! 205: ! 206: if (!handle) /* invalid handle */ ! 207: return(parseFree(handle)); ! 208: /* skip spaces */ ! 209: for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++); ! 210: if (!*(handle->bufPos)) ! 211: return(parseFree(handle)); /* end of data */ ! 212: ! 213: startPos = handle->bufPos; /* store cmd start */ ! 214: for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++) ! 215: { /* no string end? */ ! 216: for (;;) ! 217: { ! 218: if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen]) ! 219: break; /* char matches ? */ ! 220: else ! 221: if (memcmp(startPos, (char*)(handle->cmdPos[++cmdIndex]), cmdLen)) ! 222: return(parseFree(handle)); /* unknown command */ ! 223: ! 224: if (cmdIndex >= handle->cmdNum) ! 225: return(parseFree(handle)); /* unknown command */ ! 226: } ! 227: ! 228: cmdLen++; /* next char */ ! 229: } ! 230: ! 231: /* Get param. First skip all blanks, then insert zero after param */ ! 232: ! 233: for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++); ! 234: *param = handle->bufPos; ! 235: ! 236: for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++); ! 237: *(handle->bufPos++) = 0; ! 238: ! 239: return(cmdIndex); ! 240: } ! 241: ! 242: void proc_print_scsidevice(Scsi_Device *scd, char *buffer, int *size, int len) ! 243: { ! 244: int x, y = *size; ! 245: ! 246: y = sprintf(buffer + len, ! 247: "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ", ! 248: scd->host->host_no, scd->channel, scd->id, scd->lun); ! 249: for (x = 0; x < 8; x++) { ! 250: if (scd->vendor[x] >= 0x20) ! 251: y += sprintf(buffer + len + y, "%c", scd->vendor[x]); ! 252: else ! 253: y += sprintf(buffer + len + y," "); ! 254: } ! 255: y += sprintf(buffer + len + y, " Model: "); ! 256: for (x = 0; x < 16; x++) { ! 257: if (scd->model[x] >= 0x20) ! 258: y += sprintf(buffer + len + y, "%c", scd->model[x]); ! 259: else ! 260: y += sprintf(buffer + len + y, " "); ! 261: } ! 262: y += sprintf(buffer + len + y, " Rev: "); ! 263: for (x = 0; x < 4; x++) { ! 264: if (scd->rev[x] >= 0x20) ! 265: y += sprintf(buffer + len + y, "%c", scd->rev[x]); ! 266: else ! 267: y += sprintf(buffer + len + y, " "); ! 268: } ! 269: y += sprintf(buffer + len + y, "\n"); ! 270: ! 271: y += sprintf(buffer + len + y, " Type: %s ", ! 272: scd->type < MAX_SCSI_DEVICE_CODE ? ! 273: scsi_device_types[(int)scd->type] : "Unknown " ); ! 274: y += sprintf(buffer + len + y, " ANSI" ! 275: " SCSI revision: %02x", (scd->scsi_level < 3)?1:2); ! 276: if (scd->scsi_level == 2) ! 277: y += sprintf(buffer + len + y, " CCS\n"); ! 278: else ! 279: y += sprintf(buffer + len + y, "\n"); ! 280: ! 281: *size = y; ! 282: return; ! 283: } ! 284: ! 285: /* ! 286: * Overrides for Emacs so that we get a uniform tabbing style. ! 287: * Emacs will notice this stuff at the end of the file and automatically ! 288: * adjust the settings for this buffer only. This must remain at the end ! 289: * of the file. ! 290: * --------------------------------------------------------------------------- ! 291: * Local variables: ! 292: * c-indent-level: 4 ! 293: * c-brace-imaginary-offset: 0 ! 294: * c-brace-offset: -4 ! 295: * c-argdecl-indent: 4 ! 296: * c-label-offset: -4 ! 297: * c-continued-statement-offset: 4 ! 298: * c-continued-brace-offset: 0 ! 299: * indent-tabs-mode: nil ! 300: * tab-width: 8 ! 301: * End: ! 302: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.