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