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 struct ccw_device
*ccwdev
;
90 struct zfcp_adapter
*adapter
= NULL
;
92 snprintf(busid
, sizeof(busid
), "0.0.%04x", devno
);
93 ccwdev
= get_ccwdev_by_busid(&zfcp_ccw_driver
, busid
);
97 adapter
= dev_get_drvdata(&ccwdev
->dev
);
101 zfcp_adapter_get(adapter
);
103 put_device(&ccwdev
->dev
);
108 static int zfcp_cfdc_set_fsf(struct zfcp_fsf_cfdc
*fsf_cfdc
, int command
)
111 case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL
:
112 fsf_cfdc
->command
= FSF_QTCB_DOWNLOAD_CONTROL_FILE
;
113 fsf_cfdc
->option
= FSF_CFDC_OPTION_NORMAL_MODE
;
115 case ZFCP_CFDC_CMND_DOWNLOAD_FORCE
:
116 fsf_cfdc
->command
= FSF_QTCB_DOWNLOAD_CONTROL_FILE
;
117 fsf_cfdc
->option
= FSF_CFDC_OPTION_FORCE
;
119 case ZFCP_CFDC_CMND_FULL_ACCESS
:
120 fsf_cfdc
->command
= FSF_QTCB_DOWNLOAD_CONTROL_FILE
;
121 fsf_cfdc
->option
= FSF_CFDC_OPTION_FULL_ACCESS
;
123 case ZFCP_CFDC_CMND_RESTRICTED_ACCESS
:
124 fsf_cfdc
->command
= FSF_QTCB_DOWNLOAD_CONTROL_FILE
;
125 fsf_cfdc
->option
= FSF_CFDC_OPTION_RESTRICTED_ACCESS
;
127 case ZFCP_CFDC_CMND_UPLOAD
:
128 fsf_cfdc
->command
= FSF_QTCB_UPLOAD_CONTROL_FILE
;
129 fsf_cfdc
->option
= 0;
138 static int zfcp_cfdc_sg_setup(int command
, struct scatterlist
*sg
,
139 u8 __user
*control_file
)
142 retval
= zfcp_sg_setup_table(sg
, ZFCP_CFDC_PAGES
);
146 sg
[ZFCP_CFDC_PAGES
- 1].length
= ZFCP_CFDC_MAX_SIZE
% PAGE_SIZE
;
148 if (command
& ZFCP_CFDC_WITH_CONTROL_FILE
&&
149 command
& ZFCP_CFDC_DOWNLOAD
) {
150 retval
= zfcp_cfdc_copy_from_user(sg
, control_file
);
152 zfcp_sg_free_table(sg
, ZFCP_CFDC_PAGES
);
160 static void zfcp_cfdc_req_to_sense(struct zfcp_cfdc_data
*data
,
161 struct zfcp_fsf_req
*req
)
163 data
->fsf_status
= req
->qtcb
->header
.fsf_status
;
164 memcpy(&data
->fsf_status_qual
, &req
->qtcb
->header
.fsf_status_qual
,
165 sizeof(union fsf_status_qual
));
166 memcpy(&data
->payloads
, &req
->qtcb
->bottom
.support
.els
,
167 sizeof(req
->qtcb
->bottom
.support
.els
));
170 static long zfcp_cfdc_dev_ioctl(struct file
*file
, unsigned int command
,
171 unsigned long buffer
)
173 struct zfcp_cfdc_data
*data
;
174 struct zfcp_cfdc_data __user
*data_user
;
175 struct zfcp_adapter
*adapter
;
176 struct zfcp_fsf_req
*req
;
177 struct zfcp_fsf_cfdc
*fsf_cfdc
;
180 if (command
!= ZFCP_CFDC_IOC
)
183 data_user
= (void __user
*) buffer
;
187 fsf_cfdc
= kmalloc(sizeof(struct zfcp_fsf_cfdc
), GFP_KERNEL
);
191 data
= kmalloc(sizeof(struct zfcp_cfdc_data
), GFP_KERNEL
);
197 retval
= copy_from_user(data
, data_user
, sizeof(*data
));
203 if (data
->signature
!= 0xCFDCACDF) {
208 retval
= zfcp_cfdc_set_fsf(fsf_cfdc
, data
->command
);
210 adapter
= zfcp_cfdc_get_adapter(data
->devno
);
215 zfcp_adapter_get(adapter
);
217 retval
= zfcp_cfdc_sg_setup(data
->command
, fsf_cfdc
->sg
,
218 data_user
->control_file
);
221 req
= zfcp_fsf_control_file(adapter
, fsf_cfdc
);
223 retval
= PTR_ERR(req
);
227 if (req
->status
& ZFCP_STATUS_FSFREQ_ERROR
) {
232 zfcp_cfdc_req_to_sense(data
, req
);
233 retval
= copy_to_user(data_user
, data
, sizeof(*data_user
));
239 if (data
->command
& ZFCP_CFDC_UPLOAD
)
240 retval
= zfcp_cfdc_copy_to_user(&data_user
->control_file
,
244 zfcp_fsf_req_free(req
);
246 zfcp_sg_free_table(fsf_cfdc
->sg
, ZFCP_CFDC_PAGES
);
248 zfcp_adapter_put(adapter
);
256 static const struct file_operations zfcp_cfdc_fops
= {
257 .unlocked_ioctl
= zfcp_cfdc_dev_ioctl
,
259 .compat_ioctl
= zfcp_cfdc_dev_ioctl
263 struct miscdevice zfcp_cfdc_misc
= {
264 .minor
= MISC_DYNAMIC_MINOR
,
266 .fops
= &zfcp_cfdc_fops
,