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