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