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