4 * Userspace interface for accessing the
5 * Access Control Lists / Control File Data Channel
7 * Copyright IBM Corporation 2008, 2009
10 #define KMSG_COMPONENT "zfcp"
11 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
13 #include <linux/types.h>
14 #include <linux/miscdevice.h>
15 #include <asm/ccwdev.h>
20 #define ZFCP_CFDC_CMND_DOWNLOAD_NORMAL 0x00010001
21 #define ZFCP_CFDC_CMND_DOWNLOAD_FORCE 0x00010101
22 #define ZFCP_CFDC_CMND_FULL_ACCESS 0x00000201
23 #define ZFCP_CFDC_CMND_RESTRICTED_ACCESS 0x00000401
24 #define ZFCP_CFDC_CMND_UPLOAD 0x00010002
26 #define ZFCP_CFDC_DOWNLOAD 0x00000001
27 #define ZFCP_CFDC_UPLOAD 0x00000002
28 #define ZFCP_CFDC_WITH_CONTROL_FILE 0x00010000
30 #define ZFCP_CFDC_IOC_MAGIC 0xDD
31 #define ZFCP_CFDC_IOC \
32 _IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_data)
35 * struct zfcp_cfdc_data - data for ioctl cfdc interface
36 * @signature: request signature
37 * @devno: FCP adapter device number
38 * @command: command code
39 * @fsf_status: returns status of FSF command to userspace
40 * @fsf_status_qual: returned to userspace
41 * @payloads: access conflicts list
42 * @control_file: access control table
44 struct zfcp_cfdc_data
{
49 u8 fsf_status_qual
[FSF_STATUS_QUALIFIER_SIZE
];
54 static int zfcp_cfdc_copy_from_user(struct scatterlist
*sg
,
55 void __user
*user_buffer
)
58 unsigned int size
= ZFCP_CFDC_MAX_SIZE
;
61 length
= min((unsigned int)size
, sg
->length
);
62 if (copy_from_user(sg_virt(sg
++), user_buffer
, length
))
64 user_buffer
+= length
;
70 static int zfcp_cfdc_copy_to_user(void __user
*user_buffer
,
71 struct scatterlist
*sg
)
74 unsigned int size
= ZFCP_CFDC_MAX_SIZE
;
77 length
= min((unsigned int) size
, sg
->length
);
78 if (copy_to_user(user_buffer
, sg_virt(sg
++), length
))
80 user_buffer
+= length
;
86 static struct zfcp_adapter
*zfcp_cfdc_get_adapter(u32 devno
)
89 snprintf(busid
, sizeof(busid
), "0.0.%04x", devno
);
90 return zfcp_get_adapter_by_busid(busid
);
93 static int zfcp_cfdc_set_fsf(struct zfcp_fsf_cfdc
*fsf_cfdc
, int command
)
96 case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL
:
97 fsf_cfdc
->command
= FSF_QTCB_DOWNLOAD_CONTROL_FILE
;
98 fsf_cfdc
->option
= FSF_CFDC_OPTION_NORMAL_MODE
;
100 case ZFCP_CFDC_CMND_DOWNLOAD_FORCE
:
101 fsf_cfdc
->command
= FSF_QTCB_DOWNLOAD_CONTROL_FILE
;
102 fsf_cfdc
->option
= FSF_CFDC_OPTION_FORCE
;
104 case ZFCP_CFDC_CMND_FULL_ACCESS
:
105 fsf_cfdc
->command
= FSF_QTCB_DOWNLOAD_CONTROL_FILE
;
106 fsf_cfdc
->option
= FSF_CFDC_OPTION_FULL_ACCESS
;
108 case ZFCP_CFDC_CMND_RESTRICTED_ACCESS
:
109 fsf_cfdc
->command
= FSF_QTCB_DOWNLOAD_CONTROL_FILE
;
110 fsf_cfdc
->option
= FSF_CFDC_OPTION_RESTRICTED_ACCESS
;
112 case ZFCP_CFDC_CMND_UPLOAD
:
113 fsf_cfdc
->command
= FSF_QTCB_UPLOAD_CONTROL_FILE
;
114 fsf_cfdc
->option
= 0;
123 static int zfcp_cfdc_sg_setup(int command
, struct scatterlist
*sg
,
124 u8 __user
*control_file
)
127 retval
= zfcp_sg_setup_table(sg
, ZFCP_CFDC_PAGES
);
131 sg
[ZFCP_CFDC_PAGES
- 1].length
= ZFCP_CFDC_MAX_SIZE
% PAGE_SIZE
;
133 if (command
& ZFCP_CFDC_WITH_CONTROL_FILE
&&
134 command
& ZFCP_CFDC_DOWNLOAD
) {
135 retval
= zfcp_cfdc_copy_from_user(sg
, control_file
);
137 zfcp_sg_free_table(sg
, ZFCP_CFDC_PAGES
);
145 static void zfcp_cfdc_req_to_sense(struct zfcp_cfdc_data
*data
,
146 struct zfcp_fsf_req
*req
)
148 data
->fsf_status
= req
->qtcb
->header
.fsf_status
;
149 memcpy(&data
->fsf_status_qual
, &req
->qtcb
->header
.fsf_status_qual
,
150 sizeof(union fsf_status_qual
));
151 memcpy(&data
->payloads
, &req
->qtcb
->bottom
.support
.els
,
152 sizeof(req
->qtcb
->bottom
.support
.els
));
155 static long zfcp_cfdc_dev_ioctl(struct file
*file
, unsigned int command
,
156 unsigned long buffer
)
158 struct zfcp_cfdc_data
*data
;
159 struct zfcp_cfdc_data __user
*data_user
;
160 struct zfcp_adapter
*adapter
;
161 struct zfcp_fsf_req
*req
;
162 struct zfcp_fsf_cfdc
*fsf_cfdc
;
165 if (command
!= ZFCP_CFDC_IOC
)
168 data_user
= (void __user
*) buffer
;
172 fsf_cfdc
= kmalloc(sizeof(struct zfcp_fsf_cfdc
), GFP_KERNEL
);
176 data
= kmalloc(sizeof(struct zfcp_cfdc_data
), GFP_KERNEL
);
182 retval
= copy_from_user(data
, data_user
, sizeof(*data
));
188 if (data
->signature
!= 0xCFDCACDF) {
193 retval
= zfcp_cfdc_set_fsf(fsf_cfdc
, data
->command
);
195 adapter
= zfcp_cfdc_get_adapter(data
->devno
);
200 zfcp_adapter_get(adapter
);
202 retval
= zfcp_cfdc_sg_setup(data
->command
, fsf_cfdc
->sg
,
203 data_user
->control_file
);
206 req
= zfcp_fsf_control_file(adapter
, fsf_cfdc
);
208 retval
= PTR_ERR(req
);
212 if (req
->status
& ZFCP_STATUS_FSFREQ_ERROR
) {
217 zfcp_cfdc_req_to_sense(data
, req
);
218 retval
= copy_to_user(data_user
, data
, sizeof(*data_user
));
224 if (data
->command
& ZFCP_CFDC_UPLOAD
)
225 retval
= zfcp_cfdc_copy_to_user(&data_user
->control_file
,
229 zfcp_fsf_req_free(req
);
231 zfcp_sg_free_table(fsf_cfdc
->sg
, ZFCP_CFDC_PAGES
);
233 zfcp_adapter_put(adapter
);
241 static const struct file_operations zfcp_cfdc_fops
= {
242 .unlocked_ioctl
= zfcp_cfdc_dev_ioctl
,
244 .compat_ioctl
= zfcp_cfdc_dev_ioctl
248 struct miscdevice zfcp_cfdc_misc
= {
249 .minor
= MISC_DYNAMIC_MINOR
,
251 .fops
= &zfcp_cfdc_fops
,