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