126601c340b497b11f0701e2ab2908ecdbd0f4be
[platform/upstream/multipath-tools.git] / libmpathpersist / mpath_pr_ioctl.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stddef.h>
4
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include <scsi/sg.h>
9 #include <scsi/scsi.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <sys/ioctl.h>
13 #include <unistd.h>
14 #include <libudev.h>
15 #include "mpath_pr_ioctl.h"
16 #include "mpath_persist.h"
17 #include "unaligned.h"
18
19 #include "debug.h"
20
21 #define FILE_NAME_SIZE          256
22
23 #define TIMEOUT 2000
24 #define MAXRETRY 5
25
26 int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp *resp, int noisy);
27 int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr,
28                               SenseData_t *Sensedata);
29 void dumpHex(const char* str, int len, int no_ascii);
30 int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
31                 unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
32 uint32_t  format_transportids(struct prout_param_descriptor *paramp);
33 void convert_be32_to_cpu(uint32_t *num);
34 void convert_be16_to_cpu(uint16_t *num);
35 void decode_transport_id(struct prin_fulldescr *fdesc, unsigned char * p, int length);
36 int get_prin_length(int rq_servact);
37 int mpath_isLittleEndian(void);
38
39 unsigned int mpath_mx_alloc_len;
40
41 int prout_do_scsi_ioctl(char * dev, int rq_servact, int rq_scope,
42                 unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy)
43 {
44
45         int status, paramlen = 24, ret = 0;
46         uint32_t translen=0;
47         int retry = MAXRETRY;
48         SenseData_t Sensedata;
49         struct sg_io_hdr io_hdr;
50         char devname[FILE_NAME_SIZE];
51         int fd = -1;
52
53         snprintf(devname, FILE_NAME_SIZE, "/dev/%s",dev);
54         fd = open(devname, O_RDONLY);
55         if(fd < 0){
56                 condlog (1, "%s: unable to open device.", dev);
57                 return MPATH_PR_FILE_ERROR;
58         }
59
60         unsigned char cdb[MPATH_PROUT_CMDLEN] =
61         {MPATH_PROUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
62
63
64         if (paramp->sa_flags & MPATH_F_SPEC_I_PT_MASK)
65         {
66                 translen = format_transportids(paramp);
67                 paramlen = 24 + translen;
68         }
69         else
70                 paramlen = 24;
71
72         if ( rq_servact > 0)
73                 cdb[1] = (unsigned char)(rq_servact & 0x1f);
74         cdb[2] = (((rq_scope & 0xf) << 4) | (rq_type & 0xf));
75         cdb[7] = (unsigned char)((paramlen >> 8) & 0xff);
76         cdb[8] = (unsigned char)(paramlen & 0xff);
77
78 retry :
79         condlog(4, "%s: rq_servact = %d", dev, rq_servact);
80         condlog(4, "%s: rq_scope = %d ", dev, rq_scope);
81         condlog(4, "%s: rq_type = %d ", dev, rq_type);
82         condlog(4, "%s: paramlen = %d", dev, paramlen);
83
84         if (noisy)
85         {
86                 condlog(4, "%s: Persistent Reservation OUT parameter:", dev);
87                 dumpHex((const char *)paramp, paramlen,1);
88         }
89
90         memset(&Sensedata, 0, sizeof(SenseData_t));
91         memset(&io_hdr,0 , sizeof( struct sg_io_hdr));
92         io_hdr.interface_id = 'S';
93         io_hdr.cmd_len = MPATH_PROUT_CMDLEN;
94         io_hdr.cmdp = cdb;
95         io_hdr.sbp = (void *)&Sensedata;
96         io_hdr.mx_sb_len = sizeof (SenseData_t);
97         io_hdr.timeout = TIMEOUT;
98
99         if (paramlen > 0) {
100                 io_hdr.dxferp = (void *)paramp;
101                 io_hdr.dxfer_len = paramlen;
102                 io_hdr.dxfer_direction = SG_DXFER_TO_DEV ;
103         }
104         else {
105                 io_hdr.dxfer_direction = SG_DXFER_NONE;
106         }
107         ret = ioctl(fd, SG_IO, &io_hdr);
108         if (ret < 0)
109         {
110                 condlog(0, "%s: ioctl failed %d", dev, ret);
111                 close(fd);
112                 return ret;
113         }
114
115         condlog(4, "%s: Duration=%u (ms)", dev, io_hdr.duration);
116
117         status = mpath_translate_response(dev, io_hdr, &Sensedata);
118         condlog(3, "%s: status = %d", dev, status);
119
120         if (status == MPATH_PR_SENSE_UNIT_ATTENTION && (retry > 0))
121         {
122                 --retry;
123                 condlog(3, "%s: retrying for Unit Attention. Remaining retries = %d",
124                         dev, retry);
125                 goto retry;
126         }
127
128         if (((status == MPATH_PR_SENSE_NOT_READY )&& (Sensedata.ASC == 0x04)&&
129                                 (Sensedata.ASCQ == 0x07))&& (retry > 0))
130         {
131                 usleep(1000);
132                 --retry;
133                 condlog(3, "%s: retrying for sense 02/04/07."
134                         " Remaining retries = %d", dev, retry);
135                 goto retry;
136         }
137
138         close(fd);
139         return status;
140 }
141
142 /*
143  * Helper macro to avoid overflow of prout_param_descriptor in
144  * format_transportids(). Data must not be written past
145  * MPATH_MAX_PARAM_LEN bytes from struct prout_param_descriptor.
146  */
147 #define check_overflow(ofs, n, start, label)                            \
148         do {                                                            \
149                 if ((ofs) + (n) +                                       \
150                     offsetof(struct prout_param_descriptor, private_buffer) \
151                     > MPATH_MAX_PARAM_LEN)                              \
152                 {                                                       \
153                         (ofs) = (start);                                \
154                         goto label;                                     \
155                 }                                                       \
156         } while(0)
157
158 uint32_t  format_transportids(struct prout_param_descriptor *paramp)
159 {
160         unsigned int i = 0, len;
161         uint32_t buff_offset = 4;
162         memset(paramp->private_buffer, 0, sizeof(paramp->private_buffer));
163         for (i=0; i < paramp->num_transportid; i++ )
164         {
165                 uint32_t start_offset = buff_offset;
166
167                 check_overflow(buff_offset, 1, start_offset, end_loop);
168                 paramp->private_buffer[buff_offset] = (uint8_t)((paramp->trnptid_list[i]->format_code & 0xff)|
169                                                         (paramp->trnptid_list[i]->protocol_id & 0xff));
170                 buff_offset += 1;
171                 switch(paramp->trnptid_list[i]->protocol_id)
172                 {
173                         case MPATH_PROTOCOL_ID_FC:
174                                 check_overflow(buff_offset, 7 + 8 + 8,
175                                                start_offset, end_loop);
176                                 buff_offset += 7;
177                                 memcpy(&paramp->private_buffer[buff_offset], &paramp->trnptid_list[i]->n_port_name, 8);
178                                 buff_offset +=8 ;
179                                 buff_offset +=8 ;
180                                 break;
181                         case MPATH_PROTOCOL_ID_SAS:
182                                 check_overflow(buff_offset, 3 + 12,
183                                                start_offset, end_loop);
184                                 buff_offset += 3;
185                                 memcpy(&paramp->private_buffer[buff_offset], &paramp->trnptid_list[i]->sas_address, 8);
186                                 buff_offset += 12;
187                                 break;
188                         case MPATH_PROTOCOL_ID_ISCSI:
189                                 len = (paramp->trnptid_list[i]->iscsi_name[1] & 0xff)+2;
190                                 check_overflow(buff_offset, 1 + len,
191                                                start_offset, end_loop);
192                                 buff_offset += 1;
193                                 memcpy(&paramp->private_buffer[buff_offset], &paramp->trnptid_list[i]->iscsi_name,len);
194                                 buff_offset += len ;
195                                 break;
196                 }
197
198         }
199 end_loop:
200         buff_offset -= 4;
201         paramp->private_buffer[0] = (unsigned char)((buff_offset >> 24) & 0xff);
202         paramp->private_buffer[1] = (unsigned char)((buff_offset >> 16) & 0xff);
203         paramp->private_buffer[2] = (unsigned char)((buff_offset >> 8) & 0xff);
204         paramp->private_buffer[3] = (unsigned char)(buff_offset & 0xff);
205         buff_offset += 4;
206         return buff_offset;
207 }
208
209 static void mpath_format_readkeys(struct prin_resp *pr_buff)
210 {
211         convert_be32_to_cpu(&pr_buff->prin_descriptor.prin_readkeys.prgeneration);
212         convert_be32_to_cpu(&pr_buff->prin_descriptor.prin_readkeys.additional_length);
213 }
214
215 static void mpath_format_readresv(struct prin_resp *pr_buff)
216 {
217
218         convert_be32_to_cpu(&pr_buff->prin_descriptor.prin_readresv.prgeneration);
219         convert_be32_to_cpu(&pr_buff->prin_descriptor.prin_readresv.additional_length);
220
221         return;
222 }
223
224 static void mpath_format_reportcapabilities(struct prin_resp *pr_buff)
225 {
226         convert_be16_to_cpu(&pr_buff->prin_descriptor.prin_readcap.length);
227         convert_be16_to_cpu(&pr_buff->prin_descriptor.prin_readcap.pr_type_mask);
228
229         return;
230 }
231
232 static void mpath_format_readfullstatus(struct prin_resp *pr_buff)
233 {
234         int num;
235         uint32_t fdesc_count=0;
236         unsigned char *p;
237         char  *ppbuff;
238         uint32_t additional_length, k, tid_len_len = 0;
239         char tempbuff[MPATH_MAX_PARAM_LEN];
240         struct prin_fulldescr fdesc;
241         static const unsigned int pbuf_size =
242                 sizeof(pr_buff->prin_descriptor.prin_readfd.private_buffer);
243
244         convert_be32_to_cpu(&pr_buff->prin_descriptor.prin_readfd.prgeneration);
245         convert_be32_to_cpu(&pr_buff->prin_descriptor.prin_readfd.number_of_descriptor);
246
247         if (pr_buff->prin_descriptor.prin_readfd.number_of_descriptor == 0)
248         {
249                 condlog(3, "No registration or reservation found.");
250                 return;
251         }
252
253         additional_length = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
254         if (additional_length > pbuf_size) {
255                 condlog(3, "PRIN length %u exceeds max length %d", additional_length,
256                         pbuf_size);
257                 return;
258         }
259
260         memset(&fdesc, 0, sizeof(struct prin_fulldescr));
261
262         memcpy( tempbuff, pr_buff->prin_descriptor.prin_readfd.private_buffer,
263                 pbuf_size);
264         memset(&pr_buff->prin_descriptor.prin_readfd.private_buffer, 0,
265                pbuf_size);
266
267         p =(unsigned char *)tempbuff;
268         ppbuff = (char *)pr_buff->prin_descriptor.prin_readfd.private_buffer;
269
270         for (k = 0; k < additional_length; k += num, p += num) {
271                 memcpy(&fdesc.key, p, 8 );
272                 fdesc.flag = p[12];
273                 fdesc.scope_type =  p[13];
274                 fdesc.rtpi = get_unaligned_be16(&p[18]);
275
276                 tid_len_len = get_unaligned_be32(&p[20]);
277                 if (tid_len_len + 24 + k > additional_length) {
278                         condlog(0,
279                                 "%s: corrupt PRIN response: status descriptor end %d exceeds length %d",
280                                 __func__, tid_len_len + k + 24,
281                                 additional_length);
282                         tid_len_len = additional_length - k - 24;
283                 }
284
285                 if (tid_len_len > 0)
286                         decode_transport_id( &fdesc, &p[24], tid_len_len);
287
288                 num = 24 + tid_len_len;
289                 memcpy(ppbuff, &fdesc, sizeof(struct prin_fulldescr));
290                 pr_buff->prin_descriptor.prin_readfd.descriptors[fdesc_count]= (struct prin_fulldescr *)ppbuff;
291                 ppbuff += sizeof(struct prin_fulldescr);
292                 ++fdesc_count;
293         }
294
295         pr_buff->prin_descriptor.prin_readfd.number_of_descriptor = fdesc_count;
296
297         return;
298 }
299
300 void
301 decode_transport_id(struct prin_fulldescr *fdesc, unsigned char * p, int length)
302 {
303         unsigned int num;
304         int jump, k;
305         for (k = 0, jump = 24; k < length; k += jump, p += jump) {
306                 fdesc->trnptid.format_code = ((p[0] >> 6) & 0x3);
307                 fdesc->trnptid.protocol_id = (p[0] & 0xf);
308                 switch (fdesc->trnptid.protocol_id) {
309                 case MPATH_PROTOCOL_ID_FC:
310                         memcpy(&fdesc->trnptid.n_port_name, &p[8], 8);
311                         jump = 24;
312                         break;
313                 case MPATH_PROTOCOL_ID_ISCSI:
314                         num = get_unaligned_be16(&p[2]);
315                         if (num >= sizeof(fdesc->trnptid.iscsi_name))
316                                 num = sizeof(fdesc->trnptid.iscsi_name);
317                         memcpy(&fdesc->trnptid.iscsi_name, &p[4], num);
318                         jump = (((num + 4) < 24) ? 24 : num + 4);
319                         break;
320                 case MPATH_PROTOCOL_ID_SAS:
321                         memcpy(&fdesc->trnptid.sas_address, &p[4], 8);
322                         jump = 24;
323                         break;
324                 default:
325                         jump = 24;
326                         break;
327                 }
328         }
329 }
330
331 int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int noisy)
332 {
333
334         int ret, status, got, fd;
335         int mx_resp_len;
336         SenseData_t Sensedata;
337         int retry = MAXRETRY;
338         struct sg_io_hdr io_hdr;
339         char devname[FILE_NAME_SIZE];
340         unsigned char cdb[MPATH_PRIN_CMDLEN] =
341         {MPATH_PRIN_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
342
343         snprintf(devname, FILE_NAME_SIZE, "/dev/%s",dev);
344         fd = open(devname, O_RDONLY);
345         if(fd < 0){
346                 condlog(0, "%s: Unable to open device ", dev);
347                 return MPATH_PR_FILE_ERROR;
348         }
349
350         if (mpath_mx_alloc_len)
351                 mx_resp_len = mpath_mx_alloc_len;
352         else
353                 mx_resp_len = get_prin_length(rq_servact);
354
355         if (mx_resp_len == 0) {
356                 status = MPATH_PR_SYNTAX_ERROR;
357                 goto out;
358         }
359
360         cdb[1] = (unsigned char)(rq_servact & 0x1f);
361         cdb[7] = (unsigned char)((mx_resp_len >> 8) & 0xff);
362         cdb[8] = (unsigned char)(mx_resp_len & 0xff);
363
364 retry :
365         memset(&Sensedata, 0, sizeof(SenseData_t));
366         memset(&io_hdr,0 , sizeof( struct sg_io_hdr));
367
368         io_hdr.interface_id = 'S';
369         io_hdr.cmd_len = MPATH_PRIN_CMDLEN;
370         io_hdr.mx_sb_len = sizeof (SenseData_t);
371         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
372         io_hdr.cmdp = cdb;
373         io_hdr.sbp = (void *)&Sensedata;
374         io_hdr.timeout = TIMEOUT;
375
376
377
378         io_hdr.dxfer_len = mx_resp_len;
379         io_hdr.dxferp = (void *)resp;
380
381         ret =ioctl(fd, SG_IO, &io_hdr);
382         if (ret < 0){
383                 condlog(0, "%s: IOCTL failed %d", dev, ret);
384                 status = MPATH_PR_OTHER;
385                 goto out;
386         }
387
388         got = mx_resp_len - io_hdr.resid;
389
390         condlog(3, "%s: duration = %u (ms)", dev, io_hdr.duration);
391         condlog(4, "%s: persistent reservation in: requested %d bytes but got %d bytes)", dev, mx_resp_len, got);
392
393         status = mpath_translate_response(dev, io_hdr, &Sensedata);
394
395         if (status == MPATH_PR_SENSE_UNIT_ATTENTION && (retry > 0))
396         {
397                 --retry;
398                 condlog(3, "%s: retrying for Unit Attention. Remaining retries = %d", dev, retry);
399                 goto retry;
400         }
401
402         if (((status == MPATH_PR_SENSE_NOT_READY )&& (Sensedata.ASC == 0x04)&&
403                                 (Sensedata.ASCQ == 0x07))&& (retry > 0))
404         {
405                 usleep(1000);
406                 --retry;
407                 condlog(3, "%s: retrying for 02/04/07. Remaining retries = %d", dev, retry);
408                 goto retry;
409         }
410
411         if (status != MPATH_PR_SUCCESS)
412                 goto out;
413
414         if (noisy)
415                 dumpHex((const char *)resp, got , 1);
416
417
418         switch (rq_servact)
419         {
420                 case MPATH_PRIN_RKEY_SA :
421                         mpath_format_readkeys(resp);
422                         break;
423                 case MPATH_PRIN_RRES_SA :
424                         mpath_format_readresv(resp);
425                         break;
426                 case MPATH_PRIN_RCAP_SA :
427                         mpath_format_reportcapabilities(resp);
428                         break;
429                 case MPATH_PRIN_RFSTAT_SA :
430                         mpath_format_readfullstatus(resp);
431         }
432
433 out:
434         close(fd);
435         return status;
436 }
437
438 int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr,
439                               SenseData_t *Sensedata)
440 {
441         condlog(3, "%s: status driver:%02x host:%02x scsi:%02x", dev,
442                         io_hdr.driver_status, io_hdr.host_status ,io_hdr.status);
443         io_hdr.status &= 0x7e;
444         if ((0 == io_hdr.status) &&
445             (0 == io_hdr.host_status) &&
446             (0 == io_hdr.driver_status))
447                 return MPATH_PR_SUCCESS;
448
449         switch(io_hdr.status) {
450         case SAM_STAT_GOOD:
451                 break;
452         case SAM_STAT_CHECK_CONDITION:
453                 condlog(3, "%s: Sense_Key=%02x, ASC=%02x ASCQ=%02x",
454                         dev, Sensedata->Sense_Key,
455                         Sensedata->ASC, Sensedata->ASCQ);
456                 switch(Sensedata->Sense_Key) {
457                 case NO_SENSE:
458                         return MPATH_PR_NO_SENSE;
459                 case RECOVERED_ERROR:
460                         return MPATH_PR_SUCCESS;
461                 case NOT_READY:
462                         return MPATH_PR_SENSE_NOT_READY;
463                 case MEDIUM_ERROR:
464                         return MPATH_PR_SENSE_MEDIUM_ERROR;
465                 case BLANK_CHECK:
466                         return MPATH_PR_OTHER;
467                 case HARDWARE_ERROR:
468                         return MPATH_PR_SENSE_HARDWARE_ERROR;
469                 case ILLEGAL_REQUEST:
470                         return MPATH_PR_ILLEGAL_REQ;
471                 case UNIT_ATTENTION:
472                         return MPATH_PR_SENSE_UNIT_ATTENTION;
473                 case DATA_PROTECT:
474                 case COPY_ABORTED:
475                         return MPATH_PR_OTHER;
476                 case ABORTED_COMMAND:
477                         return MPATH_PR_SENSE_ABORTED_COMMAND;
478
479                 default :
480                         return MPATH_PR_OTHER;
481                 }
482         case SAM_STAT_RESERVATION_CONFLICT:
483                 return MPATH_PR_RESERV_CONFLICT;
484
485         default :
486                 return  MPATH_PR_OTHER;
487         }
488
489         switch(io_hdr.host_status) {
490         case DID_OK :
491                 break;
492         default :
493                 return MPATH_PR_OTHER;
494         }
495         switch(io_hdr.driver_status)
496         {
497         case DRIVER_OK:
498                 break;
499         default :
500                 return MPATH_PR_OTHER;
501         }
502         return MPATH_PR_SUCCESS;
503 }
504
505 void convert_be16_to_cpu(uint16_t *num)
506 {
507         *num = get_unaligned_be16(num);
508 }
509
510 void convert_be32_to_cpu(uint32_t *num)
511 {
512         *num = get_unaligned_be32(num);
513 }
514
515 void
516 dumpHex(const char* str, int len, int log)
517 {
518         const char * p = str;
519         unsigned char c;
520         char buff[82];
521         const int bpstart = 5;
522         int bpos = bpstart;
523         int  k;
524
525         if (len <= 0)
526                 return;
527         memset(buff, ' ', 80);
528         buff[80] = '\0';
529         for (k = 0; k < len; k++) {
530                 c = *p++;
531                 bpos += 3;
532                 if (bpos == (bpstart + (9 * 3)))
533                         bpos++;
534                 sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c);
535                 buff[bpos + 2] = ' ';
536                 if ((k > 0) && (0 == ((k + 1) % 16))) {
537                         if (log)
538                                 condlog(0, "%.76s" , buff);
539                         else
540                                 printf("%.76s" , buff);
541                         bpos = bpstart;
542                         memset(buff, ' ', 80);
543                 }
544         }
545         if (bpos > bpstart) {
546                 buff[bpos + 2] = '\0';
547                 if (log)
548                         condlog(0, "%s", buff);
549                 else
550                         printf("%s\n" , buff);
551         }
552         return;
553 }
554
555 int get_prin_length(int rq_servact)
556 {
557         int mx_resp_len;
558         switch (rq_servact)
559         {
560                 case MPATH_PRIN_RKEY_SA:
561                         mx_resp_len =  sizeof(struct prin_readdescr);
562                         break;
563                 case MPATH_PRIN_RRES_SA :
564                         mx_resp_len =  sizeof(struct prin_resvdescr);
565                         break;
566                 case MPATH_PRIN_RCAP_SA :
567                         mx_resp_len = sizeof(struct prin_capdescr);
568                         break;
569                 case MPATH_PRIN_RFSTAT_SA:
570                         mx_resp_len = sizeof(struct print_fulldescr_list) + sizeof(struct prin_fulldescr *)*32;
571                         break;
572                 default:
573                         condlog(0, "invalid service action, %d", rq_servact);
574                         mx_resp_len = 0;
575                         break;
576         }
577         if (mx_resp_len > MPATH_MAX_PARAM_LEN)
578                 mx_resp_len = MPATH_MAX_PARAM_LEN;
579         return mx_resp_len;
580 }