"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "mapscsi-0.0.11/scsi_api.c" of archive mapscsi-0.0.11.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <fcntl.h>
8 #include <errno.h>
9 #include <limits.h>
10 #include <libgen.h>
11 #include <signal.h>
12 #include <syslog.h>
13
14 #include "scsi_api.h"
15
16
17 /* global linked list of scsi devices */
18 scsi_device_t *scsidev_head = NULL;
19
20
21 static int decode_int(void *dest, const char *str, size_t size)
22 {
23 return sscanf(str, "%d", (int*)dest);
24 }
25
26
27 static int encode_int(char *str, void *src, size_t size)
28 {
29 return snprintf(str, size, "%d", *(int*)src);
30 }
31
32
33 static int decode_str(void *dest, const char *str, size_t size)
34 {
35 int l = strlen(strncpy((char*)dest, str, size));
36 return (l == size) ? -1 : l;
37 }
38
39
40 static int encode_str(char *str, void *src, size_t size)
41 {
42 int l = strlen(strncpy(str, (char*)src, size));
43 return (l == size) ? -1 : l;
44 }
45
46
47 static int encode_strp(char *str, void *src, size_t size)
48 {
49 if(*((char**)src)) {
50 int l = strlen(strncpy(str, *((char**)src), size));
51 return (l == size) ? -1 : l;
52 } else {
53 str[0] = '\0';
54 return 0;
55 }
56 }
57
58
59 static int decode_strp(void *dest, const char *str, size_t size)
60 {
61 int l = strlen(*((char**)dest) = strdup(str));
62 return (l == size) ? -1 : l;
63 }
64
65
66 static int decode_type(void *dest, const char *str, size_t size)
67 {
68 if(strcmp(str, "disk") == 0) {
69 *(int*)dest = TYPE_DISK;
70 return 1;
71 } else if(strcmp(str, "processor") == 0) {
72 *(int*)dest = TYPE_PROCESSOR;
73 return 1;
74 } else if(strcmp(str, "cdrom") == 0) {
75 *(int*)dest = TYPE_ROM;
76 return 1;
77 } else if(strcmp(str, "worm") == 0) {
78 *(int*)dest = TYPE_WORM;
79 return 1;
80 } else if(strcmp(str, "tape") == 0) {
81 *(int*)dest = TYPE_TAPE;
82 return 1;
83 } else if(strcmp(str, "mod") == 0) {
84 *(int*)dest = TYPE_MOD;
85 return 1;
86 } else if(strcmp(str, "scanner") == 0) {
87 *(int*)dest = TYPE_SCANNER;
88 return 1;
89 }
90 return 0;
91 }
92
93
94 static int encode_type(char *str, void *src, size_t size)
95 {
96 switch(*(int*)src) {
97 case TYPE_DISK:
98 return snprintf(str, size, "%s", "disk");
99 break;
100 case TYPE_PROCESSOR:
101 return snprintf(str, size, "%s", "processor");
102 break;
103 case TYPE_ROM:
104 return snprintf(str, size, "%s", "cdrom");
105 break;
106 case TYPE_WORM:
107 return snprintf(str, size, "%s", "worm");
108 break;
109 case TYPE_TAPE:
110 return snprintf(str, size, "%s", "tape");
111 break;
112 case TYPE_MOD:
113 return snprintf(str, size, "%s", "mod");
114 break;
115 case TYPE_SCANNER:
116 return snprintf(str, size, "%s", "scanner");
117 break;
118 default:
119 return snprintf(str, size, "%s", "other");
120 }
121 }
122
123
124 scsi_device_param_t params[] = {
125 { 'h', "host", "Host / adapter no", &encode_int, &decode_int,
126 offsetof(scsi_device_t, host), 0 },
127 { 'c', "channel", "Channel no", &encode_int, &decode_int,
128 offsetof(scsi_device_t, channel), 0 },
129 { 't', "id", "Target / scsi id", &encode_int, &decode_int,
130 offsetof(scsi_device_t, id), 0 },
131 { 'l', "lun", "Lun", &encode_int, &decode_int,
132 offsetof(scsi_device_t, lun), 0 },
133 { 'p', "part", "Partition number", &encode_int, &decode_int,
134 offsetof(scsi_device_t, part), 0 },
135 { 'w', "fcwwnn", "FC World Wide Node Name", &encode_str, &decode_str,
136 offsetof(scsi_device_t, wwnn), msizeof(scsi_device_t, wwnn) },
137 { 'W', "fcwwpn", "FC World Wide Port Name", &encode_str, &decode_str,
138 offsetof(scsi_device_t, wwpn), msizeof(scsi_device_t, wwpn) },
139 { 'I', "fcdid", "FC Port ID", &encode_str, &decode_str,
140 offsetof(scsi_device_t, portid), msizeof(scsi_device_t, portid) },
141 { 'L', "fclid", "FC Loop ID", &encode_int, &decode_int,
142 offsetof(scsi_device_t, loopid), 0 },
143 { 'B', "pci", "PCI bus:dev.func", &encode_str, &decode_str,
144 offsetof(scsi_device_t, pciinfo), msizeof(scsi_device_t, pciinfo) },
145 { 'H', "hostname", "HBA Driver name", &encode_str, &decode_str,
146 offsetof(scsi_device_t, hostname), msizeof(scsi_device_t, hostname) },
147 { 'V', "vendor", "Vendor Inquiry info", &encode_str, &decode_str,
148 offsetof(scsi_device_t, vendor), msizeof(scsi_device_t, vendor) },
149 { 'P', "product", "Product Inquiry info", &encode_str, &decode_str,
150 offsetof(scsi_device_t, product), msizeof(scsi_device_t, product) },
151 { 'R', "revision", "Revision Inquiry info", &encode_str, &decode_str,
152 offsetof(scsi_device_t, revision), msizeof(scsi_device_t, revision) },
153 { 'S', "serial", "Serial number Inquiry info", &encode_str, &decode_str,
154 offsetof(scsi_device_t, serial), msizeof(scsi_device_t, serial) },
155 { 'D', "prefix", "Device prefix (sd, scd)", &encode_str, &decode_str,
156 offsetof(scsi_device_t, prefix), msizeof(scsi_device_t, prefix) },
157 { 'T', "type", "Device type (disk, cdrom)", &encode_type, &decode_type,
158 offsetof(scsi_device_t, type), 0 },
159 { 'g', "device", "Generic device (/dev/sg0)", &encode_strp, &decode_strp,
160 offsetof(scsi_device_t, device), msizeof(scsi_device_t, device) },
161 { 'd', "sg_device", "Device (/dev/sda)", &encode_strp, &decode_strp,
162 offsetof(scsi_device_t, sg_device), msizeof(scsi_device_t, sg_device) },
163 { '\0', "", "", NULL, NULL, 0, 0 }
164 };
165
166
167 /* process a complete SCSI cmd. Use the generic SCSI interface. */
168 int handle_scsi_cmd(int fd,
169 unsigned cmd_len, /* command length */
170 unsigned in_size, /* input data size */
171 unsigned char *i_buff, /* input buffer */
172 unsigned out_size, /* output data size */
173 unsigned char *o_buff /* output buffer */)
174 {
175 int status = 0;
176 struct sg_header *sg_hd;
177
178 /* safety checks */
179 if (!cmd_len) return -1; /* need a cmd_len != 0 */
180 if (!i_buff) return -1; /* need an input buffer != NULL */
181 if (SCSI_OFF + cmd_len + in_size > 4096) return -1;
182 if (SCSI_OFF + out_size > 4096) return -1;
183
184 if (!o_buff) out_size = 0; /* no output buffer, no output size */
185
186 /* generic SCSI device header construction */
187 sg_hd = (struct sg_header *) i_buff;
188 sg_hd->reply_len = SCSI_OFF + out_size;
189 sg_hd->twelve_byte = cmd_len == 12;
190 sg_hd->result = 0;
191
192 /* send command */
193 status = write( fd, i_buff, SCSI_OFF + cmd_len + in_size );
194 if ( status < 0 || status != SCSI_OFF + cmd_len + in_size ||
195 sg_hd->result ) {
196 /* some error happened */
197 fprintf( stderr, "write(generic) result = 0x%x cmd = 0x%x\n",
198 sg_hd->result, i_buff[SCSI_OFF] );
199 perror("");
200 return status;
201 }
202
203 if (!o_buff) o_buff = i_buff; /* buffer pointer check */
204
205 /* retrieve result */
206 status = read( fd, o_buff, SCSI_OFF + out_size);
207 if ( status < 0 || status != SCSI_OFF + out_size || sg_hd->result ) {
208 /* some error happened */
209 fprintf( stderr, "read(generic) status = 0x%x, result = 0x%x, "
210 "cmd = 0x%x\n",
211 status, sg_hd->result, o_buff[SCSI_OFF] );
212 fprintf( stderr, "read(generic) sense "
213 "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
214 sg_hd->sense_buffer[0], sg_hd->sense_buffer[1],
215 sg_hd->sense_buffer[2], sg_hd->sense_buffer[3],
216 sg_hd->sense_buffer[4], sg_hd->sense_buffer[5],
217 sg_hd->sense_buffer[6], sg_hd->sense_buffer[7],
218 sg_hd->sense_buffer[8], sg_hd->sense_buffer[9],
219 sg_hd->sense_buffer[10], sg_hd->sense_buffer[11],
220 sg_hd->sense_buffer[12], sg_hd->sense_buffer[13],
221 sg_hd->sense_buffer[14], sg_hd->sense_buffer[15]);
222 if (status < 0)
223 perror("");
224 }
225 /* Look if we got what we expected to get */
226 if (status == SCSI_OFF + out_size) status = 0; /* got them all */
227
228 return status; /* 0 means no error */
229 }
230
231
232 /* request vendor brand and model - use evpd=0, op=0 */
233 /* request serial number - use evpd=1, op=0x80 */
234 unsigned char *scsi_inquiry (int fd, int evpd, int pg)
235 {
236 static unsigned char cmd[SCSI_OFF + 18]; /* SCSI command buffer */
237 static unsigned char scsi_inquiry_buffer[SCSI_OFF + INQUIRY_REPLY_LEN];
238 unsigned char cmdblk [ INQUIRY_CMDLEN ] =
239 { INQUIRY_CMD, /* command */
240 evpd, /* lun/reserved */
241 pg, /* page code */
242 0, /* reserved */
243 INQUIRY_REPLY_LEN, /* allocation length */
244 0 };/* reserved/flag/link */
245
246 memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) );
247
248 if (handle_scsi_cmd(fd, sizeof(cmdblk), 0, cmd,
249 sizeof(scsi_inquiry_buffer) - SCSI_OFF,
250 scsi_inquiry_buffer)) {
251 fprintf( stderr, "Inquiry failed\n" );
252 exit(2);
253 }
254 return (scsi_inquiry_buffer + SCSI_OFF);
255 }
256
257
258 static void str_trim(char *p)
259 {
260 char *t = p + strlen(p) - 1;
261 while(t >= p) {
262 if(*t == 0x20) *t-- = '\0';
263 else break;
264 }
265 }
266
267
268 static void str_path(char *p)
269 {
270 char *t, *r, *w = p;
271
272 t = r = strdup(p);
273 while(*r) {
274 if(*r != ' ') *w++ = *r++;
275 else r++;
276 }
277 *w = '\0';
278 free(t);
279 while(*p) {
280 if(!isalnum(*p) && *p != '/') *p = '-';
281 p++;
282 }
283 }
284
285
286 int get_scsi_dev_info(int fd, scsi_device_t *scsidev)
287 {
288 unsigned char *buf;
289 Sg_scsi_id scsi_id;
290 char hostname[HOSTNAME_LEN+1];
291 int l;
292
293 /* Get host no, channel and scsi id */
294 if(ioctl(fd, SG_GET_SCSI_ID, &scsi_id) < 0) {
295 perror("ioctl");
296 exit(1);
297 }
298
299 scsidev->host = scsi_id.host_no;
300 scsidev->channel = scsi_id.channel;
301 scsidev->id = scsi_id.scsi_id;
302 scsidev->lun = scsi_id.lun;
303
304 /* Get scsi inquiry info */
305 buf = scsi_inquiry(fd, 0, 0);
306
307 scsidev->active = 1;
308
309 scsidev->type = *(buf+INQUIRY_PERIPHERAL_OFFSET);
310
311 memcpy(scsidev->vendor,
312 buf + INQUIRY_VENDOR_OFFSET, INQUIRY_VENDOR_LENGTH);
313 scsidev->vendor[INQUIRY_VENDOR_LENGTH] = '\0';
314 str_trim(scsidev->vendor);
315
316 memcpy(scsidev->revision,
317 buf + INQUIRY_REVISION_OFFSET, INQUIRY_REVISION_LENGTH);
318 scsidev->revision[INQUIRY_REVISION_LENGTH] = '\0';
319 str_trim(scsidev->revision);
320
321 memcpy(scsidev->product,
322 buf + INQUIRY_PRODUCT_OFFSET, INQUIRY_PRODUCT_LENGTH);
323 scsidev->product[INQUIRY_PRODUCT_LENGTH] = '\0';
324 str_trim(scsidev->product);
325
326 memcpy(scsidev->safteid, buf + INQUIRY_SAFTEID_OFFSET, INQUIRY_SAFTEID_LENGTH);
327 scsidev->safteid[INQUIRY_SAFTEID_LENGTH] = '\0';
328
329 scsidev->channelid = *(buf+INQUIRY_CHANNELID_OFFSET);
330
331 /* Get serial number */
332 buf = scsi_inquiry(fd, 1, 0x80);
333 l = buf[3];
334 memcpy(scsidev->serial, buf + 4, l);
335 scsidev->serial[l] = '\0';
336 str_trim(scsidev->serial);
337
338 /* Get the hostname */
339 *(int*)hostname = HOSTNAME_LEN;
340 if(ioctl (fd, SCSI_IOCTL_PROBE_HOST, hostname) >= 0) {
341 strncpy(scsidev->hostname, hostname, HOSTNAME_LEN);
342 str_trim(scsidev->hostname);
343 }
344
345 /* Get the PCI bus:dev.fn */
346 if(ioctl(fd, SCSI_IOCTL_GET_PCI, scsidev->pciinfo) < 0) {
347 /* we ignore the error, either ioctl is not supported
348 or the scsi device is not PCI (ide-scsi) */
349 }
350
351 /* Get the WWN to scsi id map from Qlogic cards */
352 if(strncmp(scsidev->hostname, "QLogic QLA2", 11) == 0)
353 qlogic_probe(fd);
354
355 return 0;
356 }
357
358
359 void make_dev_name(char * fname, const char * leadin, int k,
360 int do_numeric)
361 {
362 char buff[64];
363 int big,little;
364
365 if(leadin[0] == '/') strcpy(fname, leadin);
366 else sprintf(fname, "/dev/%s", leadin);
367 if (do_numeric) {
368 sprintf(buff, "%d", k);
369 strcat(fname, buff);
370 }
371 else {
372 if (k < 26) {
373 buff[0] = 'a' + (char)k;
374 buff[1] = '\0';
375 strcat(fname, buff);
376 }
377 else if (k <= 255) {
378 /* assumes sequence goes x,y,z,aa,ab,ac etc */
379 big = k/26;
380 little = k - (26 * big);
381 big = big - 1;
382
383 buff[0] = 'a' + (char)big;
384 buff[1] = 'a' + (char)little;
385 buff[2] = '\0';
386 strcat(fname, buff);
387 }
388 else
389 strcat(fname, "xxxx");
390 }
391 }
392
393
394 scsi_device_t* find_dev_by_loc(int host, int channel, int id, int lun)
395 {
396 scsi_device_t *scsidev = scsidev_head;
397
398 while(scsidev->next) {
399 if (host == scsidev->host && channel == scsidev->channel &&
400 id == scsidev->id && lun == scsidev->lun) return scsidev;
401 scsidev = scsidev->next;
402 }
403 return NULL;
404 }
405
406
407 scsi_device_t* find_dev_by_name(const char* device)
408 {
409 scsi_device_t *scsidev = scsidev_head;
410 char device_temp[PATH_MAX+1];
411
412
413 if(device[0] == '/') strcpy(device_temp, device);
414 else sprintf(device_temp, "/dev/%s", device);
415
416 while(scsidev->next) {
417 if (scsidev->device && strcmp(device_temp, scsidev->device) == 0)
418 return scsidev;
419 scsidev = scsidev->next;
420 }
421 return NULL;
422 }
423
424
425 void map_sg_devices(int type, const char* prefix, int numeric)
426 {
427 scsi_device_t *scsidev = NULL;
428 int fd, k, res, num_errors = 0;
429 int host, channel, id, lun;
430 scsi_idlun_t idlun;
431 char device[PATH_MAX+1];
432
433 /* find sd? devices that map to sg? devices */
434 for (k = 0, res = 0; num_errors < MAX_ERRORS; k++) {
435
436 make_dev_name(device, prefix, k, numeric);
437
438 fd = open(device, O_RDONLY | O_NONBLOCK);
439 if (fd < 0) {
440 if (EBUSY == errno) {
441 printf("Device %s is busy\n", device);
442 ++num_errors;
443 continue;
444 }
445 else if ((ENODEV == errno) || (ENOENT == errno) ||
446 (ENXIO == errno)) {
447 ++num_errors;
448 continue;
449 }
450 else {
451 perror("open");
452 ++num_errors;
453 continue;
454 }
455 }
456
457 res = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
458 if (res < 0) {
459 perror("ioctl");
460 ++num_errors;
461 continue;
462 }
463 res = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &host);
464 if (res < 0) {
465 perror("ioctl");
466 ++num_errors;
467 continue;
468 }
469
470 id = idlun.dev_id & 0xff;
471 lun = (idlun.dev_id >> 8) & 0xff;
472 channel = (idlun.dev_id >> 16) & 0xff;
473
474 scsidev = find_dev_by_loc(host, channel, id, lun);
475 if (scsidev && scsidev->type == type) {
476 scsidev->device = strdup(device);
477 strncpy(scsidev->prefix, prefix, PREFIX_LEN);
478 /* printf("%s - %d %d %d %d maps to %s\n",
479 device, host, channel, id, lun, scsidev->sg_device); */
480 } else {
481 /* printf("can't find sd device for %s", scsidev->sg_device); */
482 }
483
484 close(fd);
485
486 }
487 }
488
489
490 int scan_scsi_devices(int sg_numeric)
491 {
492 char tmp[PATH_MAX];
493 scsi_device_t *scsidev = scsidev_head;
494 int fd, ind, k, last_sg_ind, num_errors = 0;
495
496 for (k = 0; (k < MAX_SCSI_DEVS) && (num_errors < MAX_ERRORS); k++) {
497
498 make_dev_name(tmp, "/dev/sg", k, sg_numeric);
499 scsidev->sg_device = strdup(tmp);
500
501 fd = open(scsidev->sg_device, O_RDWR);
502
503 if (fd < 0) {
504 if (EBUSY == errno) {
505 scsidev->active = -2;
506 continue;
507 } else if ((ENODEV == errno) ||
508 (ENOENT == errno) || (ENXIO == errno)) {
509 ++num_errors;
510 scsidev->active = -1;
511 continue;
512 } else {
513 scsidev->active = 0;
514 ++num_errors;
515 continue;
516 }
517 }
518
519 get_scsi_dev_info(fd, scsidev);
520 #if DEBUG
521 print_scsi_dev_info(scsidev);
522 #endif
523 close(fd);
524 scsidev->next = calloc(1, sizeof(scsi_device_t));
525 scsidev = scsidev->next;
526 }
527
528 return 0;
529 }
530
531
532 void print_scsi_dev_info(scsi_device_t *scsidev)
533 {
534 char scsiinfo[1024] = "";
535 char tmpbuf[128] = "";
536 char* scsicodes = "ThctlVPRSBdg";
537 char* fccodes = "wWIL";
538 char *code;
539 int l;
540
541 code = scsicodes;
542 while(*code) {
543 scsi_device_param_t *param = params;
544 while(param->substchar) {
545 if(param->substchar == *code) break;
546 param++;
547 }
548 if(param->enc) {
549 if(param->enc(tmpbuf, ((void*)scsidev)+param->offset, 128) > 0) {
550 if(scsiinfo[0]) strncat(scsiinfo, " ", 1024-strlen(scsiinfo));
551 strncat(scsiinfo, param->name, 1024-strlen(scsiinfo));
552 strncat(scsiinfo, "=", 1024-strlen(scsiinfo));
553 if(param->enc != encode_int)
554 strncat(scsiinfo, "\"", 1024-strlen(scsiinfo));
555 strncat(scsiinfo, tmpbuf, 1024-strlen(scsiinfo));
556 if(param->enc != encode_int)
557 strncat(scsiinfo, "\"", 1024-strlen(scsiinfo));
558 }
559 }
560 code++;
561 }
562 if(!scsidev->isfc) goto notfc;
563 code = fccodes;
564 while(*code) {
565 scsi_device_param_t *param = params;
566 while(param->substchar) {
567 if(param->substchar == *code) break;
568 param++;
569 }
570 if(param->enc) {
571 if(param->enc(tmpbuf, ((void*)scsidev)+param->offset, 128) > 0) {
572 strncat(scsiinfo, " ", 1024-strlen(scsiinfo));
573 strncat(scsiinfo, param->name, 1024-strlen(scsiinfo));
574 strncat(scsiinfo, "=", 1024-strlen(scsiinfo));
575 if(param->enc != encode_int)
576 strncat(scsiinfo, "\"", 1024-strlen(scsiinfo));
577 strncat(scsiinfo, tmpbuf, 1024-strlen(scsiinfo));
578 if(param->enc != encode_int)
579 strncat(scsiinfo, "\"", 1024-strlen(scsiinfo));
580 }
581 }
582 code++;
583 }
584
585 notfc:
586 printf("%s\n", scsiinfo);
587 }
588
589
590 int free_scsidev(scsi_device_t *scsidev)
591 {
592 scsi_device_t *c_scsidev = scsidev;
593
594 while(c_scsidev->next) {
595 scsi_device_t *t = c_scsidev;
596 c_scsidev = c_scsidev->next;
597 if(t->device) free(t->device);
598 if(t->sg_device) free(t->sg_device);
599 free(t);
600 }
601 return 0;
602 }
603
604