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