cp: define a FIXME macro that leaves a sclp message
[hvf.git] / cp / drivers / spooldev.c
blob293eda9d3241d1b1afdab8a7805b8581a1390ecc
1 /*
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
5 * details.
6 */
8 #include <dat.h>
9 #include <channel.h>
10 #include <vcpu.h>
11 #include <vdevice.h>
12 #include <spool.h>
13 #include <buddy.h>
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)
22 u64 gaddr, len;
23 int ret;
25 BUG_ON(ccw->flags & (CCW_FLAG_IDA | CCW_FLAG_MIDA));
27 gaddr = ccw->addr; /* the address has already been checked */
28 len = ccw->count;
30 if (!len)
31 return 0;
33 if (gaddr > sys->directory->storage_size) {
34 st->sch_status = SC_PROG_CHK;
35 return 0;
38 if (write)
39 ret = memcpy_from_guest(gaddr, st->iobuf, &len);
40 else
41 ret = memcpy_to_guest(gaddr, st->iobuf, &len);
43 if (ret)
44 st->sch_status = SC_PROT_CHK;
46 st->pos = 0;
47 st->rem = len;
49 return 0;
52 static void __get_ccw(struct virt_sys *sys, struct spdev_state *st, struct ccw *ccw)
54 struct ccw0 rawccw;
55 u64 len;
56 int ret;
58 if ((!st->f && (st->addr & 0xff000000)) || (st->f && (st->addr & 0x80000000)) ||
59 (st->addr & 0x00000007)) {
60 st->sch_status = SC_PROG_CHK;
61 return;
64 len = sizeof(struct ccw);
65 ret = memcpy_from_guest(st->addr, &rawccw, &len);
66 if (ret) {
67 con_printf(sys->con, "failed to fetch ccw %d \n", ret);
68 st->sch_status = SC_PROT_CHK;
69 return;
72 if (!st->f)
73 ccw0_to_ccw1(ccw, &rawccw);
74 else
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
81 * device."
83 int spool_exec(struct virt_sys *sys, struct virt_device *vdev)
85 struct spdev_state st;
86 struct page *pages;
87 struct ccw ccw;
89 int cnt = 0;
91 pages = alloc_pages(4, ZONE_NORMAL); /* get 64k buf */
92 if (!pages) {
93 con_printf(sys->con, "out of memory: could not allocate "
94 "channel buffer (64kB)\n");
95 return -ENOMEM;
98 st.iobuf = page_to_addr(pages);
99 st.dev_status = 0;
100 st.sch_status = 0;
101 st.cd = 0;
102 st.rem = 0;
103 st.pos = 0;
104 st.tic2tic = 0;
106 mutex_lock(&vdev->lock);
107 vdev->scsw.ac &= ~AC_START;
108 vdev->scsw.ac |= AC_SCH_ACT | AC_DEV_ACT;
110 st.f = vdev->orb.f;
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);
119 for(;;) {
120 con_printf(sys->con, "CCW %3d @%08x, ", cnt++, st.addr);
122 /* ORB must contain a valid address */
123 __get_ccw(sys, &st, &ccw);
125 st.addr += 8;
127 if (st.sch_status)
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);
133 /* handle TICs */
134 if (ccw.cmd == CCW_CMD_TIC) {
135 if (st.tic2tic)
136 goto prog_check;
138 if (st.f && (ccw.flags || ccw.count))
139 goto prog_check;
141 /* Note: we'll end up checking the address next interation */
142 st.addr = ccw.addr;
143 st.tic2tic = 1;
144 continue;
147 /* reset the tic-to-tic flag */
148 st.tic2tic = 0;
150 //////////////////////////////////////////////////////
152 /* handle invalid commands */
153 if (!st.cd && ((ccw.cmd & 0x0f) == 0x00))
154 goto prog_check;
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)
162 goto prog_check;
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)
170 goto prog_check;
172 /* The Data address must be valid */
173 if (st.f && (ccw.addr & 0x80000000))
174 goto prog_check;
176 FIXME("");
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 ");
180 goto prog_check;
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))
188 break;
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);
198 else
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))
209 break;
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;
222 out:
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;
235 vdev->scsw.f = st.f;
237 queue_io_interrupt(sys, vdev->sch, vdev->pmcw.interrupt_param, 0,
238 vdev->pmcw.isc);
239 mutex_unlock(&vdev->lock);
241 free_pages(st.iobuf, 4);
243 return 0;
245 prog_check:
246 st.sch_status = SC_PROG_CHK;
247 goto out;