d99c0dad8f50f7faf949698a93fff9484191a774
[multipath-tools/.git] / libmpathpersist / mpath_persist.c
1 #include "mpath_persist.h"
2 #include <libdevmapper.h>
3 #include <defaults.h>
4 #include <sys/stat.h>
5 #include <linux/kdev_t.h>
6 #include <fcntl.h>
7 #include <vector.h>
8 #include <checkers.h>
9 #include <structs.h>
10 #include <structs_vec.h>
11
12 #include <prio.h>
13 #include <unistd.h>
14 #include <devmapper.h>
15 #include <debug.h>
16 #include <config.h>
17 #include <switchgroup.h>
18 #include <discovery.h>
19 #include <dmparser.h>
20 #include <ctype.h>
21 #include <propsel.h>
22
23 #include "mpathpr.h"
24 #include "mpath_pr_ioctl.h"
25
26 #include <pthread.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #define __STDC_FORMAT_MACROS 1
32
33
34 int
35 mpath_lib_init (void)
36 {
37         if (load_config(DEFAULT_CONFIGFILE)){
38                 condlog(0, "Failed to initialize multipath config.");
39                 return 1;
40         }
41
42         return 0;
43 }
44
45 int
46 mpath_lib_exit (void)
47 {
48         dm_lib_release();
49         dm_lib_exit();
50         cleanup_prio();
51         cleanup_checkers();
52         free_config(conf);
53         conf = NULL;
54         return 0;
55 }
56
57 static int
58 updatepaths (struct multipath * mpp)
59 {
60         int i, j;
61         struct pathgroup * pgp;
62         struct path * pp;
63
64         if (!mpp->pg)
65                 return 0;
66
67         vector_foreach_slot (mpp->pg, pgp, i){
68                 if (!pgp->paths)
69                         continue;
70
71                 vector_foreach_slot (pgp->paths, pp, j){
72                         if (!strlen(pp->dev)){
73                                 if (devt2devname(pp->dev, pp->dev_t)){
74                                         /*
75                                          * path is not in sysfs anymore
76                                          */
77                                         pp->state = PATH_DOWN;
78                                         continue;
79                                 }
80                                 pp->mpp = mpp;
81                                 pathinfo(pp, conf->hwtable, DI_ALL);
82                                 continue;
83                         }
84                         pp->mpp = mpp;
85                         if (pp->state == PATH_UNCHECKED ||
86                                         pp->state == PATH_WILD)
87                                 pathinfo(pp, conf->hwtable, DI_CHECKER);
88
89                         if (pp->priority == PRIO_UNDEF)
90                                 pathinfo(pp, conf->hwtable, DI_PRIO);
91                 }
92         }
93         return 0;
94 }
95
96 int 
97 mpath_prin_activepath (struct multipath *mpp, int rq_servact,
98         struct prin_resp * resp, int noisy)
99 {
100         int i,j, ret = MPATH_PR_DMMP_ERROR;
101         struct pathgroup *pgp = NULL;
102         struct path *pp = NULL;
103
104         vector_foreach_slot (mpp->pg, pgp, j){
105                 vector_foreach_slot (pgp->paths, pp, i){
106                         if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
107                                 condlog(2, "%s: %s not available. Skip.", mpp->wwid, pp->dev);
108                                 condlog(3, "%s: status = %d.", mpp->wwid, pp->state);
109                                 continue;
110                         }
111
112                         condlog(3, "%s: sending pr in command to %s ", mpp->wwid, pp->dev);
113                         ret = mpath_send_prin_activepath(pp->dev, rq_servact, resp, noisy);
114                         switch(ret)
115                         {
116                                 case MPATH_PR_SUCCESS:
117                                 case MPATH_PR_SENSE_INVALID_OP:
118                                         return ret;
119                                 default:
120                                         continue;
121                         }
122                 }
123         }
124         return ret;     
125 }
126
127 int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp *resp, int noisy, int verbose)
128 {
129         struct stat info;
130         vector curmp = NULL;
131         vector pathvec = NULL;
132         char * alias;
133         struct multipath * mpp;
134         int map_present;
135         int major, minor;
136         int ret;
137
138         conf->verbosity = verbose;
139
140         if (fstat( fd, &info) != 0){
141                 condlog(0, "stat error %d", fd);
142                 return MPATH_PR_FILE_ERROR;
143         } 
144         if(!S_ISBLK(info.st_mode)){
145                 condlog(0, "Failed to get major:minor. fd = %d", fd);
146                 return MPATH_PR_FILE_ERROR;
147         }
148
149         major = (int)MAJOR(info.st_rdev);
150         minor = (int)MINOR(info.st_rdev);       
151         condlog(4, "Device %d:%d:  ", major, minor);
152
153         /* get alias from major:minor*/
154         alias = dm_mapname(major, minor);
155         if (!alias){
156                 condlog(0, "%d:%d failed to get device alias.", major, minor);
157                 return MPATH_PR_DMMP_ERROR;
158         }
159
160         condlog(3, "alias = %s", alias);
161         map_present = dm_map_present(alias);
162         if (map_present && dm_type(alias, TGT_MPATH) <= 0){
163                 condlog( 0, "%s: not a multipath device.", alias);
164                 ret = MPATH_PR_DMMP_ERROR;
165                 goto out;
166         }
167
168         /*
169          * allocate core vectors to store paths and multipaths
170          */
171         curmp = vector_alloc ();
172         pathvec = vector_alloc ();
173
174         if (!curmp || !pathvec){
175                 condlog (0, "%s: vector allocation failed.", alias);
176                 ret = MPATH_PR_DMMP_ERROR;
177                 goto out;
178         }
179
180         if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER))
181                 goto out1;
182
183         /* get info of all paths from the dm device     */
184         if (get_mpvec (curmp, pathvec, alias)){
185                 condlog(0, "%s: failed to get device info.", alias);
186                 ret = MPATH_PR_DMMP_ERROR;
187                 goto out1;
188         }
189
190         mpp = find_mp_by_alias(curmp, alias);
191         if (!mpp){
192                 condlog(0, "%s: devmap not registered.", alias);
193                 ret = MPATH_PR_DMMP_ERROR;
194                 goto out1;
195         }
196
197         ret = mpath_prin_activepath(mpp, rq_servact, resp, noisy);
198
199 out1:
200         free_multipathvec(curmp, KEEP_PATHS);
201         free_pathvec(pathvec, FREE_PATHS);      
202 out:
203         FREE(alias);
204         return ret;                                             
205 }
206
207 int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
208                 unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, int verbose)
209 {
210
211         struct stat info;
212
213         vector curmp = NULL;
214         vector pathvec = NULL;
215
216         char * alias;
217         struct multipath * mpp;
218         int map_present;
219         int major, minor;
220         int ret;
221         int j;
222         unsigned char *keyp;
223         uint64_t prkey;         
224
225         conf->verbosity = verbose;
226
227         if (fstat( fd, &info) != 0){
228                 condlog(0, "stat error fd=%d", fd);
229                 return MPATH_PR_FILE_ERROR;
230         }
231
232         if(!S_ISBLK(info.st_mode)){
233                 condlog(3, "Failed to get major:minor. fd=%d", fd);
234                 return MPATH_PR_FILE_ERROR;     
235         }       
236
237         major = (int)MAJOR(info.st_rdev);
238         minor = (int)MINOR(info.st_rdev);
239         condlog(4, "Device  %d:%d", major, minor);
240
241         /* get WWN of the device from major:minor*/
242         alias = dm_mapname(major, minor);
243         if (!alias){
244                 return MPATH_PR_DMMP_ERROR;
245         }
246
247         condlog(3, "alias = %s", alias);
248         map_present = dm_map_present(alias);
249
250         if (map_present && dm_type(alias, TGT_MPATH) <= 0){
251                 condlog(3, "%s: not a multipath device.", alias);
252                 ret = MPATH_PR_DMMP_ERROR;
253                 goto out;
254         }
255
256         /*
257          * allocate core vectors to store paths and multipaths
258          */
259         curmp = vector_alloc ();
260         pathvec = vector_alloc ();
261
262          if (!curmp || !pathvec){
263                 condlog (0, "%s: vector allocation failed.", alias);
264                 ret = MPATH_PR_DMMP_ERROR;
265                 goto out;
266         }
267
268         if (path_discovery(pathvec, conf, DI_SYSFS | DI_CHECKER))
269                 goto out1;
270
271         /* get info of all paths from the dm device     */
272         if (get_mpvec(curmp, pathvec, alias)){
273                 condlog(0, "%s: failed to get device info.", alias);
274                 ret = MPATH_PR_DMMP_ERROR;
275                 goto out1;
276         }
277
278         mpp = find_mp_by_alias(curmp, alias);
279
280         if (!mpp) {
281                 condlog(0, "%s: devmap not registered.", alias);
282                 ret = MPATH_PR_DMMP_ERROR;
283                 goto out1;
284         }
285
286         select_reservation_key(mpp);
287
288         switch(rq_servact)
289         {
290                 case MPATH_PROUT_REG_SA: 
291                 case MPATH_PROUT_REG_IGN_SA:  
292                         ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
293                         break;
294                 case MPATH_PROUT_RES_SA :  
295                 case MPATH_PROUT_PREE_SA :  
296                 case MPATH_PROUT_PREE_AB_SA :  
297                 case MPATH_PROUT_CLEAR_SA:  
298                         ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
299                         break;
300                 case MPATH_PROUT_REL_SA:
301                         ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
302                         break;
303                 default:
304                         ret = MPATH_PR_OTHER;
305                         goto out1;
306         }
307
308         if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_REG_SA) ||
309                                 (rq_servact ==  MPATH_PROUT_REG_IGN_SA)))
310         {
311                 keyp=paramp->sa_key;
312                 prkey = 0;
313                 for (j = 0; j < 8; ++j) {
314                         if (j > 0)
315                                 prkey <<= 8;
316                         prkey |= *keyp;
317                         ++keyp;
318                 }
319                 if (prkey == 0)
320                         update_prflag(alias, "unset", noisy);
321                 else
322                         update_prflag(alias, "set", noisy);
323         } else {
324                 if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_CLEAR_SA) || 
325                                         (rq_servact == MPATH_PROUT_PREE_AB_SA ))){
326                         update_prflag(alias, "unset", noisy);
327                 }
328         }
329 out1:
330         free_multipathvec(curmp, KEEP_PATHS);
331         free_pathvec(pathvec, FREE_PATHS);
332
333 out:
334         FREE(alias);
335         return ret; 
336 }
337
338 int
339 get_mpvec (vector curmp, vector pathvec, char * refwwid)
340 {
341         int i;
342         struct multipath *mpp;
343         char params[PARAMS_SIZE], status[PARAMS_SIZE];
344
345         if (dm_get_maps (curmp)){
346                 return 1;
347         }
348
349         vector_foreach_slot (curmp, mpp, i){
350                 /*
351                  * discard out of scope maps
352                  */
353                 if (mpp->alias && refwwid && strncmp (mpp->alias, refwwid, WWID_SIZE)){
354                         free_multipath (mpp, KEEP_PATHS);
355                         vector_del_slot (curmp, i);
356                         i--;
357                         continue;
358                 }
359
360                 dm_get_map(mpp->alias, &mpp->size, params);
361                 condlog(3, "params = %s", params);
362                 dm_get_status(mpp->alias, status);
363                 condlog(3, "status = %s", status);
364                 disassemble_map (pathvec, params, mpp);
365                 
366                 /*
367                  * disassemble_map() can add new paths to pathvec.
368                  * If not in "fast list mode", we need to fetch information
369                  * about them
370                  */
371                 updatepaths(mpp);
372                 mpp->bestpg = select_path_group (mpp);
373                 disassemble_status (status, mpp);
374
375         }
376         return MPATH_PR_SUCCESS ;
377 }
378
379 void * mpath_prin_pthread_fn (void *p)
380 {
381         int ret;
382         struct prin_param * pparam = (struct prin_param *)p;
383
384         ret = prin_do_scsi_ioctl(pparam->dev, pparam->rq_servact, pparam->resp,  pparam->noisy);
385         pparam->status = ret;   
386         pthread_exit(NULL);     
387 }
388
389 int mpath_send_prin_activepath (char * dev, int rq_servact, struct prin_resp * resp, int noisy)
390 {
391
392         int rc;
393
394         rc = prin_do_scsi_ioctl(dev, rq_servact, resp,  noisy);
395         
396         return (rc);
397 }
398
399 int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
400         unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
401 {
402
403         int i, j;
404         struct pathgroup *pgp = NULL;
405         struct path *pp = NULL;
406         int rollback = 0;
407         int active_pathcount=0; 
408         int rc;
409         int count=0;
410         int status = MPATH_PR_SUCCESS;
411         uint64_t sa_key;        
412
413         if (!mpp)
414                 return MPATH_PR_DMMP_ERROR; 
415
416         active_pathcount = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
417
418         if (active_pathcount == 0) {
419                 condlog (0, "%s: no path available", mpp->wwid);
420                 return MPATH_PR_DMMP_ERROR;
421         }
422
423         if ( paramp->sa_flags & MPATH_F_ALL_TG_PT_MASK ) {
424                 condlog (1, "Warning: ALL_TG_PT is set. Configuration not supported");
425         }
426
427         struct threadinfo thread[active_pathcount];
428
429         memset(thread, 0, sizeof(thread));
430
431         /* init thread parameter */
432         for (i =0; i< active_pathcount; i++){
433                 thread[i].param.rq_servact = rq_servact;
434                 thread[i].param.rq_scope = rq_scope;
435                 thread[i].param.rq_type = rq_type;
436                 thread[i].param.paramp = paramp;
437                 thread[i].param.noisy = noisy;
438                 thread[i].param.status = -1;
439
440                 condlog (3, "THRED ID [%d] INFO]", i);
441                 condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
442                 condlog (3, "rq_scope=%d ", thread[i].param.rq_scope); 
443                 condlog (3, "rq_type=%d ", thread[i].param.rq_type);  
444                 condlog (3, "rkey="); 
445                 condlog (3, "paramp->sa_flags =%02x ", thread[i].param.paramp->sa_flags); 
446                 condlog (3, "noisy=%d ", thread[i].param.noisy); 
447                 condlog (3, "status=%d ", thread[i].param.status); 
448         }
449
450         pthread_attr_t attr;
451         pthread_attr_init(&attr);
452         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
453
454         vector_foreach_slot (mpp->pg, pgp, j){
455                 vector_foreach_slot (pgp->paths, pp, i){
456                         if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
457                                 condlog (1, "%s: %s path not up. Skip.", mpp->wwid, pp->dev);
458                                 continue;
459                         }
460                         strncpy(thread[count].param.dev, pp->dev, FILE_NAME_SIZE);
461
462                         if (count && (thread[count].param.paramp->sa_flags & MPATH_F_SPEC_I_PT_MASK)){
463                                 /*
464                                  * Clearing SPEC_I_PT as transportids are already registered by now.
465                                  */
466                                 thread[count].param.paramp->sa_flags &= (~MPATH_F_SPEC_I_PT_MASK);
467                         }
468
469                         condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
470
471                         rc = pthread_create(&thread[count].id, &attr, mpath_prout_pthread_fn, (void *)(&thread[count].param));
472                         if (rc){
473                                 condlog (0, "%s: failed to create thread %d", mpp->wwid, rc);
474                         }
475                         count = count +1;
476                 }
477         }
478         for( i=0; i < active_pathcount ; i++){
479                 rc = pthread_join(thread[i].id, NULL);
480                 if (rc){
481                         condlog (0, "%s: Thread[%d] failed to join thread %d", mpp->wwid, i, rc);
482                 }
483                 if (!rollback && (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)){
484                         rollback = 1;
485                         sa_key = 0;
486                         for (i = 0; i < 8; ++i){
487                                 if (i > 0)
488                                         sa_key <<= 8;
489                                 sa_key |= paramp->sa_key[i];
490                         }
491                         status = MPATH_PR_RESERV_CONFLICT ;
492                 }
493                 if (!rollback && (status == MPATH_PR_SUCCESS)){
494                         status = thread[i].param.status;
495                 }
496         }
497         if (rollback && ((rq_servact == MPATH_PROUT_REG_SA) && sa_key != 0 )){
498                 condlog (3, "%s: ERROR: initiating pr out rollback", mpp->wwid);
499                 for( i=0 ; i < active_pathcount ; i++){
500                         if((thread[i].param.status == MPATH_PR_SUCCESS) &&
501                                         ((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
502                                 memcpy(&thread[i].param.paramp->key, &thread[i].param.paramp->sa_key, 8);
503                                 memset(&thread[i].param.paramp->sa_key, 0, 8);
504                                 thread[i].param.status = MPATH_PR_SUCCESS;
505                                 rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn, 
506                                                 (void *)(&thread[count].param));
507                                 if (rc){
508                                         condlog (0, "%s: failed to create thread for rollback. %d",  mpp->wwid, rc);
509                                 }
510                         }
511                 }
512                 for(i=0; i < active_pathcount ; i++){
513                         rc = pthread_join(thread[i].id, NULL);
514                         if (rc){
515                                 condlog (3, "%s: failed to join thread while rolling back %d",
516                                                 mpp->wwid, i);
517                         }
518                 }
519         }
520
521         pthread_attr_destroy(&attr);
522         return (status);
523 }
524
525 void * mpath_prout_pthread_fn(void *p)
526 {
527         int ret;
528         struct prout_param * param = (struct prout_param *)p;
529
530         ret = prout_do_scsi_ioctl( param->dev,param->rq_servact, param->rq_scope,
531                         param->rq_type, param->paramp, param->noisy);
532         param->status = ret;
533         pthread_exit(NULL);
534 }
535
536 int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
537         unsigned int rq_type, struct prout_param_descriptor* paramp, int noisy)
538 {
539         int i,j, ret;
540         struct pathgroup *pgp = NULL;
541         struct path *pp = NULL;
542
543         vector_foreach_slot (mpp->pg, pgp, j){
544                 vector_foreach_slot (pgp->paths, pp, i){
545                         if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
546                                 condlog (1, "%s: %s path not up. Skip", mpp->wwid, pp->dev); 
547                                 continue;
548                         }
549
550                         condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
551                         ret = send_prout_activepath(pp->dev, rq_servact, rq_scope, rq_type, 
552                                         paramp, noisy); 
553                         return ret ;
554                 }
555         }
556         return MPATH_PR_SUCCESS;
557 }
558
559 int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
560         unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
561 {
562         struct prout_param param;
563         param.rq_servact = rq_servact;
564         param.rq_scope  = rq_scope;
565         param.rq_type   = rq_type;
566         param.paramp    = paramp;
567         param.noisy = noisy;
568         param.status = -1;
569
570         pthread_t thread;
571         pthread_attr_t attr;
572         int rc;
573
574         memset(&thread, 0, sizeof(thread));
575         strncpy(param.dev, dev, FILE_NAME_SIZE);
576         /* Initialize and set thread joinable attribute */
577         pthread_attr_init(&attr);
578         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
579
580         rc = pthread_create(&thread, &attr, mpath_prout_pthread_fn, (void *)(&param));
581         if (rc){
582                 condlog (3, "%s: failed to create thread %d", dev, rc);
583                 exit(-1);
584         }
585         /* Free attribute and wait for the other threads */
586         pthread_attr_destroy(&attr);
587         rc = pthread_join(thread, NULL);
588
589         return (param.status);
590 }
591
592 int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
593         unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
594 {
595         int i, j;
596         int num = 0;
597         struct pathgroup *pgp = NULL;
598         struct path *pp = NULL;
599         int active_pathcount = 0;
600         pthread_attr_t attr;
601         int rc, found = 0;;
602         int count = 0;
603         int status = MPATH_PR_SUCCESS;
604         struct prin_resp resp;
605         struct prout_param_descriptor *pamp;
606         struct prin_resp *pr_buff;
607         int length;
608         struct transportid *pptr;       
609
610         if (!mpp)
611                 return MPATH_PR_DMMP_ERROR;
612
613         active_pathcount = pathcount (mpp, PATH_UP) + pathcount (mpp, PATH_GHOST);
614
615         struct threadinfo thread[active_pathcount];
616         memset(thread, 0, sizeof(thread));
617         for (i = 0; i < active_pathcount; i++){
618                 thread[i].param.rq_servact = rq_servact;
619                 thread[i].param.rq_scope = rq_scope;
620                 thread[i].param.rq_type = rq_type;
621                 thread[i].param.paramp = paramp;
622                 thread[i].param.noisy = noisy;
623                 thread[i].param.status = -1;
624
625                 condlog (3, " path count = %d", i);
626                 condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
627                 condlog (3, "rq_scope=%d ", thread[i].param.rq_scope);
628                 condlog (3, "rq_type=%d ", thread[i].param.rq_type);
629                 condlog (3, "noisy=%d ", thread[i].param.noisy);
630                 condlog (3, "status=%d ", thread[i].param.status);
631         }
632
633         pthread_attr_init (&attr);
634         pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
635
636         vector_foreach_slot (mpp->pg, pgp, j){
637                 vector_foreach_slot (pgp->paths, pp, i){
638                         if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
639                                 condlog (1, "%s: %s path not up.", mpp->wwid, pp->dev);
640                                 continue;
641                         }
642                         
643                         strncpy(thread[count].param.dev, pp->dev, FILE_NAME_SIZE);
644                         condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->dev);
645                         rc = pthread_create (&thread[count].id, &attr, mpath_prout_pthread_fn,
646                                         (void *) (&thread[count].param));
647                         if (rc)
648                                 condlog (0, "%s: failed to create thread. %d",  mpp->wwid, rc);
649                         count = count + 1;
650                 }
651         }
652         pthread_attr_destroy (&attr);
653         for (i = 0; i < active_pathcount; i++){
654                 rc = pthread_join (thread[i].id, NULL);
655                 if (rc){
656                         condlog (1, "%s: failed to join thread.  %d",  mpp->wwid,  rc);
657                 }
658         }
659
660         for (i = 0; i < active_pathcount; i++){
661                 /*  check thread status here and return the status */
662
663                 if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
664                         status = MPATH_PR_RESERV_CONFLICT;
665                 else if (status == MPATH_PR_SUCCESS
666                                 && thread[i].param.status != MPATH_PR_RESERV_CONFLICT)
667                         status = thread[i].param.status;
668         }
669
670         status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
671         if (status != MPATH_PR_SUCCESS){
672                 condlog (0, "%s: pr in read reservation command failed.", mpp->wwid);
673                 return MPATH_PR_OTHER;
674         }
675
676         num = resp.prin_descriptor.prin_readresv.additional_length / 8;
677         if (num == 0){
678                 condlog (2, "%s: Path holding reservation is released.", mpp->wwid);
679                 return MPATH_PR_SUCCESS;        
680         }
681         condlog (2, "%s: Path holding reservation is not avialable.", mpp->wwid);
682
683         pr_buff =  mpath_alloc_prin_response(MPATH_PRIN_RFSTAT_SA);
684         if (!pr_buff){
685                 condlog (0, "%s: failed to  alloc pr in response buffer.", mpp->wwid);  
686                 return MPATH_PR_OTHER;
687         }
688
689         status = mpath_prin_activepath (mpp, MPATH_PRIN_RFSTAT_SA, pr_buff, noisy);
690
691         if (status != MPATH_PR_SUCCESS){
692                 condlog (0,  "%s: pr in read full status command failed.",  mpp->wwid);
693                 goto out;
694         }
695
696         num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
697         if (0 == num){
698                 goto out;
699         }
700         length = sizeof (struct prout_param_descriptor) + (sizeof (struct transportid *));
701
702         pamp = (struct prout_param_descriptor *)malloc (length);
703         if (!pamp){
704                 condlog (0, "%s: failed to alloc pr out parameter.", mpp->wwid);
705                 goto out1;
706         }
707
708         memset(pamp, 0, length);
709
710         pamp->trnptid_list[0] = (struct transportid *) malloc (sizeof (struct transportid));
711         if (!pamp->trnptid_list[0]){
712                 condlog (0, "%s: failed to alloc pr out transportid.", mpp->wwid);
713                 goto out1;
714         }
715
716         if (mpp->reservation_key ){
717                 memcpy (pamp->key, mpp->reservation_key, 8);
718                 condlog (3, "%s: reservation key set.", mpp->wwid);
719         }
720
721         mpath_prout_common (mpp, MPATH_PROUT_CLEAR_SA, rq_scope, rq_type, pamp,
722                         noisy);
723
724         pamp->num_transportid = 1;
725         pptr=pamp->trnptid_list[0];
726
727         for (i = 0; i < num; i++){
728                 if (mpp->reservation_key && 
729                         memcmp(pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key,
730                         mpp->reservation_key, 8)){      
731                         /*register with tarnsport id*/
732                         memset(pamp, 0, length);
733                         pamp->trnptid_list[0] = pptr;
734                         memset (pamp->trnptid_list[0], 0, sizeof (struct transportid));
735                         memcpy (pamp->sa_key,
736                                         pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
737                         pamp->sa_flags = MPATH_F_SPEC_I_PT_MASK;
738                         pamp->num_transportid = 1;
739
740                         memcpy (pamp->trnptid_list[0],
741                                         &pr_buff->prin_descriptor.prin_readfd.descriptors[i]->trnptid,
742                                         sizeof (struct transportid));
743                         status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
744                                         pamp, noisy);
745
746                         pamp->sa_flags = 0;
747                         memcpy (pamp->key, pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
748                         memset (pamp->sa_key, 0, 8);
749                         pamp->num_transportid = 0;
750                         status = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
751                                         pamp, noisy);
752                 }
753                 else
754                 {
755                         if (mpp->reservation_key)
756                                 found = 1;
757                 }
758
759
760         }
761
762         if (found){
763                 memset (pamp, 0, length);
764                 memcpy (pamp->sa_key, mpp->reservation_key, 8);
765                 memset (pamp->key, 0, 8);
766                 status = mpath_prout_reg(mpp, MPATH_PROUT_REG_SA, rq_scope, rq_type, pamp, noisy);      
767         }
768
769
770         free(pptr);
771 out1:
772         free (pamp);
773 out:
774         free (pr_buff);
775         return (status);
776 }
777
778 void * mpath_alloc_prin_response(int prin_sa)
779 {
780         void * ptr = NULL;
781         int size=0;
782         switch (prin_sa)
783         {
784                 case MPATH_PRIN_RKEY_SA:
785                         size = sizeof(struct prin_readdescr);
786                         ptr = malloc(size);
787                         memset(ptr, 0, size);
788                         break;
789                 case MPATH_PRIN_RRES_SA:
790                         size = sizeof(struct prin_resvdescr);
791                         ptr = malloc(size);
792                         memset(ptr, 0, size);
793                         break;
794                 case MPATH_PRIN_RCAP_SA:
795                         size=sizeof(struct prin_capdescr);
796                         ptr = malloc(size);
797                         memset(ptr, 0, size);
798                         break;
799                 case MPATH_PRIN_RFSTAT_SA:
800                         size = sizeof(struct print_fulldescr_list) + 
801                                 sizeof(struct prin_fulldescr *)*MPATH_MX_TIDS;
802                         ptr = malloc(size);
803                         memset(ptr, 0, size);
804                         break;
805         }
806         return ptr;
807 }
808
809 int update_map_pr(struct multipath *mpp)
810 {
811         int noisy=0;
812         struct prin_resp *resp;
813         int i,j, ret, isFound;
814         unsigned char *keyp;
815         uint64_t prkey;
816
817         if (!mpp->reservation_key)
818         {
819                 /* Nothing to do. Assuming pr mgmt feature is disabled*/
820                 condlog(3, "%s: reservation_key not set in multiapth.conf", mpp->alias);
821                 return MPATH_PR_SUCCESS;
822         }
823
824         resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
825         if (!resp)
826         {
827                 condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
828                 return MPATH_PR_OTHER;
829         }
830         ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp, noisy);
831
832         if (ret != MPATH_PR_SUCCESS )
833         {
834                 condlog(0,"%s : pr in read keys service action failed Error=%d", mpp->alias, ret);
835                 free(resp);
836                 return  ret;
837         }
838
839         if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
840         {
841                 condlog(0,"%s: No key found. Device may not be registered. ", mpp->alias);
842                 free(resp);
843                 return MPATH_PR_SUCCESS;
844         }
845
846         prkey = 0;
847         keyp = mpp->reservation_key;
848         for (j = 0; j < 8; ++j) {
849                 if (j > 0)
850                         prkey <<= 8;
851                 prkey |= *keyp;
852                 ++keyp;
853         }
854         condlog(2, "%s: Multipath  reservation_key: 0x%" PRIx64 " ", mpp->alias, prkey);
855
856         isFound =0;
857         for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
858         {
859                 condlog(2, "%s: PR IN READKEYS[%d]  reservation key:", mpp->alias, i);
860                 dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i*8], 8 , 1);
861
862                 if (!memcmp(mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i*8], 8))
863                 {
864                         condlog(2, "%s: reservation key found in pr in readkeys response", mpp->alias);
865                         isFound =1;
866                 }
867         }
868
869         if (isFound)
870         {
871                 mpp->prflag = 1;
872                 condlog(2, "%s: prflag flag set.", mpp->alias );
873         }
874
875         free(resp);
876         return MPATH_PR_SUCCESS;
877 }
878
879
880