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