4cb7ecc910261f8aaa8cd23812b596636e727c83
[multipath-tools/.git] / libmultipath / checkers / libsg.c
1 /*
2  * Copyright (c) 2004, 2005 Christophe Varoqui
3  */
4 #include <string.h>
5 #include <sys/ioctl.h>
6 #include <errno.h>
7 #include <sys/stat.h>
8
9 #include "checkers.h"
10 #include "libsg.h"
11 #include "../libmultipath/sg_include.h"
12
13 int
14 sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff)
15 {
16         /* defaults */
17         int blocks = 1;
18         long long start_block = 0;
19         int bs = 512;
20         int cdbsz = 10;
21         int * diop = NULL;
22
23         unsigned char rdCmd[cdbsz];
24         unsigned char *sbb = senseBuff;
25         struct sg_io_hdr io_hdr;
26         int res;
27         int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88};
28         int sz_ind;
29         struct stat filestatus;
30         int retry_count = 3;
31
32         if (fstat(sg_fd, &filestatus) != 0)
33                 return PATH_DOWN;
34         bs = (filestatus.st_blksize > 4096)? 4096: filestatus.st_blksize;
35         memset(rdCmd, 0, cdbsz);
36         sz_ind = 1;
37         rdCmd[0] = rd_opcode[sz_ind];
38         rdCmd[2] = (unsigned char)((start_block >> 24) & 0xff);
39         rdCmd[3] = (unsigned char)((start_block >> 16) & 0xff);
40         rdCmd[4] = (unsigned char)((start_block >> 8) & 0xff);
41         rdCmd[5] = (unsigned char)(start_block & 0xff);
42         rdCmd[7] = (unsigned char)((blocks >> 8) & 0xff);
43         rdCmd[8] = (unsigned char)(blocks & 0xff);
44
45         memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
46         io_hdr.interface_id = 'S';
47         io_hdr.cmd_len = cdbsz;
48         io_hdr.cmdp = rdCmd;
49         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
50         io_hdr.dxfer_len = bs * blocks;
51         io_hdr.dxferp = buff;
52         io_hdr.mx_sb_len = SENSE_BUFF_LEN;
53         io_hdr.sbp = senseBuff;
54         io_hdr.timeout = DEF_TIMEOUT;
55         io_hdr.pack_id = (int)start_block;
56         if (diop && *diop)
57         io_hdr.flags |= SG_FLAG_DIRECT_IO;
58
59 retry: 
60         memset(senseBuff, 0, SENSE_BUFF_LEN);
61         while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno));
62
63         if (res < 0) {
64                 if (ENOMEM == errno) {
65                         return PATH_UP;
66                 }
67                 return PATH_DOWN;
68         }
69
70         if ((0 == io_hdr.status) &&
71             (0 == io_hdr.host_status) &&
72             (0 == io_hdr.driver_status)) {
73                 return PATH_UP;
74         } else {
75                 int key = 0;
76
77                 if (io_hdr.sb_len_wr > 3) {
78                         if (sbb[0] == 0x72 || sbb[0] == 0x73)
79                                 key = sbb[1] & 0x0f;
80                         else if (io_hdr.sb_len_wr > 13 &&
81                                  ((sbb[0] & 0x7f) == 0x70 ||
82                                   (sbb[0] & 0x7f) == 0x71))
83                                 key = sbb[2] & 0x0f;
84                 }
85
86                 /*
87                  * Retry if UNIT_ATTENTION check condition.
88                  */
89                 if (key == 0x6) {
90                         if (--retry_count)
91                                 goto retry;
92                 }
93                 return PATH_DOWN;
94         }
95 }