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