Imported Upstream version 0.8.9
[platform/upstream/multipath-tools.git] / mpathpersist / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/types.h>
5 #include <fcntl.h>
6 #include "checkers.h"
7 #include "vector.h"
8 #include "config.h"
9 #include "structs.h"
10 #include <getopt.h>
11 #include <libudev.h>
12 #include "mpath_persist.h"
13 #include "mpath_persist_int.h"
14 #include "main.h"
15 #include "debug.h"
16 #include <pthread.h>
17 #include <ctype.h>
18 #include <string.h>
19 #include <errno.h>
20 #include "version.h"
21
22 static const char * pr_type_strs[] = {
23         "obsolete [0]",
24         "Write Exclusive",
25         "obsolete [2]",
26         "Exclusive Access",
27         "obsolete [4]",
28         "Write Exclusive, registrants only",
29         "Exclusive Access, registrants only",
30         "Write Exclusive, all registrants",
31         "Exclusive Access, all registrants",
32         "obsolete [9]", "obsolete [0xa]", "obsolete [0xb]", "obsolete [0xc]",
33         "obsolete [0xd]", "obsolete [0xe]", "obsolete [0xf]",
34 };
35
36 int get_transportids_length(unsigned char * transportid_arr, int max_transportid, int num_transportids);
37 void mpath_print_buf_readcap(struct prin_resp *pr_buff);
38 void mpath_print_buf_readfullstat(struct prin_resp *pr_buff);
39 void mpath_print_buf_readresv(struct prin_resp *pr_buff);
40 void mpath_print_buf_readkeys(struct prin_resp *pr_buff);
41 void dumpHex(const char* str, int len, int no_ascii);
42 void * mpath_alloc_prin_response(int prin_sa);
43 void mpath_print_transport_id(struct prin_fulldescr *fdesc);
44 int construct_transportid(const char * inp, struct transportid transid[], int num_transportids);
45
46 void rcu_register_thread_memb(void) {}
47
48 void rcu_unregister_thread_memb(void) {}
49
50
51 static int verbose, loglevel, noisy;
52
53 static int handle_args(int argc, char * argv[], int line);
54
55 static int do_batch_file(const char *batch_fn)
56 {
57         char command[] = "mpathpersist";
58         const int ARGV_CHUNK = 2;
59         const char delims[] = " \t\n";
60         size_t len = 0;
61         char *line = NULL;
62         ssize_t n;
63         int nline = 0;
64         int argl = ARGV_CHUNK;
65         FILE *fl;
66         char **argv = calloc(argl, sizeof(*argv));
67         int ret = MPATH_PR_SUCCESS;
68
69         if (argv == NULL)
70                 return MPATH_PR_OTHER;
71
72         fl = fopen(batch_fn, "r");
73         if (fl == NULL) {
74                 fprintf(stderr, "unable to open %s: %s\n",
75                         batch_fn, strerror(errno));
76                 free(argv);
77                 return MPATH_PR_SYNTAX_ERROR;
78         } else {
79                 if (verbose >= 2)
80                         fprintf(stderr, "running batch file %s\n",
81                                 batch_fn);
82         }
83
84         while ((n = getline(&line, &len, fl)) != -1) {
85                 char *_token, *token;
86                 int argc = 0;
87                 int rv;
88
89                 nline++;
90                 argv[argc++] = command;
91
92                 if (line[n-1] == '\n')
93                         line[n-1] = '\0';
94                 if (verbose >= 3)
95                         fprintf(stderr, "processing line %d: %s\n",
96                                 nline, line);
97
98                 for (token = strtok_r(line, delims, &_token);
99                      token != NULL && *token != '#';
100                      token = strtok_r(NULL, delims, &_token)) {
101
102                         if (argc >= argl) {
103                                 int argn = argl + ARGV_CHUNK;
104                                 char **tmp;
105
106                                 tmp = realloc(argv, argn * sizeof(*argv));
107                                 if (tmp == NULL)
108                                         break;
109                                 argv = tmp;
110                                 argl = argn;
111                         }
112
113                         if (argc == 1 && !strcmp(token, command))
114                                 continue;
115
116                         argv[argc++] = token;
117                 }
118
119                 if (argc <= 1)
120                         continue;
121
122                 if (verbose >= 2) {
123                         int i;
124
125                         fprintf(stderr, "## file %s line %d:", batch_fn, nline);
126                         for (i = 0; i < argc; i++)
127                                 fprintf(stderr, " %s", argv[i]);
128                         fprintf(stderr, "\n");
129                 }
130
131                 optind = 0;
132                 rv = handle_args(argc, argv, nline);
133                 if (rv != MPATH_PR_SUCCESS)
134                         ret = rv;
135         }
136
137         fclose(fl);
138         free(argv);
139         free(line);
140         return ret;
141 }
142
143 static struct prout_param_descriptor *
144 alloc_prout_param_descriptor(int num_transportid)
145 {
146         struct prout_param_descriptor *paramp;
147
148         if (num_transportid < 0 || num_transportid > MPATH_MX_TIDS)
149                 return NULL;
150
151         paramp= malloc(sizeof(struct prout_param_descriptor) +
152                                 (sizeof(struct transportid *) * num_transportid));
153
154         if (!paramp)
155                 return NULL;
156
157         memset(paramp, 0, sizeof(struct prout_param_descriptor) +
158                         (sizeof(struct transportid *) * num_transportid));
159         return paramp;
160 }
161
162 static void free_prout_param_descriptor(struct prout_param_descriptor *paramp)
163 {
164         unsigned int i;
165         if (!paramp)
166                 return;
167
168         for (i = 0; i < paramp->num_transportid; i++)
169                 free(paramp->trnptid_list[i]);
170
171         free(paramp);
172 }
173
174 static int handle_args(int argc, char * argv[], int nline)
175 {
176         int c;
177         int fd = -1;
178         const char *device_name = NULL;
179         int num_prin_sa = 0;
180         int num_prout_sa = 0;
181         int num_prout_param = 0;
182         int prin_flag = 0;
183         int prout_flag = 0;
184         int ret = 0;
185         int hex = 0;
186         uint64_t param_sark = 0;
187         unsigned int prout_type = 0;
188         int param_alltgpt = 0;
189         int param_aptpl = 0;
190         uint64_t param_rk = 0;
191         unsigned int param_rtp = 0;
192         int num_transportids = 0;
193         struct transportid transportids[MPATH_MX_TIDS];
194         int prout = 1;
195         int prin = 1;
196         int prin_sa = -1;
197         int prout_sa = -1;
198         char *batch_fn = NULL;
199         void *resp = NULL;
200
201         memset(transportids, 0, MPATH_MX_TIDS * sizeof(struct transportid));
202
203         while (1)
204         {
205                 int option_index = 0;
206
207                 c = getopt_long (argc, argv, "v:Cd:hHioYZK:S:PAT:skrGILcRX:l:f:",
208                                 long_options, &option_index);
209                 if (c == -1)
210                         break;
211
212                 switch (c)
213                 {
214                         case 'f':
215                                 if (nline != 0) {
216                                         fprintf(stderr,
217                                                 "ERROR: -f option not allowed in batch file\n");
218                                         ret = MPATH_PR_SYNTAX_ERROR;
219                                         goto out;
220                                 }
221                                 if (batch_fn != NULL) {
222                                         fprintf(stderr,
223                                                 "ERROR: -f option can be used at most once\n");
224                                         ret = MPATH_PR_SYNTAX_ERROR;
225                                         goto out;
226                                 }
227                                 batch_fn = strdup(optarg);
228                                 break;
229                         case 'v':
230                                 if (nline == 0 && 1 != sscanf (optarg, "%d", &loglevel))
231                                 {
232                                         fprintf (stderr, "bad argument to '--verbose'\n");
233                                         ret = MPATH_PR_SYNTAX_ERROR;
234                                         goto out;
235                                 }
236                                 break;
237
238                         case 'C':
239                                 prout_sa = MPATH_PROUT_CLEAR_SA;
240                                 ++num_prout_sa;
241                                 break;
242
243                         case 'd':
244                                 device_name = optarg;
245                                 break;
246
247                         case 'h':
248                                 usage ();
249                                 free(batch_fn);
250                                 return 0;
251
252                         case 'H':
253                                 hex=1;
254                                 break;
255
256                         case 'i':
257                                 prin_flag = 1;
258                                 break;
259
260                         case 'o':
261                                 prout_flag = 1;
262                                 break;
263
264                         case 'Y':
265                                 param_alltgpt = 1;
266                                 ++num_prout_param;
267                                 break;
268                         case 'Z':
269                                 param_aptpl = 1;
270                                 ++num_prout_param;
271                                 break;
272                         case 'K':
273                                 if (1 != sscanf (optarg, "%" SCNx64 "", &param_rk))
274                                 {
275                                         fprintf (stderr, "bad argument to '--param-rk'\n");
276                                         ret = MPATH_PR_SYNTAX_ERROR;
277                                         goto out;
278                                 }
279                                 ++num_prout_param;
280                                 break;
281
282                         case 'S':
283                                 if (1 != sscanf (optarg, "%" SCNx64 "", &param_sark))
284                                 {
285                                         fprintf (stderr, "bad argument to '--param-sark'\n");
286                                         ret = MPATH_PR_SYNTAX_ERROR;
287                                         goto out;
288                                 }
289                                 ++num_prout_param;
290                                 break;
291
292                         case 'P':
293                                 prout_sa = MPATH_PROUT_PREE_SA;
294                                 ++num_prout_sa;
295                                 break;
296
297                         case 'A':
298                                 prout_sa = MPATH_PROUT_PREE_AB_SA;
299                                 ++num_prout_sa;
300                                 break;
301
302                         case 'T':
303                                 if (1 != sscanf (optarg, "%x", &prout_type))
304                                 {
305                                         fprintf (stderr, "bad argument to '--prout-type'\n");
306                                         ret = MPATH_PR_SYNTAX_ERROR;
307                                         goto out;
308                                 }
309                                 ++num_prout_param;
310                                 break;
311
312                         case 's':
313                                 prin_sa = MPATH_PRIN_RFSTAT_SA;
314                                 ++num_prin_sa;
315                                 break;
316
317                         case 'k':
318                                 prin_sa = MPATH_PRIN_RKEY_SA;
319                                 ++num_prin_sa;
320                                 break;
321
322                         case 'r':
323                                 prin_sa = MPATH_PRIN_RRES_SA;
324                                 ++num_prin_sa;
325                                 break;
326
327                         case 'G':
328                                 prout_sa = MPATH_PROUT_REG_SA;
329                                 ++num_prout_sa;
330                                 break;
331
332                         case 'I':
333                                 prout_sa = MPATH_PROUT_REG_IGN_SA;
334                                 ++num_prout_sa;
335                                 break;
336
337                         case 'L':
338                                 prout_sa = MPATH_PROUT_REL_SA;
339                                 ++num_prout_sa;
340                                 break;
341
342                         case 'c':
343                                 prin_sa = MPATH_PRIN_RCAP_SA;
344                                 ++num_prin_sa;
345                                 break;
346
347                         case 'R':
348                                 prout_sa = MPATH_PROUT_RES_SA;
349                                 ++num_prout_sa;
350                                 break;
351
352                         case 'X':
353                                 if (0 != construct_transportid(optarg, transportids, num_transportids)) {
354                                         fprintf(stderr, "bad argument to '--transport-id'\n");
355                                         ret = MPATH_PR_SYNTAX_ERROR;
356                                         goto out;
357                                 }
358
359                                 ++num_transportids;
360                                 break;
361
362                         case 'l':
363                                 if (1 != sscanf(optarg, "%u", &mpath_mx_alloc_len)) {
364                                         fprintf(stderr, "bad argument to '--alloc-length'\n");
365                                         ret = MPATH_PR_SYNTAX_ERROR;
366                                         goto out;
367                                 } else if (MPATH_MAX_PARAM_LEN < mpath_mx_alloc_len) {
368                                         fprintf(stderr, "'--alloc-length' argument exceeds maximum"
369                                                         " limit(%d)\n", MPATH_MAX_PARAM_LEN);
370                                         ret = MPATH_PR_SYNTAX_ERROR;
371                                         goto out;
372                                 }
373                                 break;
374
375                         default:
376                                 fprintf(stderr, "unrecognised switch " "code 0x%x ??\n", c);
377                                 ret = MPATH_PR_SYNTAX_ERROR;
378                                 goto out;
379                 }
380         }
381
382         if (optind < argc)
383         {
384
385                 if (NULL == device_name)
386                 {
387                         device_name = argv[optind];
388                         ++optind;
389                 }
390                 if (optind < argc)
391                 {
392                         for (; optind < argc; ++optind)
393                                 fprintf (stderr, "Unexpected extra argument: %s\n", argv[optind]);
394                         ret = MPATH_PR_SYNTAX_ERROR;
395                         goto out;
396                 }
397         }
398
399         if (nline == 0) {
400                 /* set verbosity */
401                 noisy = (loglevel >= 3) ? 1 : hex;
402                 verbose = (loglevel >= 3)? 3: loglevel;
403                 ret = mpath_persistent_reserve_init_vecs(verbose);
404                 if (ret != MPATH_PR_SUCCESS)
405                         goto out;
406         }
407
408         if ((prout_flag + prin_flag) == 0 && batch_fn == NULL)
409         {
410                 fprintf (stderr, "choose either '--in' or '--out' \n");
411                 ret = MPATH_PR_SYNTAX_ERROR;
412                 goto out;
413         }
414         if ((prout_flag + prin_flag) > 1)
415         {
416                 fprintf (stderr, "choose either '--in' or '--out' \n");
417                 ret = MPATH_PR_SYNTAX_ERROR;
418                 goto out;
419         }
420         else if (prout_flag)
421         {                               /* syntax check on PROUT arguments */
422                 prin = 0;
423                 if ((1 != num_prout_sa) || (0 != num_prin_sa))
424                 {
425                         fprintf (stderr, " For Persistent Reserve Out only one "
426                                         "appropriate\n service action must be "
427                                         "chosen \n");
428                         ret = MPATH_PR_SYNTAX_ERROR;
429                         goto out;
430                 }
431         }
432         else if (prin_flag)
433         {                               /* syntax check on PRIN arguments */
434                 prout = 0;
435                 if (num_prout_sa > 0)
436                 {
437                         fprintf (stderr, " When a service action for Persistent "
438                                         "Reserve Out is chosen the\n"
439                                         " '--out' option must be given \n");
440                         ret = MPATH_PR_SYNTAX_ERROR;
441                         goto out;
442                 }
443                 if (0 == num_prin_sa)
444                 {
445                         fprintf (stderr,
446                                         " No service action given for Persistent Reserve IN\n");
447                         ret = MPATH_PR_SYNTAX_ERROR;
448                         goto out;
449                 }
450                 else if (num_prin_sa > 1)
451                 {
452                         fprintf (stderr, " Too many service actions given; choose "
453                                         "one only\n");
454                         ret = MPATH_PR_SYNTAX_ERROR;
455                         goto out;
456                 }
457         }
458         else
459         {
460                 if (batch_fn == NULL)
461                         ret = MPATH_PR_SYNTAX_ERROR;
462                 goto out;
463         }
464
465         if ((param_rtp) && (MPATH_PROUT_REG_MOV_SA != prout_sa))
466         {
467                 fprintf (stderr, " --relative-target-port"
468                                 " only useful with --register-move\n");
469                 ret = MPATH_PR_SYNTAX_ERROR;
470                 goto out;
471         }
472
473         if (((MPATH_PROUT_RES_SA == prout_sa) ||
474                                 (MPATH_PROUT_REL_SA == prout_sa) ||
475                                 (MPATH_PROUT_PREE_SA == prout_sa) ||
476                                 (MPATH_PROUT_PREE_AB_SA == prout_sa)) &&
477                         (0 == prout_type)) {
478                 fprintf(stderr, "Warning: --prout-type probably needs to be "
479                                 "given\n");
480         }
481         if ((verbose > 2) && num_transportids)
482         {
483                 fprintf (stderr, "number of tranport-ids decoded from "
484                                 "command line : %d\n", num_transportids);
485         }
486
487         if (device_name == NULL)
488         {
489                 fprintf (stderr, "No device name given \n");
490                 ret = MPATH_PR_SYNTAX_ERROR;
491                 goto out;
492         }
493
494         /* open device */
495         if ((fd = open (device_name, O_RDONLY)) < 0)
496         {
497                 fprintf (stderr, "%s: error opening file (rw) fd=%d\n",
498                                 device_name, fd);
499                 ret = MPATH_PR_FILE_ERROR;
500                 goto out;
501         }
502
503
504         if (prin)
505         {
506                 resp = mpath_alloc_prin_response(prin_sa);
507                 if (!resp)
508                 {
509                         fprintf (stderr, "failed to allocate PRIN response buffer\n");
510                         ret = MPATH_PR_OTHER;
511                         goto out_fd;
512                 }
513
514                 ret = __mpath_persistent_reserve_in (fd, prin_sa, resp, noisy);
515                 if (ret != MPATH_PR_SUCCESS )
516                 {
517                         fprintf (stderr, "Persistent Reserve IN command failed\n");
518                         free(resp);
519                         goto out_fd;
520                 }
521
522                 switch(prin_sa)
523                 {
524                         case MPATH_PRIN_RKEY_SA:
525                                 mpath_print_buf_readkeys(resp);
526                                 break;
527                         case MPATH_PRIN_RRES_SA:
528                                 mpath_print_buf_readresv(resp);
529                                 break;
530                         case MPATH_PRIN_RCAP_SA:
531                                 mpath_print_buf_readcap(resp);
532                                 break;
533                         case MPATH_PRIN_RFSTAT_SA:
534                                 mpath_print_buf_readfullstat(resp);
535                                 break;
536                 }
537                 free(resp);
538         }
539         else if (prout)
540         {
541                 int j;
542                 struct prout_param_descriptor *paramp;
543
544                 paramp = alloc_prout_param_descriptor(num_transportids);
545                 if (!paramp) {
546                         fprintf(stderr, "malloc paramp failed\n");
547                         ret = MPATH_PR_OTHER;
548                         goto out_fd;
549                 }
550
551                 for (j = 7; j >= 0; --j) {
552                         paramp->key[j] = (param_rk & 0xff);
553                         param_rk >>= 8;
554                 }
555
556                 for (j = 7; j >= 0; --j) {
557                         paramp->sa_key[j] = (param_sark & 0xff);
558                         param_sark >>= 8;
559                 }
560
561                 if (param_alltgpt)
562                         paramp->sa_flags |= MPATH_F_ALL_TG_PT_MASK;
563                 if (param_aptpl)
564                         paramp->sa_flags |= MPATH_F_APTPL_MASK;
565
566                 if (num_transportids)
567                 {
568                         paramp->sa_flags |= MPATH_F_SPEC_I_PT_MASK;
569                         paramp->num_transportid = num_transportids;
570                         for (j = 0 ; j < num_transportids; j++)
571                         {
572                                 paramp->trnptid_list[j] = (struct transportid *)malloc(sizeof(struct transportid));
573                                 if (!paramp->trnptid_list[j]) {
574                                         fprintf(stderr, "malloc paramp->trnptid_list[%d] failed.\n", j);
575                                         ret = MPATH_PR_OTHER;
576                                         free_prout_param_descriptor(paramp);
577                                         goto out_fd;
578                                 }
579                                 memcpy(paramp->trnptid_list[j], &transportids[j],sizeof(struct transportid));
580                         }
581                 }
582
583                 /* PROUT commands other than 'register and move' */
584                 ret = __mpath_persistent_reserve_out (fd, prout_sa, 0, prout_type,
585                                 paramp, noisy);
586                 free_prout_param_descriptor(paramp);
587         }
588
589         if (ret != MPATH_PR_SUCCESS)
590         {
591                 switch(ret)
592                 {
593                         case MPATH_PR_SENSE_UNIT_ATTENTION:
594                                 printf("persistent reserve out: scsi status: Unit Attention\n");
595                                 break;
596                         case MPATH_PR_RESERV_CONFLICT:
597                                 printf("persistent reserve out: scsi status: Reservation Conflict\n");
598                                 break;
599                 }
600                 printf("PR out: command failed\n");
601         }
602
603 out_fd:
604         close (fd);
605 out :
606         if (ret == MPATH_PR_SYNTAX_ERROR) {
607                 free(batch_fn);
608                 if (nline == 0)
609                         usage();
610                 else
611                         fprintf(stderr, "syntax error on line %d in batch file\n",
612                                 nline);
613         } else if (batch_fn != NULL) {
614                 int rv = do_batch_file(batch_fn);
615
616                 free(batch_fn);
617                 ret = ret == 0 ? rv : ret;
618         }
619         if (nline == 0)
620                 mpath_persistent_reserve_free_vecs();
621         return (ret >= 0) ? ret : MPATH_PR_OTHER;
622 }
623
624 int main(int argc, char *argv[])
625 {
626         int ret;
627
628         if (optind == argc)
629         {
630
631                 fprintf (stderr, "No parameter used\n");
632                 usage ();
633                 exit (1);
634         }
635
636         if (getuid () != 0)
637         {
638                 fprintf (stderr, "need to be root\n");
639                 exit (1);
640         }
641
642         if (libmpathpersist_init()) {
643                 exit(1);
644         }
645         if (atexit((void(*)(void))libmpathpersist_exit))
646                 fprintf(stderr, "failed to register cleanup handler for libmpathpersist: %m");
647
648         ret = handle_args(argc, argv, 0);
649         return (ret >= 0) ? ret : MPATH_PR_OTHER;
650 }
651
652 int
653 get_transportids_length(unsigned char * transportid_arr, int max_transportid, int num_transportids)
654 {
655         int compact_len = 0;
656         unsigned char * ucp = transportid_arr;
657         int k, off, protocol_id, len;
658         for (k = 0, off = 0; ((k < num_transportids) && (k < max_transportid));
659                         ++k, off += MPATH_MX_TID_LEN) {
660                 protocol_id = ucp[off] & 0xf;
661                 if (5 == protocol_id) {
662                         len = (ucp[off + 2] << 8) + ucp[off + 3] + 4;
663                         if (len < 24)
664                                 len = 24;
665                         if (off > compact_len)
666                                 memmove(ucp + compact_len, ucp + off, len);
667                         compact_len += len;
668
669                 } else {
670                         if (off > compact_len)
671                                 memmove(ucp + compact_len, ucp + off, 24);
672                         compact_len += 24;
673                 }
674         }
675
676         return compact_len;
677 }
678
679 void mpath_print_buf_readkeys( struct prin_resp *pr_buff)
680 {
681         int i,j,k, num;
682         unsigned char *keyp;
683         uint64_t prkey;
684         printf("  PR generation=0x%x, ", pr_buff->prin_descriptor.prin_readkeys.prgeneration);
685
686         num = pr_buff->prin_descriptor.prin_readkeys.additional_length / 8;
687         if (0 == num) {
688                 printf("        0 registered reservation key.\n");
689                 return;
690         }
691         else if (1 == num)
692                 printf("        1 registered reservation key follows:\n");
693         else
694                 printf("        %d registered reservation keys follow:\n", num);
695
696
697         keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[0];
698         for (i = 0; i < num ; i++)
699         {
700                 prkey = 0;
701                 for (j = 0; j < 8; ++j) {
702
703                         if (j > 0)
704                                 prkey <<= 8;
705                         prkey |= keyp[j];
706                 }
707                 printf("    0x%" PRIx64 "\n", prkey);
708                 k=8*i+j;
709                 keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[k];
710         }
711 }
712
713 void mpath_print_buf_readresv( struct prin_resp *pr_buff)
714 {
715         int j, num, scope=0, type=0;
716         unsigned char *keyp;
717         uint64_t prkey;
718
719         num = pr_buff->prin_descriptor.prin_readresv.additional_length / 8;
720         if (0 == num)
721         {
722                 printf("  PR generation=0x%x, there is NO reservation held \n", pr_buff->prin_descriptor.prin_readresv.prgeneration);
723                 return ;
724         }
725         else
726                 printf("  PR generation=0x%x, Reservation follows:\n", pr_buff->prin_descriptor.prin_readresv.prgeneration);
727         keyp = (unsigned  char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[0];
728         prkey = 0;
729         for (j = 0; j < 8; ++j) {
730                 if (j > 0)
731                         prkey <<= 8;
732                 prkey |= keyp[j];
733         }
734
735         printf("   Key = 0x%" PRIx64 "\n", prkey);
736
737         scope = (pr_buff->prin_descriptor.prin_readresv.scope_type >> 4) &  0x0f;
738         type = pr_buff->prin_descriptor.prin_readresv.scope_type & 0x0f;
739
740         if (scope == 0)
741                 printf("  scope = LU_SCOPE, type = %s", pr_type_strs[type]);
742         else
743                 printf("  scope = %d, type = %s", scope, pr_type_strs[type]);
744
745         printf("\n");
746
747 }
748
749 void mpath_print_buf_readcap( struct prin_resp *pr_buff)
750 {
751         if ( pr_buff->prin_descriptor.prin_readcap.length <= 2 ) {
752                 fprintf(stderr, "Unexpected response for PRIN Report "
753                                 "Capabilities\n");
754                 return; //MALFORMED;
755         }
756
757         printf("Report capabilities response:\n");
758
759         printf("  Compatible Reservation Handling(CRH): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x10));
760         printf("  Specify Initiator Ports Capable(SIP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x8));
761         printf("  All Target Ports Capable(ATP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x4 ));
762         printf("  Persist Through Power Loss Capable(PTPL_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0]));
763         printf("  Type Mask Valid(TMV): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80));
764         printf("  Allow Commands: %d\n", !!(( pr_buff->prin_descriptor.prin_readcap.flags[1] >> 4) & 0x7));
765         printf("  Persist Through Power Loss Active(PTPL_A): %d\n",
766                         !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x1));
767
768         if(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80)
769         {
770                 printf("    Support indicated in Type mask:\n");
771
772                 printf("      %s: %d\n", pr_type_strs[7], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x80);
773                 printf("      %s: %d\n", pr_type_strs[6], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x40);
774                 printf("      %s: %d\n", pr_type_strs[5], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x20);
775                 printf("      %s: %d\n", pr_type_strs[3], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x8);
776                 printf("      %s: %d\n", pr_type_strs[1], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x2);
777                 printf("      %s: %d\n", pr_type_strs[8], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x100);
778         }
779 }
780
781 void mpath_print_buf_readfullstat( struct prin_resp *pr_buff)
782 {
783
784         int i,j, num;
785         uint64_t  prkey;
786         uint16_t  rel_pt_addr;
787         unsigned char * keyp;
788
789         num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
790         if (0 == num)
791         {
792                 printf("  PR generation=0x%x \n", pr_buff->prin_descriptor.prin_readfd.prgeneration);
793                 return ;
794         }
795         else
796                 printf("  PR generation=0x%x \n", pr_buff->prin_descriptor.prin_readfd.prgeneration);
797
798         for (i = 0 ; i < num; i++)
799         {
800                 keyp = (unsigned  char *)&pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key;
801
802                 prkey = 0;
803                 for (j = 0; j < 8; ++j) {
804                         if (j > 0)
805                                 prkey <<= 8;
806                         prkey |= *keyp;
807                         ++keyp;
808                 }
809                 printf("   Key = 0x%" PRIx64 "\n", prkey);
810
811                 if (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->flag & 0x02)
812                         printf("      All target ports bit set\n");
813                 else {
814                         printf("      All target ports bit clear\n");
815
816                         rel_pt_addr = pr_buff->prin_descriptor.prin_readfd.descriptors[i]->rtpi;
817                         printf("      Relative port address: 0x%x\n",
818                                         rel_pt_addr);
819                 }
820
821                 if (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->flag & 0x1) {
822                         printf("      << Reservation holder >>\n");
823                         j = ((pr_buff->prin_descriptor.prin_readfd.descriptors[i]->scope_type >> 4) & 0xf);
824                         if (0 == j)
825                                 printf("      scope: LU_SCOPE, ");
826                         else
827                                 printf("      scope: %d ", j);
828                         j = (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->scope_type & 0xf);
829                         printf(" type: %s\n", pr_type_strs[j]);
830                 } else
831                         printf("      not reservation holder\n");
832                 mpath_print_transport_id(pr_buff->prin_descriptor.prin_readfd.descriptors[i]);
833         }
834 }
835
836 static void usage(void)
837 {
838         fprintf(stderr, VERSION_STRING);
839         fprintf(stderr,
840                         "Usage: mpathpersist [OPTIONS] [DEVICE]\n"
841                         " Options:\n"
842                         "    --verbose|-v level         verbosity level\n"
843                         "                   0           Critical messages\n"
844                         "                   1           Error messages\n"
845                         "                   2           Warning messages\n"
846                         "                   3           Informational messages\n"
847                         "                   4           Informational messages with trace enabled\n"
848                         "    --clear|-C                 PR Out: Clear\n"
849                         "    --device=DEVICE|-d DEVICE  query or change DEVICE\n"
850                         "    --batch-file|-f FILE       run commands from FILE\n"
851                         "    --help|-h                  output this usage message\n"
852                         "    --hex|-H                   output response in hex\n"
853                         "    --in|-i                    request PR In command \n"
854                         "    --out|-o                   request PR Out command\n"
855                         "    --param-alltgpt|-Y         PR Out parameter 'ALL_TG_PT\n"
856                         "    --param-aptpl|-Z           PR Out parameter 'APTPL'\n"
857                         "    --read-keys|-k             PR In: Read Keys\n"
858                         "    --param-rk=RK|-K RK        PR Out parameter reservation key\n"
859                         "    --param-sark=SARK|-S SARK  PR Out parameter service action\n"
860                         "                               reservation key (SARK is in hex)\n"
861                         "    --preempt|-P               PR Out: Preempt\n"
862                         "    --preempt-abort|-A         PR Out: Preempt and Abort\n"
863                         "    --prout-type=TYPE|-T TYPE  PR Out command type\n"
864                         "    --read-full-status|-s      PR In: Read Full Status\n"
865                         "    --read-keys|-k             PR In: Read Keys\n"
866                         "    --read-reservation|-r      PR In: Read Reservation\n"
867                         "    --register|-G              PR Out: Register\n"
868                         "    --register-ignore|-I       PR Out: Register and Ignore\n"
869                         "    --release|-L               PR Out: Release\n"
870                         "    --report-capabilities|-c   PR In: Report Capabilities\n"
871                         "    --reserve|-R               PR Out: Reserve\n"
872                         "    --transport-id=TIDS|-X TIDS  TransportIDs can be mentioned\n"
873                         "                                 in several forms\n"
874                         "    --alloc-length=LEN|-l LEN  PR In: maximum allocation length\n");
875 }
876
877 void
878 mpath_print_transport_id(struct prin_fulldescr *fdesc)
879 {
880         switch (fdesc->trnptid.protocol_id) {
881         case MPATH_PROTOCOL_ID_FC:
882                 printf("   FCP-2 ");
883                 if (0 != fdesc->trnptid.format_code)
884                         printf(" [Unexpected format code: %d]\n",
885                                         fdesc->trnptid.format_code);
886                 dumpHex((const char *)fdesc->trnptid.n_port_name, 8, 0);
887                 break;
888         case MPATH_PROTOCOL_ID_ISCSI:
889                 printf("   iSCSI ");
890                 if (0 == fdesc->trnptid.format_code) {
891                         printf("name: %.*s\n", (int)sizeof(fdesc->trnptid.iscsi_name),
892                                 fdesc->trnptid.iscsi_name);
893                 }else if (1 == fdesc->trnptid.format_code){
894                         printf("world wide unique port id: %.*s\n",
895                                         (int)sizeof(fdesc->trnptid.iscsi_name),
896                                         fdesc->trnptid.iscsi_name);
897                 }else {
898                         printf("  [Unexpected format code: %d]\n", fdesc->trnptid.format_code);
899                         dumpHex((const char *)fdesc->trnptid.iscsi_name,
900                                  (int)sizeof(fdesc->trnptid.iscsi_name), 0);
901                 }
902                 break;
903         case MPATH_PROTOCOL_ID_SAS:
904                 printf("   SAS ");
905                 if (0 != fdesc->trnptid.format_code)
906                         printf(" [Unexpected format code: %d]\n",
907                                         fdesc->trnptid.format_code);
908                 dumpHex((const char *)fdesc->trnptid.sas_address, 8, 0);
909                 break;
910         default:
911                 return;
912         }
913 }
914
915 int
916 construct_transportid(const char * lcp, struct transportid transid[], int num_transportids)
917 {
918         int k = 0;
919         int j, n, b, c, len, alen;
920         const char * ecp;
921         const char * isip;
922
923         if ((0 == memcmp("fcp,", lcp, 4)) ||
924                         (0 == memcmp("FCP,", lcp, 4))) {
925                 lcp += 4;
926                 k = strspn(lcp, "0123456789aAbBcCdDeEfF");
927
928                 len = strlen(lcp);
929                 if (len != k) {
930                         fprintf(stderr, "badly formed symbolic FCP TransportID: %s\n",
931                                         lcp);
932                         return 1;
933                 }
934                 transid[num_transportids].format_code = MPATH_PROTOCOL_ID_FC;
935                 transid[num_transportids].protocol_id = MPATH_WWUI_DEVICE_NAME;
936                 for (k = 0, j = 0, b = 0; k < 16; ++k) {
937                         c = lcp[k];
938                         if (isdigit(c))
939                                 n = c - 0x30;
940                         else if (isupper(c))
941                                 n = c - 0x37;
942                         else
943                                 n = c - 0x57;
944                         if (k & 1) {
945                                 transid[num_transportids].n_port_name[j] = b | n;
946                                 ++j;
947                         } else
948                                 b = n << 4;
949                 }
950                 goto my_cont_b;
951         }
952         if ((0 == memcmp("sas,", lcp, 4)) || (0 == memcmp("SAS,", lcp, 4))) {
953                 lcp += 4;
954                 k = strspn(lcp, "0123456789aAbBcCdDeEfF");
955                 len =strlen(lcp);
956                 if (len != k) {
957                         fprintf(stderr, "badly formed symbolic SAS TransportID: %s\n",
958                                         lcp);
959                         return 1;
960                 }
961                 transid[num_transportids].format_code = MPATH_PROTOCOL_ID_SAS;
962                 transid[num_transportids].protocol_id = MPATH_WWUI_DEVICE_NAME;
963                 memcpy(&transid[num_transportids].sas_address, lcp, 8);
964
965                 goto my_cont_b;
966         }
967         if (0 == memcmp("iqn.", lcp, 4)) {
968                 ecp = strpbrk(lcp, " \t");
969                 isip = strstr(lcp, ",i,0x");
970                 if (ecp && (isip > ecp))
971                         isip = NULL;
972                 len = ecp ? (ecp - lcp) : (int)strlen(lcp);
973                 transid[num_transportids].format_code = (isip ? MPATH_WWUI_PORT_IDENTIFIER:MPATH_WWUI_DEVICE_NAME);
974                 transid[num_transportids].protocol_id = MPATH_PROTOCOL_ID_ISCSI;
975                 alen = len + 1; /* at least one trailing null */
976                 if (alen < 20)
977                         alen = 20;
978                 else if (0 != (alen % 4))
979                         alen = ((alen / 4) + 1) * 4;
980                 if (alen > 241) { /* sam5r02.pdf A.2 (Annex) */
981                         fprintf(stderr, "iSCSI name too long, alen=%d\n", alen);
982                         return 0;
983                 }
984                 transid[num_transportids].iscsi_name[1] = alen & 0xff;
985                 memcpy(&transid[num_transportids].iscsi_name[2], lcp, len);
986                 goto my_cont_b;
987         }
988 my_cont_b:
989         if (k >= MPATH_MAX_PARAM_LEN) {
990                 fprintf(stderr, "build_transportid: array length exceeded\n");
991                 return 1;
992         }
993         return 0;
994 }