1
2
3
4
5
6
7
8
9#include <linux/module.h>
10#include <linux/init.h>
11
12#include <asm/ccwdev.h>
13#include <asm/cio.h>
14
15#include "cio.h"
16#include "cio_debug.h"
17#include "css.h"
18#include "device.h"
19#include "ioasm.h"
20#include "io_sch.h"
21
22
23
24
25
26static void
27ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
28{
29 struct subchannel *sch = to_subchannel(cdev->dev.parent);
30 char dbf_text[15];
31
32 if (!scsw_is_valid_cstat(&irb->scsw) ||
33 !(scsw_cstat(&irb->scsw) & (SCHN_STAT_CHN_DATA_CHK |
34 SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK)))
35 return;
36 CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check "
37 "received"
38 " ... device %04x on subchannel 0.%x.%04x, dev_stat "
39 ": %02X sch_stat : %02X\n",
40 cdev->private->dev_id.devno, sch->schid.ssid,
41 sch->schid.sch_no,
42 scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw));
43 sprintf(dbf_text, "chk%x", sch->schid.sch_no);
44 CIO_TRACE_EVENT(0, dbf_text);
45 CIO_HEX_EVENT(0, irb, sizeof(struct irb));
46}
47
48
49
50
51static void
52ccw_device_path_notoper(struct ccw_device *cdev)
53{
54 struct subchannel *sch;
55
56 sch = to_subchannel(cdev->dev.parent);
57 if (cio_update_schib(sch))
58 goto doverify;
59
60 CIO_MSG_EVENT(0, "%s(0.%x.%04x) - path(s) %02x are "
61 "not operational \n", __func__,
62 sch->schid.ssid, sch->schid.sch_no,
63 sch->schib.pmcw.pnom);
64
65 sch->lpm &= ~sch->schib.pmcw.pnom;
66doverify:
67 cdev->private->flags.doverify = 1;
68}
69
70
71
72
73static void
74ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
75{
76
77
78
79
80
81 cdev->private->irb.scsw.cmd.ectl = 0;
82 if ((irb->scsw.cmd.stctl & SCSW_STCTL_ALERT_STATUS) &&
83 !(irb->scsw.cmd.stctl & SCSW_STCTL_INTER_STATUS))
84 cdev->private->irb.scsw.cmd.ectl = irb->scsw.cmd.ectl;
85
86 if (!cdev->private->irb.scsw.cmd.ectl)
87 return;
88
89 memcpy (&cdev->private->irb.ecw, irb->ecw, sizeof (irb->ecw));
90}
91
92
93
94
95static int
96ccw_device_accumulate_esw_valid(struct irb *irb)
97{
98 if (!irb->scsw.cmd.eswf &&
99 (irb->scsw.cmd.stctl == SCSW_STCTL_STATUS_PEND))
100 return 0;
101 if (irb->scsw.cmd.stctl ==
102 (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) &&
103 !(irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED))
104 return 0;
105 return 1;
106}
107
108
109
110
111static void
112ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
113{
114 struct irb *cdev_irb;
115 struct sublog *cdev_sublog, *sublog;
116
117 if (!ccw_device_accumulate_esw_valid(irb))
118 return;
119
120 cdev_irb = &cdev->private->irb;
121
122
123 cdev_irb->esw.esw1.lpum = irb->esw.esw1.lpum;
124
125
126 if (irb->scsw.cmd.eswf) {
127 cdev_sublog = &cdev_irb->esw.esw0.sublog;
128 sublog = &irb->esw.esw0.sublog;
129
130 cdev_sublog->esf = sublog->esf;
131
132
133
134
135 if (irb->scsw.cmd.cstat & (SCHN_STAT_CHN_DATA_CHK |
136 SCHN_STAT_CHN_CTRL_CHK |
137 SCHN_STAT_INTF_CTRL_CHK)) {
138
139 cdev_sublog->arep = sublog->arep;
140
141 cdev_sublog->fvf = sublog->fvf;
142
143 cdev_sublog->sacc = sublog->sacc;
144
145 cdev_sublog->termc = sublog->termc;
146
147 cdev_sublog->seqc = sublog->seqc;
148 }
149
150 cdev_sublog->devsc = sublog->devsc;
151
152 cdev_sublog->serr = sublog->serr;
153
154 cdev_sublog->ioerr = sublog->ioerr;
155
156 if (irb->scsw.cmd.cstat & SCHN_STAT_INTF_CTRL_CHK)
157 cdev_irb->esw.esw0.erw.cpt = irb->esw.esw0.erw.cpt;
158
159 cdev_irb->esw.esw0.erw.fsavf = irb->esw.esw0.erw.fsavf;
160 if (cdev_irb->esw.esw0.erw.fsavf) {
161
162 memcpy(cdev_irb->esw.esw0.faddr, irb->esw.esw0.faddr,
163 sizeof (irb->esw.esw0.faddr));
164
165 cdev_irb->esw.esw0.erw.fsaf = irb->esw.esw0.erw.fsaf;
166 }
167
168 cdev_irb->esw.esw0.erw.scavf = irb->esw.esw0.erw.scavf;
169 if (irb->esw.esw0.erw.scavf)
170
171 cdev_irb->esw.esw0.saddr = irb->esw.esw0.saddr;
172
173 }
174
175
176
177 cdev_irb->esw.esw0.erw.auth = irb->esw.esw0.erw.auth;
178
179 cdev_irb->esw.esw0.erw.pvrf = irb->esw.esw0.erw.pvrf;
180 if (irb->esw.esw0.erw.pvrf)
181 cdev->private->flags.doverify = 1;
182
183 cdev_irb->esw.esw0.erw.cons = irb->esw.esw0.erw.cons;
184 if (irb->esw.esw0.erw.cons)
185 cdev_irb->esw.esw0.erw.scnt = irb->esw.esw0.erw.scnt;
186}
187
188
189
190
191void
192ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb)
193{
194 struct irb *cdev_irb;
195
196
197
198
199
200
201 if (!(scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))
202 return;
203
204
205 ccw_device_msg_control_check(cdev, irb);
206
207
208 if (scsw_is_valid_pno(&irb->scsw) && scsw_pno(&irb->scsw))
209 ccw_device_path_notoper(cdev);
210
211 if (scsw_is_tm(&irb->scsw)) {
212 memcpy(&cdev->private->irb, irb, sizeof(struct irb));
213 return;
214 }
215
216
217
218 if (!scsw_is_solicited(&irb->scsw))
219 return;
220
221 cdev_irb = &cdev->private->irb;
222
223
224
225
226
227
228 if (irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC)
229 memset(&cdev->private->irb, 0, sizeof(struct irb));
230
231
232 if (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) {
233
234 cdev_irb->scsw.cmd.key = irb->scsw.cmd.key;
235
236 cdev_irb->scsw.cmd.sctl = irb->scsw.cmd.sctl;
237
238 cdev_irb->scsw.cmd.cc |= irb->scsw.cmd.cc;
239
240 cdev_irb->scsw.cmd.fmt = irb->scsw.cmd.fmt;
241
242 cdev_irb->scsw.cmd.pfch = irb->scsw.cmd.pfch;
243
244 cdev_irb->scsw.cmd.isic = irb->scsw.cmd.isic;
245
246 cdev_irb->scsw.cmd.alcc = irb->scsw.cmd.alcc;
247
248 cdev_irb->scsw.cmd.ssi = irb->scsw.cmd.ssi;
249 }
250
251
252 ccw_device_accumulate_ecw(cdev, irb);
253
254
255 cdev_irb->scsw.cmd.fctl |= irb->scsw.cmd.fctl;
256
257 cdev_irb->scsw.cmd.actl = irb->scsw.cmd.actl;
258
259 cdev_irb->scsw.cmd.stctl |= irb->scsw.cmd.stctl;
260
261
262
263
264 if ((irb->scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) ||
265 ((irb->scsw.cmd.stctl ==
266 (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND)) &&
267 (irb->scsw.cmd.actl & SCSW_ACTL_DEVACT) &&
268 (irb->scsw.cmd.actl & SCSW_ACTL_SCHACT)) ||
269 (irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED))
270 cdev_irb->scsw.cmd.cpa = irb->scsw.cmd.cpa;
271
272 cdev_irb->scsw.cmd.dstat &= ~DEV_STAT_BUSY;
273
274 if (irb->scsw.cmd.stctl &
275 (SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_SEC_STATUS
276 | SCSW_STCTL_INTER_STATUS | SCSW_STCTL_ALERT_STATUS))
277 cdev_irb->scsw.cmd.dstat |= irb->scsw.cmd.dstat;
278
279 cdev_irb->scsw.cmd.cstat |= irb->scsw.cmd.cstat;
280
281 if ((irb->scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) &&
282 (irb->scsw.cmd.cstat & ~(SCHN_STAT_PCI | SCHN_STAT_INCORR_LEN))
283 == 0)
284 cdev_irb->scsw.cmd.count = irb->scsw.cmd.count;
285
286
287 ccw_device_accumulate_esw(cdev, irb);
288
289
290
291
292
293
294
295
296
297
298
299
300
301 if ((cdev_irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
302 !(cdev_irb->esw.esw0.erw.cons))
303 cdev->private->flags.dosense = 1;
304}
305
306
307
308
309int
310ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
311{
312 struct subchannel *sch;
313 struct ccw1 *sense_ccw;
314 int rc;
315
316 sch = to_subchannel(cdev->dev.parent);
317
318
319 if (scsw_actl(&irb->scsw) & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT))
320
321
322
323
324
325
326 return -EBUSY;
327
328
329
330
331 sense_ccw = &to_io_private(sch)->sense_ccw;
332 sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
333 sense_ccw->cda = (__u32) __pa(cdev->private->irb.ecw);
334 sense_ccw->count = SENSE_MAX_COUNT;
335 sense_ccw->flags = CCW_FLAG_SLI;
336
337 rc = cio_start(sch, sense_ccw, 0xff);
338 if (rc == -ENODEV || rc == -EACCES)
339 dev_fsm_event(cdev, DEV_EVENT_VERIFY);
340 return rc;
341}
342
343
344
345
346void
347ccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb)
348{
349
350
351
352
353
354 if (!(scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))
355 return;
356
357
358 ccw_device_msg_control_check(cdev, irb);
359
360
361 if (scsw_is_valid_pno(&irb->scsw) && scsw_pno(&irb->scsw))
362 ccw_device_path_notoper(cdev);
363
364 if (!(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
365 (irb->scsw.cmd.dstat & DEV_STAT_CHN_END)) {
366 cdev->private->irb.esw.esw0.erw.cons = 1;
367 cdev->private->flags.dosense = 0;
368 }
369
370 if (ccw_device_accumulate_esw_valid(irb) &&
371 irb->esw.esw0.erw.pvrf)
372 cdev->private->flags.doverify = 1;
373}
374
375
376
377
378
379int
380ccw_device_accumulate_and_sense(struct ccw_device *cdev, struct irb *irb)
381{
382 ccw_device_accumulate_irb(cdev, irb);
383 if ((irb->scsw.cmd.actl & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0)
384 return -EBUSY;
385
386 if (cdev->private->flags.dosense &&
387 !(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)) {
388 cdev->private->irb.esw.esw0.erw.cons = 1;
389 cdev->private->flags.dosense = 0;
390 return 0;
391 }
392 if (cdev->private->flags.dosense) {
393 ccw_device_do_sense(cdev, irb);
394 return -EBUSY;
395 }
396 return 0;
397}
398
399