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