linux/drivers/s390/scsi/zfcp_cfdc.c
<<
>>
Prefs
   1/*
   2 * zfcp device driver
   3 *
   4 * Userspace interface for accessing the
   5 * Access Control Lists / Control File Data Channel
   6 *
   7 * Copyright IBM Corporation 2008, 2009
   8 */
   9
  10#define KMSG_COMPONENT "zfcp"
  11#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  12
  13#include <linux/types.h>
  14#include <linux/miscdevice.h>
  15#include <asm/ccwdev.h>
  16#include "zfcp_def.h"
  17#include "zfcp_ext.h"
  18#include "zfcp_fsf.h"
  19
  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
  25
  26#define ZFCP_CFDC_DOWNLOAD                      0x00000001
  27#define ZFCP_CFDC_UPLOAD                        0x00000002
  28#define ZFCP_CFDC_WITH_CONTROL_FILE             0x00010000
  29
  30#define ZFCP_CFDC_IOC_MAGIC                     0xDD
  31#define ZFCP_CFDC_IOC \
  32        _IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_data)
  33
  34/**
  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
  43 */
  44struct zfcp_cfdc_data {
  45        u32 signature;
  46        u32 devno;
  47        u32 command;
  48        u32 fsf_status;
  49        u8  fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
  50        u8  payloads[256];
  51        u8  control_file[0];
  52};
  53
  54static int zfcp_cfdc_copy_from_user(struct scatterlist *sg,
  55                                    void __user *user_buffer)
  56{
  57        unsigned int length;
  58        unsigned int size = ZFCP_CFDC_MAX_SIZE;
  59
  60        while (size) {
  61                length = min((unsigned int)size, sg->length);
  62                if (copy_from_user(sg_virt(sg++), user_buffer, length))
  63                        return -EFAULT;
  64                user_buffer += length;
  65                size -= length;
  66        }
  67        return 0;
  68}
  69
  70static int zfcp_cfdc_copy_to_user(void __user  *user_buffer,
  71                                  struct scatterlist *sg)
  72{
  73        unsigned int length;
  74        unsigned int size = ZFCP_CFDC_MAX_SIZE;
  75
  76        while (size) {
  77                length = min((unsigned int) size, sg->length);
  78                if (copy_to_user(user_buffer, sg_virt(sg++), length))
  79                        return -EFAULT;
  80                user_buffer += length;
  81                size -= length;
  82        }
  83        return 0;
  84}
  85
  86static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno)
  87{
  88        char busid[9];
  89        snprintf(busid, sizeof(busid), "0.0.%04x", devno);
  90        return zfcp_get_adapter_by_busid(busid);
  91}
  92
  93static int zfcp_cfdc_set_fsf(struct zfcp_fsf_cfdc *fsf_cfdc, int command)
  94{
  95        switch (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;
  99                break;
 100        case ZFCP_CFDC_CMND_DOWNLOAD_FORCE:
 101                fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE;
 102                fsf_cfdc->option = FSF_CFDC_OPTION_FORCE;
 103                break;
 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;
 107                break;
 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;
 111                break;
 112        case ZFCP_CFDC_CMND_UPLOAD:
 113                fsf_cfdc->command = FSF_QTCB_UPLOAD_CONTROL_FILE;
 114                fsf_cfdc->option = 0;
 115                break;
 116        default:
 117                return -EINVAL;
 118        }
 119
 120        return 0;
 121}
 122
 123static int zfcp_cfdc_sg_setup(int command, struct scatterlist *sg,
 124                              u8 __user *control_file)
 125{
 126        int retval;
 127        retval = zfcp_sg_setup_table(sg, ZFCP_CFDC_PAGES);
 128        if (retval)
 129                return retval;
 130
 131        sg[ZFCP_CFDC_PAGES - 1].length = ZFCP_CFDC_MAX_SIZE % PAGE_SIZE;
 132
 133        if (command & ZFCP_CFDC_WITH_CONTROL_FILE &&
 134            command & ZFCP_CFDC_DOWNLOAD) {
 135                retval = zfcp_cfdc_copy_from_user(sg, control_file);
 136                if (retval) {
 137                        zfcp_sg_free_table(sg, ZFCP_CFDC_PAGES);
 138                        return -EFAULT;
 139                }
 140        }
 141
 142        return 0;
 143}
 144
 145static void zfcp_cfdc_req_to_sense(struct zfcp_cfdc_data *data,
 146                                   struct zfcp_fsf_req *req)
 147{
 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));
 153}
 154
 155static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
 156                                unsigned long buffer)
 157{
 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;
 163        int retval;
 164
 165        if (command != ZFCP_CFDC_IOC)
 166                return -ENOTTY;
 167
 168        data_user = (void __user *) buffer;
 169        if (!data_user)
 170                return -EINVAL;
 171
 172        fsf_cfdc = kmalloc(sizeof(struct zfcp_fsf_cfdc), GFP_KERNEL);
 173        if (!fsf_cfdc)
 174                return -ENOMEM;
 175
 176        data = kmalloc(sizeof(struct zfcp_cfdc_data), GFP_KERNEL);
 177        if (!data) {
 178                retval = -ENOMEM;
 179                goto no_mem_sense;
 180        }
 181
 182        retval = copy_from_user(data, data_user, sizeof(*data));
 183        if (retval) {
 184                retval = -EFAULT;
 185                goto free_buffer;
 186        }
 187
 188        if (data->signature != 0xCFDCACDF) {
 189                retval = -EINVAL;
 190                goto free_buffer;
 191        }
 192
 193        retval = zfcp_cfdc_set_fsf(fsf_cfdc, data->command);
 194
 195        adapter = zfcp_cfdc_get_adapter(data->devno);
 196        if (!adapter) {
 197                retval = -ENXIO;
 198                goto free_buffer;
 199        }
 200        zfcp_adapter_get(adapter);
 201
 202        retval = zfcp_cfdc_sg_setup(data->command, fsf_cfdc->sg,
 203                                    data_user->control_file);
 204        if (retval)
 205                goto adapter_put;
 206        req = zfcp_fsf_control_file(adapter, fsf_cfdc);
 207        if (IS_ERR(req)) {
 208                retval = PTR_ERR(req);
 209                goto free_sg;
 210        }
 211
 212        if (req->status & ZFCP_STATUS_FSFREQ_ERROR) {
 213                retval = -ENXIO;
 214                goto free_fsf;
 215        }
 216
 217        zfcp_cfdc_req_to_sense(data, req);
 218        retval = copy_to_user(data_user, data, sizeof(*data_user));
 219        if (retval) {
 220                retval = -EFAULT;
 221                goto free_fsf;
 222        }
 223
 224        if (data->command & ZFCP_CFDC_UPLOAD)
 225                retval = zfcp_cfdc_copy_to_user(&data_user->control_file,
 226                                                fsf_cfdc->sg);
 227
 228 free_fsf:
 229        zfcp_fsf_req_free(req);
 230 free_sg:
 231        zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES);
 232 adapter_put:
 233        zfcp_adapter_put(adapter);
 234 free_buffer:
 235        kfree(data);
 236 no_mem_sense:
 237        kfree(fsf_cfdc);
 238        return retval;
 239}
 240
 241static const struct file_operations zfcp_cfdc_fops = {
 242        .unlocked_ioctl = zfcp_cfdc_dev_ioctl,
 243#ifdef CONFIG_COMPAT
 244        .compat_ioctl = zfcp_cfdc_dev_ioctl
 245#endif
 246};
 247
 248struct miscdevice zfcp_cfdc_misc = {
 249        .minor = MISC_DYNAMIC_MINOR,
 250        .name = "zfcp_cfdc",
 251        .fops = &zfcp_cfdc_fops,
 252};
 253