2 * (C) Copyright 2007-2011 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * This file is released under the GPLv2. See the COPYING file for more
16 * store == 0: iobuf -> storage
17 * store == 1: storage -> iobuf
19 static int __xfer_storage(struct virt_sys
*sys
, struct virt_device
*vdev
,
20 struct spdev_state
*st
, struct ccw
*ccw
, int write
)
25 BUG_ON(ccw
->flags
& (CCW_FLAG_IDA
| CCW_FLAG_MIDA
));
27 gaddr
= ccw
->addr
; /* the address has already been checked */
33 if (gaddr
> sys
->directory
->storage_size
) {
34 st
->sch_status
= SC_PROG_CHK
;
39 ret
= memcpy_from_guest(gaddr
, st
->iobuf
, &len
);
41 ret
= memcpy_to_guest(gaddr
, st
->iobuf
, &len
);
44 st
->sch_status
= SC_PROT_CHK
;
52 static void __get_ccw(struct virt_sys
*sys
, struct spdev_state
*st
, struct ccw
*ccw
)
58 if ((!st
->f
&& (st
->addr
& 0xff000000)) || (st
->f
&& (st
->addr
& 0x80000000)) ||
59 (st
->addr
& 0x00000007)) {
60 st
->sch_status
= SC_PROG_CHK
;
64 len
= sizeof(struct ccw
);
65 ret
= memcpy_from_guest(st
->addr
, &rawccw
, &len
);
67 con_printf(sys
->con
, "failed to fetch ccw %d \n", ret
);
68 st
->sch_status
= SC_PROT_CHK
;
73 ccw0_to_ccw1(ccw
, &rawccw
);
75 memcpy(ccw
, &rawccw
, sizeof(struct ccw
));
79 * This fuction behaves as a control unit as described in the principles of
80 * operation. It uses a function pointer to "send the command to the
83 int spool_exec(struct virt_sys
*sys
, struct virt_device
*vdev
)
85 struct spdev_state st
;
91 pages
= alloc_pages(4, ZONE_NORMAL
); /* get 64k buf */
93 con_printf(sys
->con
, "out of memory: could not allocate "
94 "channel buffer (64kB)\n");
98 st
.iobuf
= page_to_addr(pages
);
106 mutex_lock(&vdev
->lock
);
107 vdev
->scsw
.ac
&= ~AC_START
;
108 vdev
->scsw
.ac
|= AC_SCH_ACT
| AC_DEV_ACT
;
111 st
.addr
= vdev
->orb
.addr
;
112 st
.ops
= vdev
->u
.spool
.ops
;
114 mutex_unlock(&vdev
->lock
);
116 con_printf(sys
->con
, "spool_exec for %04x (%08x), format-%d\n",
117 vdev
->pmcw
.dev_num
, vdev
->sch
, st
.f
);
120 con_printf(sys
->con
, "CCW %3d @%08x, ", cnt
++, st
.addr
);
122 /* ORB must contain a valid address */
123 __get_ccw(sys
, &st
, &ccw
);
128 goto out
; /* in case __get_ccw failed */
130 con_printf(sys
->con
, "%02x %02x %04x %08x ",
131 ccw
.cmd
, ccw
.flags
, ccw
.count
, ccw
.addr
);
134 if (ccw
.cmd
== CCW_CMD_TIC
) {
138 if (st
.f
&& (ccw
.flags
|| ccw
.count
))
141 /* Note: we'll end up checking the address next interation */
147 /* reset the tic-to-tic flag */
150 //////////////////////////////////////////////////////
152 /* handle invalid commands */
153 if (!st
.cd
&& ((ccw
.cmd
& 0x0f) == 0x00))
157 * Invalid Count, Format 0: A CCW, which is other
158 * than a CCW specifying transfer in channel, contains
159 * zeros in bit positions 48-63.
161 if (!st
.f
&& !ccw
.count
)
165 * Invalid Count, Format 1: A CCW that specifies
166 * data chaining or a CCW fetched while data chaining
167 * contains zeros in bit positions 16-31.
169 if (st
.f
&& st
.cd
&& !ccw
.count
)
172 /* The Data address must be valid */
173 if (st
.f
&& (ccw
.addr
& 0x80000000))
177 if (ccw
.flags
& (CCW_FLAG_SKP
| CCW_FLAG_PCI
| CCW_FLAG_IDA
|
178 CCW_FLAG_S
| CCW_FLAG_MIDA
| CCW_FLAG_CD
)) {
179 con_printf(sys
->con
, "unsupported ccw flag ");
184 * Write operations need to get data from storage
186 if (IS_CCW_WRITE(ccw
.cmd
)) {
187 if (__xfer_storage(sys
, vdev
, &st
, &ccw
, 1))
192 * Great! The channel decoded the CCW properly, now it's
193 * time to tell the device to execute the operation.
196 if (st
.ops
&& st
.ops
->f
[ccw
.cmd
& 0xf])
197 st
.ops
->f
[ccw
.cmd
& 0xf](sys
, vdev
, &ccw
, &st
);
199 spooldev_cmdrej(sys
, vdev
, &st
);
201 if (st
.dev_status
!= (SC_STATUS_CE
| SC_STATUS_DE
))
202 break; /* command failed, stop chanining */
205 * Read operations need to get data to storage
207 if (IS_CCW_READ(ccw
.cmd
)) {
208 if (__xfer_storage(sys
, vdev
, &st
, &ccw
, 0))
212 con_printf(sys
->con
, "OK\n");
214 if ((ccw
.flags
& (CCW_FLAG_CD
| CCW_FLAG_CC
)) == 0)
215 break; /* end of chain */
217 st
.cd
= (ccw
.flags
& CCW_FLAG_CD
) != 0;
219 st
.addr
= (st
.addr
+ 8) & 0x7fffffff;
223 mutex_lock(&vdev
->lock
);
224 vdev
->scsw
.ac
&= ~(AC_SCH_ACT
| AC_DEV_ACT
);
225 vdev
->scsw
.sc
|= SC_PRIMARY
| SC_SECONDARY
| SC_STATUS
;
226 if (st
.sch_status
|| (st
.dev_status
!= (SC_STATUS_CE
| SC_STATUS_DE
))) {
227 con_printf(sys
->con
, "FAILED\n");
228 vdev
->scsw
.sc
|= SC_ALERT
;
231 vdev
->scsw
.dev_status
= st
.dev_status
;
232 vdev
->scsw
.sch_status
= st
.sch_status
;
233 vdev
->scsw
.addr
= st
.addr
;
234 vdev
->scsw
.count
= st
.rem
;
237 queue_io_interrupt(sys
, vdev
->sch
, vdev
->pmcw
.interrupt_param
, 0,
239 mutex_unlock(&vdev
->lock
);
241 free_pages(st
.iobuf
, 4);
246 st
.sch_status
= SC_PROG_CHK
;