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