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