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