Skip to content

Commit 8f933b1

Browse files
Ralf HoppeMartin Schwidefsky
Ralf Hoppe
authored and
Martin Schwidefsky
committed
s390/hmcdrv: HMC drive CD/DVD access
This device driver allows accessing a HMC drive CD/DVD-ROM. It can be used in a LPAR and z/VM environment. Reviewed-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Ralf Hoppe <rhoppe@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
1 parent ea61a57 commit 8f933b1

17 files changed

+1793
-0
lines changed

arch/s390/include/asm/irq.h

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ enum interruption_class {
5151
IRQEXT_CMS,
5252
IRQEXT_CMC,
5353
IRQEXT_CMR,
54+
IRQEXT_FTP,
5455
IRQIO_CIO,
5556
IRQIO_QAI,
5657
IRQIO_DAS,

arch/s390/kernel/irq.c

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ static const struct irq_class irqclass_sub_desc[NR_ARCH_IRQS] = {
7070
{.irq = IRQEXT_CMS, .name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling"},
7171
{.irq = IRQEXT_CMC, .name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"},
7272
{.irq = IRQEXT_CMR, .name = "CMR", .desc = "[EXT] CPU-Measurement: RI"},
73+
{.irq = IRQEXT_FTP, .name = "FTP", .desc = "[EXT] HMC FTP Service"},
7374
{.irq = IRQIO_CIO, .name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"},
7475
{.irq = IRQIO_QAI, .name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"},
7576
{.irq = IRQIO_DAS, .name = "DAS", .desc = "[I/O] DASD"},

drivers/s390/char/Kconfig

+13
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,19 @@ config SCLP_ASYNC
102102
want for inform other people about your kernel panics,
103103
need this feature and intend to run your kernel in LPAR.
104104

105+
config HMC_DRV
106+
def_tristate m
107+
prompt "Support for file transfers from HMC drive CD/DVD-ROM"
108+
depends on 64BIT
109+
select CRC16
110+
help
111+
This option enables support for file transfers from a Hardware
112+
Management Console (HMC) drive CD/DVD-ROM. It is available as a
113+
module, called 'hmcdrv', and also as kernel built-in. There is one
114+
optional parameter for this module: cachesize=N, which modifies the
115+
transfer cache size from it's default value 0.5MB to N bytes. If N
116+
is zero, then no caching is performed.
117+
105118
config S390_TAPE
106119
def_tristate m
107120
prompt "S/390 tape device support"

drivers/s390/char/Makefile

+3
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ obj-$(CONFIG_S390_VMUR) += vmur.o
3333

3434
zcore_mod-objs := sclp_sdias.o zcore.o
3535
obj-$(CONFIG_CRASH_DUMP) += zcore_mod.o
36+
37+
hmcdrv-objs := hmcdrv_mod.o hmcdrv_dev.o hmcdrv_ftp.o hmcdrv_cache.o diag_ftp.o sclp_ftp.o
38+
obj-$(CONFIG_HMC_DRV) += hmcdrv.o

drivers/s390/char/diag_ftp.c

+237
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/*
2+
* DIAGNOSE X'2C4' instruction based HMC FTP services, useable on z/VM
3+
*
4+
* Copyright IBM Corp. 2013
5+
* Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
6+
*
7+
*/
8+
9+
#define KMSG_COMPONENT "hmcdrv"
10+
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11+
12+
#include <linux/kernel.h>
13+
#include <linux/mm.h>
14+
#include <linux/irq.h>
15+
#include <linux/wait.h>
16+
#include <linux/string.h>
17+
#include <asm/ctl_reg.h>
18+
19+
#include "hmcdrv_ftp.h"
20+
#include "diag_ftp.h"
21+
22+
/* DIAGNOSE X'2C4' return codes in Ry */
23+
#define DIAG_FTP_RET_OK 0 /* HMC FTP started successfully */
24+
#define DIAG_FTP_RET_EBUSY 4 /* HMC FTP service currently busy */
25+
#define DIAG_FTP_RET_EIO 8 /* HMC FTP service I/O error */
26+
/* and an artificial extension */
27+
#define DIAG_FTP_RET_EPERM 2 /* HMC FTP service privilege error */
28+
29+
/* FTP service status codes (after INTR at guest real location 133) */
30+
#define DIAG_FTP_STAT_OK 0U /* request completed successfully */
31+
#define DIAG_FTP_STAT_PGCC 4U /* program check condition */
32+
#define DIAG_FTP_STAT_PGIOE 8U /* paging I/O error */
33+
#define DIAG_FTP_STAT_TIMEOUT 12U /* timeout */
34+
#define DIAG_FTP_STAT_EBASE 16U /* base of error codes from SCLP */
35+
#define DIAG_FTP_STAT_LDFAIL (DIAG_FTP_STAT_EBASE + 1U) /* failed */
36+
#define DIAG_FTP_STAT_LDNPERM (DIAG_FTP_STAT_EBASE + 2U) /* not allowed */
37+
#define DIAG_FTP_STAT_LDRUNS (DIAG_FTP_STAT_EBASE + 3U) /* runs */
38+
#define DIAG_FTP_STAT_LDNRUNS (DIAG_FTP_STAT_EBASE + 4U) /* not runs */
39+
40+
/**
41+
* struct diag_ftp_ldfpl - load file FTP parameter list (LDFPL)
42+
* @bufaddr: real buffer address (at 4k boundary)
43+
* @buflen: length of buffer
44+
* @offset: dir/file offset
45+
* @intparm: interruption parameter (unused)
46+
* @transferred: bytes transferred
47+
* @fsize: file size, filled on GET
48+
* @failaddr: failing address
49+
* @spare: padding
50+
* @fident: file name - ASCII
51+
*/
52+
struct diag_ftp_ldfpl {
53+
u64 bufaddr;
54+
u64 buflen;
55+
u64 offset;
56+
u64 intparm;
57+
u64 transferred;
58+
u64 fsize;
59+
u64 failaddr;
60+
u64 spare;
61+
u8 fident[HMCDRV_FTP_FIDENT_MAX];
62+
} __packed;
63+
64+
static DECLARE_COMPLETION(diag_ftp_rx_complete);
65+
static int diag_ftp_subcode;
66+
67+
/**
68+
* diag_ftp_handler() - FTP services IRQ handler
69+
* @extirq: external interrupt (sub-) code
70+
* @param32: 32-bit interruption parameter from &struct diag_ftp_ldfpl
71+
* @param64: unused (for 64-bit interrupt parameters)
72+
*/
73+
static void diag_ftp_handler(struct ext_code extirq,
74+
unsigned int param32,
75+
unsigned long param64)
76+
{
77+
if ((extirq.subcode >> 8) != 8)
78+
return; /* not a FTP services sub-code */
79+
80+
inc_irq_stat(IRQEXT_FTP);
81+
diag_ftp_subcode = extirq.subcode & 0xffU;
82+
complete(&diag_ftp_rx_complete);
83+
}
84+
85+
/**
86+
* diag_ftp_2c4() - DIAGNOSE X'2C4' service call
87+
* @fpl: pointer to prepared LDFPL
88+
* @cmd: FTP command to be executed
89+
*
90+
* Performs a DIAGNOSE X'2C4' call with (input/output) FTP parameter list
91+
* @fpl and FTP function code @cmd. In case of an error the function does
92+
* nothing and returns an (negative) error code.
93+
*
94+
* Notes:
95+
* 1. This function only initiates a transfer, so the caller must wait
96+
* for completion (asynchronous execution).
97+
* 2. The FTP parameter list @fpl must be aligned to a double-word boundary.
98+
* 3. fpl->bufaddr must be a real address, 4k aligned
99+
*/
100+
static int diag_ftp_2c4(struct diag_ftp_ldfpl *fpl,
101+
enum hmcdrv_ftp_cmdid cmd)
102+
{
103+
int rc;
104+
105+
asm volatile(
106+
" diag %[addr],%[cmd],0x2c4\n"
107+
"0: j 2f\n"
108+
"1: la %[rc],%[err]\n"
109+
"2:\n"
110+
EX_TABLE(0b, 1b)
111+
: [rc] "=d" (rc), "+m" (*fpl)
112+
: [cmd] "0" (cmd), [addr] "d" (virt_to_phys(fpl)),
113+
[err] "i" (DIAG_FTP_RET_EPERM)
114+
: "cc");
115+
116+
switch (rc) {
117+
case DIAG_FTP_RET_OK:
118+
return 0;
119+
case DIAG_FTP_RET_EBUSY:
120+
return -EBUSY;
121+
case DIAG_FTP_RET_EPERM:
122+
return -EPERM;
123+
case DIAG_FTP_RET_EIO:
124+
default:
125+
return -EIO;
126+
}
127+
}
128+
129+
/**
130+
* diag_ftp_cmd() - executes a DIAG X'2C4' FTP command, targeting a HMC
131+
* @ftp: pointer to FTP command specification
132+
* @fsize: return of file size (or NULL if undesirable)
133+
*
134+
* Attention: Notice that this function is not reentrant - so the caller
135+
* must ensure locking.
136+
*
137+
* Return: number of bytes read/written or a (negative) error code
138+
*/
139+
ssize_t diag_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize)
140+
{
141+
struct diag_ftp_ldfpl *ldfpl;
142+
ssize_t len;
143+
#ifdef DEBUG
144+
unsigned long start_jiffies;
145+
146+
pr_debug("starting DIAG X'2C4' on '%s', requesting %zd bytes\n",
147+
ftp->fname, ftp->len);
148+
start_jiffies = jiffies;
149+
#endif
150+
init_completion(&diag_ftp_rx_complete);
151+
152+
ldfpl = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
153+
if (!ldfpl) {
154+
len = -ENOMEM;
155+
goto out;
156+
}
157+
158+
len = strlcpy(ldfpl->fident, ftp->fname, sizeof(ldfpl->fident));
159+
if (len >= HMCDRV_FTP_FIDENT_MAX) {
160+
len = -EINVAL;
161+
goto out_free;
162+
}
163+
164+
ldfpl->transferred = 0;
165+
ldfpl->fsize = 0;
166+
ldfpl->offset = ftp->ofs;
167+
ldfpl->buflen = ftp->len;
168+
ldfpl->bufaddr = virt_to_phys(ftp->buf);
169+
170+
len = diag_ftp_2c4(ldfpl, ftp->id);
171+
if (len)
172+
goto out_free;
173+
174+
/*
175+
* There is no way to cancel the running diag X'2C4', the code
176+
* needs to wait unconditionally until the transfer is complete.
177+
*/
178+
wait_for_completion(&diag_ftp_rx_complete);
179+
180+
#ifdef DEBUG
181+
pr_debug("completed DIAG X'2C4' after %lu ms\n",
182+
(jiffies - start_jiffies) * 1000 / HZ);
183+
pr_debug("status of DIAG X'2C4' is %u, with %lld/%lld bytes\n",
184+
diag_ftp_subcode, ldfpl->transferred, ldfpl->fsize);
185+
#endif
186+
187+
switch (diag_ftp_subcode) {
188+
case DIAG_FTP_STAT_OK: /* success */
189+
len = ldfpl->transferred;
190+
if (fsize)
191+
*fsize = ldfpl->fsize;
192+
break;
193+
case DIAG_FTP_STAT_LDNPERM:
194+
len = -EPERM;
195+
break;
196+
case DIAG_FTP_STAT_LDRUNS:
197+
len = -EBUSY;
198+
break;
199+
case DIAG_FTP_STAT_LDFAIL:
200+
len = -ENOENT; /* no such file or media */
201+
break;
202+
default:
203+
len = -EIO;
204+
break;
205+
}
206+
207+
out_free:
208+
free_page((unsigned long) ldfpl);
209+
out:
210+
return len;
211+
}
212+
213+
/**
214+
* diag_ftp_startup() - startup of FTP services, when running on z/VM
215+
*
216+
* Return: 0 on success, else an (negative) error code
217+
*/
218+
int diag_ftp_startup(void)
219+
{
220+
int rc;
221+
222+
rc = register_external_irq(EXT_IRQ_CP_SERVICE, diag_ftp_handler);
223+
if (rc)
224+
return rc;
225+
226+
ctl_set_bit(0, 63 - 22);
227+
return 0;
228+
}
229+
230+
/**
231+
* diag_ftp_shutdown() - shutdown of FTP services, when running on z/VM
232+
*/
233+
void diag_ftp_shutdown(void)
234+
{
235+
ctl_clear_bit(0, 63 - 22);
236+
unregister_external_irq(EXT_IRQ_CP_SERVICE, diag_ftp_handler);
237+
}

drivers/s390/char/diag_ftp.h

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* DIAGNOSE X'2C4' instruction based SE/HMC FTP Services, useable on z/VM
3+
*
4+
* Notice that all functions exported here are not reentrant.
5+
* So usage should be exclusive, ensured by the caller (e.g. using a
6+
* mutex).
7+
*
8+
* Copyright IBM Corp. 2013
9+
* Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
10+
*/
11+
12+
#ifndef __DIAG_FTP_H__
13+
#define __DIAG_FTP_H__
14+
15+
#include "hmcdrv_ftp.h"
16+
17+
int diag_ftp_startup(void);
18+
void diag_ftp_shutdown(void);
19+
ssize_t diag_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize);
20+
21+
#endif /* __DIAG_FTP_H__ */

0 commit comments

Comments
 (0)