18f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe/* 28f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * HMC Drive FTP Services 38f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * 48f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * Copyright IBM Corp. 2013 58f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * Author(s): Ralf Hoppe (rhoppe@de.ibm.com) 68f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe */ 78f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 88f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe#define KMSG_COMPONENT "hmcdrv" 98f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 108f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 118f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe#include <linux/kernel.h> 128f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe#include <linux/slab.h> 138f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe#include <linux/uaccess.h> 148f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe#include <linux/export.h> 158f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 168f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe#include <linux/ctype.h> 178f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe#include <linux/crc16.h> 188f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 198f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe#include "hmcdrv_ftp.h" 208f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe#include "hmcdrv_cache.h" 218f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe#include "sclp_ftp.h" 228f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe#include "diag_ftp.h" 238f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 248f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe/** 258f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * struct hmcdrv_ftp_ops - HMC drive FTP operations 268f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * @startup: startup function 278f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * @shutdown: shutdown function 288f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * @cmd: FTP transfer function 298f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe */ 308f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppestruct hmcdrv_ftp_ops { 318f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe int (*startup)(void); 328f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe void (*shutdown)(void); 338f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ssize_t (*transfer)(const struct hmcdrv_ftp_cmdspec *ftp, 348f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe size_t *fsize); 358f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe}; 368f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 378f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppestatic enum hmcdrv_ftp_cmdid hmcdrv_ftp_cmd_getid(const char *cmd, int len); 388f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppestatic int hmcdrv_ftp_parse(char *cmd, struct hmcdrv_ftp_cmdspec *ftp); 398f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 408f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppestatic struct hmcdrv_ftp_ops *hmcdrv_ftp_funcs; /* current operations */ 418f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppestatic DEFINE_MUTEX(hmcdrv_ftp_mutex); /* mutex for hmcdrv_ftp_funcs */ 428f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppestatic unsigned hmcdrv_ftp_refcnt; /* start/shutdown reference counter */ 438f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 448f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe/** 458f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * hmcdrv_ftp_cmd_getid() - determine FTP command ID from a command string 468f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * @cmd: FTP command string (NOT zero-terminated) 478f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * @len: length of FTP command string in @cmd 488f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe */ 498f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppestatic enum hmcdrv_ftp_cmdid hmcdrv_ftp_cmd_getid(const char *cmd, int len) 508f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe{ 518f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe /* HMC FTP command descriptor */ 528f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe struct hmcdrv_ftp_cmd_desc { 538f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe const char *str; /* command string */ 548f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe enum hmcdrv_ftp_cmdid cmd; /* associated command as enum */ 558f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe }; 568f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 578f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe /* Description of all HMC drive FTP commands 588f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * 598f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * Notes: 608f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * 1. Array size should be a prime number. 618f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * 2. Do not change the order of commands in table (because the 628f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * index is determined by CRC % ARRAY_SIZE). 638f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * 3. Original command 'nlist' was renamed, else the CRC would 648f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * collide with 'append' (see point 2). 658f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe */ 668f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe static const struct hmcdrv_ftp_cmd_desc ftpcmds[7] = { 678f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 688f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe {.str = "get", /* [0] get (CRC = 0x68eb) */ 698f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .cmd = HMCDRV_FTP_GET}, 708f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe {.str = "dir", /* [1] dir (CRC = 0x6a9e) */ 718f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .cmd = HMCDRV_FTP_DIR}, 728f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe {.str = "delete", /* [2] delete (CRC = 0x53ae) */ 738f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .cmd = HMCDRV_FTP_DELETE}, 748f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe {.str = "nls", /* [3] nls (CRC = 0xf87c) */ 758f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .cmd = HMCDRV_FTP_NLIST}, 768f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe {.str = "put", /* [4] put (CRC = 0xac56) */ 778f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .cmd = HMCDRV_FTP_PUT}, 788f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe {.str = "append", /* [5] append (CRC = 0xf56e) */ 798f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .cmd = HMCDRV_FTP_APPEND}, 808f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe {.str = NULL} /* [6] unused */ 818f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe }; 828f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 838f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe const struct hmcdrv_ftp_cmd_desc *pdesc; 848f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 858f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe u16 crc = 0xffffU; 868f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 878f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (len == 0) 888f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe return HMCDRV_FTP_NOOP; /* error indiactor */ 898f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 908f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe crc = crc16(crc, cmd, len); 918f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe pdesc = ftpcmds + (crc % ARRAY_SIZE(ftpcmds)); 928f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe pr_debug("FTP command '%s' has CRC 0x%04x, at table pos. %lu\n", 938f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe cmd, crc, (crc % ARRAY_SIZE(ftpcmds))); 948f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 958f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (!pdesc->str || strncmp(pdesc->str, cmd, len)) 968f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe return HMCDRV_FTP_NOOP; 978f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 988f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe pr_debug("FTP command '%s' found, with ID %d\n", 998f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe pdesc->str, pdesc->cmd); 1008f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1018f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe return pdesc->cmd; 1028f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe} 1038f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1048f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe/** 1058f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * hmcdrv_ftp_parse() - HMC drive FTP command parser 1068f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * @cmd: FTP command string "<cmd> <filename>" 1078f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * @ftp: Pointer to FTP command specification buffer (output) 1088f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * 1098f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * Return: 0 on success, else a (negative) error code 1108f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe */ 1118f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppestatic int hmcdrv_ftp_parse(char *cmd, struct hmcdrv_ftp_cmdspec *ftp) 1128f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe{ 1138f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe char *start; 1148f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe int argc = 0; 1158f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1168f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ftp->id = HMCDRV_FTP_NOOP; 1178f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ftp->fname = NULL; 1188f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1198f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe while (*cmd != '\0') { 1208f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1218f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe while (isspace(*cmd)) 1228f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ++cmd; 1238f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1248f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (*cmd == '\0') 1258f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe break; 1268f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1278f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe start = cmd; 1288f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1298f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe switch (argc) { 1308f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe case 0: /* 1st argument (FTP command) */ 1318f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe while ((*cmd != '\0') && !isspace(*cmd)) 1328f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ++cmd; 1338f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ftp->id = hmcdrv_ftp_cmd_getid(start, cmd - start); 1348f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe break; 1358f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe case 1: /* 2nd / last argument (rest of line) */ 1368f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe while ((*cmd != '\0') && !iscntrl(*cmd)) 1378f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ++cmd; 1388f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ftp->fname = start; 1398f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe /* fall through */ 1408f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe default: 1418f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe *cmd = '\0'; 1428f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe break; 1438f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe } /* switch */ 1448f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1458f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ++argc; 1468f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe } /* while */ 1478f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1488f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (!ftp->fname || (ftp->id == HMCDRV_FTP_NOOP)) 1498f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe return -EINVAL; 1508f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1518f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe return 0; 1528f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe} 1538f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1548f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe/** 1558f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * hmcdrv_ftp_do() - perform a HMC drive FTP, with data from kernel-space 1568f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * @ftp: pointer to FTP command specification 1578f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * 1588f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * Return: number of bytes read/written or a negative error code 1598f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe */ 1608f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppessize_t hmcdrv_ftp_do(const struct hmcdrv_ftp_cmdspec *ftp) 1618f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe{ 1628f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ssize_t len; 1638f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1648f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe mutex_lock(&hmcdrv_ftp_mutex); 1658f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1668f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (hmcdrv_ftp_funcs && hmcdrv_ftp_refcnt) { 1678f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe pr_debug("starting transfer, cmd %d for '%s' at %lld with %zd bytes\n", 1688f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ftp->id, ftp->fname, (long long) ftp->ofs, ftp->len); 1698f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe len = hmcdrv_cache_cmd(ftp, hmcdrv_ftp_funcs->transfer); 1708f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe } else { 1718f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe len = -ENXIO; 1728f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe } 1738f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1748f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe mutex_unlock(&hmcdrv_ftp_mutex); 1758f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe return len; 1768f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe} 1778f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf HoppeEXPORT_SYMBOL(hmcdrv_ftp_do); 1788f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1798f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe/** 1808f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * hmcdrv_ftp_probe() - probe for the HMC drive FTP service 1818f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * 1828f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * Return: 0 if service is available, else an (negative) error code 1838f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe */ 1848f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppeint hmcdrv_ftp_probe(void) 1858f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe{ 1868f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe int rc; 1878f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1888f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe struct hmcdrv_ftp_cmdspec ftp = { 1898f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .id = HMCDRV_FTP_NOOP, 1908f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .ofs = 0, 1918f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .fname = "", 1928f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .len = PAGE_SIZE 1938f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe }; 1948f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1958f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ftp.buf = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); 1968f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 1978f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (!ftp.buf) 1988f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe return -ENOMEM; 1998f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2008f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe rc = hmcdrv_ftp_startup(); 2018f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2028f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (rc) 2038f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe return rc; 2048f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2058f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe rc = hmcdrv_ftp_do(&ftp); 2068f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe free_page((unsigned long) ftp.buf); 2078f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe hmcdrv_ftp_shutdown(); 2088f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2098f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe switch (rc) { 2108f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe case -ENOENT: /* no such file/media or currently busy, */ 2118f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe case -EBUSY: /* but service seems to be available */ 2128f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe rc = 0; 2138f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe break; 2148f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe default: /* leave 'rc' as it is for [0, -EPERM, -E...] */ 2158f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (rc > 0) 2168f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe rc = 0; /* clear length (success) */ 2178f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe break; 2188f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe } /* switch */ 2198f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2208f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe return rc; 2218f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe} 2228f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf HoppeEXPORT_SYMBOL(hmcdrv_ftp_probe); 2238f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2248f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe/** 2258f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * hmcdrv_ftp_cmd() - Perform a HMC drive FTP, with data from user-space 2268f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * 2278f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * @cmd: FTP command string "<cmd> <filename>" 2288f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * @offset: file position to read/write 2298f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * @buf: user-space buffer for read/written directory/file 2308f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * @len: size of @buf (read/dir) or number of bytes to write 2318f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * 2328f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * This function must not be called before hmcdrv_ftp_startup() was called. 2338f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * 2348f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * Return: number of bytes read/written or a negative error code 2358f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe */ 2368f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppessize_t hmcdrv_ftp_cmd(char __kernel *cmd, loff_t offset, 2378f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe char __user *buf, size_t len) 2388f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe{ 2398f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe int order; 2408f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2418f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe struct hmcdrv_ftp_cmdspec ftp = {.len = len, .ofs = offset}; 2428f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ssize_t retlen = hmcdrv_ftp_parse(cmd, &ftp); 2438f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2448f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (retlen) 2458f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe return retlen; 2468f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2478f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe order = get_order(ftp.len); 2488f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ftp.buf = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, order); 2498f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2508f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (!ftp.buf) 2518f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe return -ENOMEM; 2528f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2538f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe switch (ftp.id) { 2548f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe case HMCDRV_FTP_DIR: 2558f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe case HMCDRV_FTP_NLIST: 2568f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe case HMCDRV_FTP_GET: 2578f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe retlen = hmcdrv_ftp_do(&ftp); 2588f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2598f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if ((retlen >= 0) && 2608f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe copy_to_user(buf, ftp.buf, retlen)) 2618f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe retlen = -EFAULT; 2628f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe break; 2638f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2648f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe case HMCDRV_FTP_PUT: 2658f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe case HMCDRV_FTP_APPEND: 2668f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (!copy_from_user(ftp.buf, buf, ftp.len)) 2678f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe retlen = hmcdrv_ftp_do(&ftp); 2688f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe else 2698f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe retlen = -EFAULT; 2708f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe break; 2718f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2728f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe case HMCDRV_FTP_DELETE: 2738f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe retlen = hmcdrv_ftp_do(&ftp); 2748f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe break; 2758f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2768f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe default: 2778f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe retlen = -EOPNOTSUPP; 2788f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe break; 2798f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe } 2808f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2818f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe free_pages((unsigned long) ftp.buf, order); 2828f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe return retlen; 2838f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe} 2848f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2858f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe/** 2868f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * hmcdrv_ftp_startup() - startup of HMC drive FTP functionality for a 2878f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * dedicated (owner) instance 2888f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * 2898f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * Return: 0 on success, else an (negative) error code 2908f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe */ 2918f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppeint hmcdrv_ftp_startup(void) 2928f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe{ 2938f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe static struct hmcdrv_ftp_ops hmcdrv_ftp_zvm = { 2948f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .startup = diag_ftp_startup, 2958f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .shutdown = diag_ftp_shutdown, 2968f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .transfer = diag_ftp_cmd 2978f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe }; 2988f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 2998f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe static struct hmcdrv_ftp_ops hmcdrv_ftp_lpar = { 3008f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .startup = sclp_ftp_startup, 3018f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .shutdown = sclp_ftp_shutdown, 3028f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe .transfer = sclp_ftp_cmd 3038f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe }; 3048f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 3058f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe int rc = 0; 3068f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 3078f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe mutex_lock(&hmcdrv_ftp_mutex); /* block transfers while start-up */ 3088f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 3098f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (hmcdrv_ftp_refcnt == 0) { 3108f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (MACHINE_IS_VM) 3118f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe hmcdrv_ftp_funcs = &hmcdrv_ftp_zvm; 3128f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe else if (MACHINE_IS_LPAR || MACHINE_IS_KVM) 3138f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe hmcdrv_ftp_funcs = &hmcdrv_ftp_lpar; 3148f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe else 3158f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe rc = -EOPNOTSUPP; 3168f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 3178f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (hmcdrv_ftp_funcs) 3188f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe rc = hmcdrv_ftp_funcs->startup(); 3198f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe } 3208f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 3218f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if (!rc) 3228f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe ++hmcdrv_ftp_refcnt; 3238f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 3248f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe mutex_unlock(&hmcdrv_ftp_mutex); 3258f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe return rc; 3268f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe} 3278f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf HoppeEXPORT_SYMBOL(hmcdrv_ftp_startup); 3288f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 3298f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe/** 3308f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * hmcdrv_ftp_shutdown() - shutdown of HMC drive FTP functionality for a 3318f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe * dedicated (owner) instance 3328f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe */ 3338f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppevoid hmcdrv_ftp_shutdown(void) 3348f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe{ 3358f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe mutex_lock(&hmcdrv_ftp_mutex); 3368f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe --hmcdrv_ftp_refcnt; 3378f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 3388f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe if ((hmcdrv_ftp_refcnt == 0) && hmcdrv_ftp_funcs) 3398f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe hmcdrv_ftp_funcs->shutdown(); 3408f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe 3418f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe mutex_unlock(&hmcdrv_ftp_mutex); 3428f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf Hoppe} 3438f933b1043e1e51f4776fc1ffe86752c7785fd4eRalf HoppeEXPORT_SYMBOL(hmcdrv_ftp_shutdown); 344