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