Deleted Added
full compact
vpo.c (35210) vpo.c (38061)
1/*-
1/*-
2 * Copyright (c) 1997 Nicolas Souchu
2 * Copyright (c) 1997, 1998 Nicolas Souchu
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright

--- 28 unchanged lines hidden (view full) ---

39#include <scsi/scsi_disk.h>
40#include <scsi/scsiconf.h>
41
42#ifdef KERNEL
43#include <sys/kernel.h>
44#endif /*KERNEL */
45
46#include <dev/ppbus/ppbconf.h>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright

--- 28 unchanged lines hidden (view full) ---

39#include <scsi/scsi_disk.h>
40#include <scsi/scsiconf.h>
41
42#ifdef KERNEL
43#include <sys/kernel.h>
44#endif /*KERNEL */
45
46#include <dev/ppbus/ppbconf.h>
47#include
47#include <dev/ppbus/vpoio.h>
48
48
49/* --------------------------------------------------------------------
50 * HERE ARE THINGS YOU MAY HAVE/WANT TO CHANGE
51 */
49#define VP0_BUFFER_SIZE 0x12000
52
50
53/*
54 * XXX
55 * We may add a timeout queue to avoid active polling on nACK.
56 */
57#define VP0_SELTMO 5000 /* select timeout */
58#define VP0_FAST_SPINTMO 500000 /* wait status timeout */
59#define VP0_LOW_SPINTMO 5000000 /* wait status timeout */
51struct vpo_sense {
52 struct scsi_sense cmd;
53 unsigned int stat;
54 unsigned int count;
55};
60
56
61/*
62 * DO NOT MODIFY ANYTHING UNDER THIS LINE
63 * --------------------------------------------------------------------
64 */
57struct vpo_data {
58 unsigned short vpo_unit;
65
59
66static __inline int vpoio_do_scsi(struct vpo_data *, int, int, char *, int,
67 char *, int, int *, int *);
60 int vpo_stat;
61 int vpo_count;
62 int vpo_error;
68
63
64 struct ppb_status vpo_status;
65 struct vpo_sense vpo_sense;
66
67 unsigned char vpo_buffer[VP0_BUFFER_SIZE];
68
69 struct vpoio_data vpo_io; /* interface to low level functions */
70
71 struct scsi_link sc_link;
72};
73
74
69static int32_t vpo_scsi_cmd(struct scsi_xfer *);
70static void vpominphys(struct buf *);
71static u_int32_t vpo_adapter_info(int);
72
75static int32_t vpo_scsi_cmd(struct scsi_xfer *);
76static void vpominphys(struct buf *);
77static u_int32_t vpo_adapter_info(int);
78
73static int vpo_detect(struct vpo_data *vpo);
74
75static int nvpo = 0;
76#define MAXVP0 8 /* XXX not much better! */
77static struct vpo_data *vpodata[MAXVP0];
78
79static int nvpo = 0;
80#define MAXVP0 8 /* XXX not much better! */
81static struct vpo_data *vpodata[MAXVP0];
82
79#ifdef KERNEL
80static struct scsi_adapter vpo_switch =
81{
82 vpo_scsi_cmd,
83 vpominphys,
84 0,
85 0,
86 vpo_adapter_info,
87 "vpo",

--- 24 unchanged lines hidden (view full) ---

112static int vpoattach(struct ppb_device *dev);
113
114static struct ppb_driver vpodriver = {
115 vpoprobe, vpoattach, "vpo"
116};
117DATA_SET(ppbdriver_set, vpodriver);
118
119
83static struct scsi_adapter vpo_switch =
84{
85 vpo_scsi_cmd,
86 vpominphys,
87 0,
88 0,
89 vpo_adapter_info,
90 "vpo",

--- 24 unchanged lines hidden (view full) ---

115static int vpoattach(struct ppb_device *dev);
116
117static struct ppb_driver vpodriver = {
118 vpoprobe, vpoattach, "vpo"
119};
120DATA_SET(ppbdriver_set, vpodriver);
121
122
120#endif /* KERNEL */
121
122static u_int32_t
123vpo_adapter_info(int unit)
124{
125
126 return 1;
127}
128
129/*
130 * vpoprobe()
131 *
132 * Called by ppb_attachdevs().
133 */
134static struct ppb_device *
135vpoprobe(struct ppb_data *ppb)
136{
123static u_int32_t
124vpo_adapter_info(int unit)
125{
126
127 return 1;
128}
129
130/*
131 * vpoprobe()
132 *
133 * Called by ppb_attachdevs().
134 */
135static struct ppb_device *
136vpoprobe(struct ppb_data *ppb)
137{
137
138 struct vpo_data *vpo;
138 struct vpo_data *vpo;
139 struct ppb_device *dev;
139
140 if (nvpo >= MAXVP0) {
141 printf("vpo: Too many devices (max %d)\n", MAXVP0);
142 return(NULL);
143 }
144
145 vpo = (struct vpo_data *)malloc(sizeof(struct vpo_data),
146 M_DEVBUF, M_NOWAIT);
147 if (!vpo) {
148 printf("vpo: cannot malloc!\n");
149 return(NULL);
150 }
151 bzero(vpo, sizeof(struct vpo_data));
152
153 vpodata[nvpo] = vpo;
154
155 /* vpo dependent initialisation */
156 vpo->vpo_unit = nvpo;
157
140
141 if (nvpo >= MAXVP0) {
142 printf("vpo: Too many devices (max %d)\n", MAXVP0);
143 return(NULL);
144 }
145
146 vpo = (struct vpo_data *)malloc(sizeof(struct vpo_data),
147 M_DEVBUF, M_NOWAIT);
148 if (!vpo) {
149 printf("vpo: cannot malloc!\n");
150 return(NULL);
151 }
152 bzero(vpo, sizeof(struct vpo_data));
153
154 vpodata[nvpo] = vpo;
155
156 /* vpo dependent initialisation */
157 vpo->vpo_unit = nvpo;
158
158 /* ppbus dependent initialisation */
159 vpo->vpo_dev.id_unit = vpo->vpo_unit;
160 vpo->vpo_dev.ppb = ppb;
159 /* ok, go to next device on next probe */
160 nvpo ++;
161
161
162 /* now, try to initialise the drive */
163 if (vpo_detect(vpo)) {
162 /* low level probe */
163 vpoio_set_unit(&vpo->vpo_io, vpo->vpo_unit);
164
165 if (!(dev = vpoio_probe(ppb, &vpo->vpo_io))) {
164 free(vpo, M_DEVBUF);
165 return (NULL);
166 }
167
166 free(vpo, M_DEVBUF);
167 return (NULL);
168 }
169
168 /* ok, go to next device on next probe */
169 nvpo ++;
170
171 return (&vpo->vpo_dev);
170 return (dev);
172}
173
174/*
175 * vpoattach()
176 *
177 * Called by ppb_attachdevs().
178 */
179static int
180vpoattach(struct ppb_device *dev)
181{
182
183 struct scsibus_data *scbus;
184 struct vpo_data *vpo = vpodata[dev->id_unit];
185
171}
172
173/*
174 * vpoattach()
175 *
176 * Called by ppb_attachdevs().
177 */
178static int
179vpoattach(struct ppb_device *dev)
180{
181
182 struct scsibus_data *scbus;
183 struct vpo_data *vpo = vpodata[dev->id_unit];
184
185 /* low level attachment */
186 if (!vpoio_attach(&vpo->vpo_io))
187 return (0);
188
186 vpo->sc_link.adapter_unit = vpo->vpo_unit;
187 vpo->sc_link.adapter_targ = VP0_INITIATOR;
188 vpo->sc_link.adapter = &vpo_switch;
189 vpo->sc_link.device = &vpo_dev;
190 vpo->sc_link.opennings = VP0_OPENNINGS;
191
192 /*
189 vpo->sc_link.adapter_unit = vpo->vpo_unit;
190 vpo->sc_link.adapter_targ = VP0_INITIATOR;
191 vpo->sc_link.adapter = &vpo_switch;
192 vpo->sc_link.device = &vpo_dev;
193 vpo->sc_link.opennings = VP0_OPENNINGS;
194
195 /*
193 * Report ourselves
194 */
195 printf("vpo%d: <Adaptec aic7110 scsi> on ppbus %d\n",
196 dev->id_unit, dev->ppb->ppb_link->adapter_unit);
197
198 /*
199 * Prepare the scsibus_data area for the upperlevel
200 * scsi code.
201 */
202 scbus = scsi_alloc_bus();
203 if(!scbus)
204 return (0);
205 scbus->adapter_link = &vpo->sc_link;
206
196 * Prepare the scsibus_data area for the upperlevel
197 * scsi code.
198 */
199 scbus = scsi_alloc_bus();
200 if(!scbus)
201 return (0);
202 scbus->adapter_link = &vpo->sc_link;
203
204 /* all went ok */
205 printf("vpo%d: <Iomega PPA-3/VPI0 SCSI controller>\n", dev->id_unit);
206
207 scsi_attachdevs(scbus);
208
209 return (1);
210}
211
212static void
213vpominphys(struct buf *bp)
214{
215
216 if (bp->b_bcount > VP0_BUFFER_SIZE)
217 bp->b_bcount = VP0_BUFFER_SIZE;
218
219 return;
220}
221
207 scsi_attachdevs(scbus);
208
209 return (1);
210}
211
212static void
213vpominphys(struct buf *bp)
214{
215
216 if (bp->b_bcount > VP0_BUFFER_SIZE)
217 bp->b_bcount = VP0_BUFFER_SIZE;
218
219 return;
220}
221
222#ifdef VP0_WARNING
223static __inline void
224vpo_warning(struct vpo_data *vpo, struct scsi_xfer *xs, int timeout)
225{
226
227 switch (timeout) {
228 case 0:
229 case VP0_ESELECT_TIMEOUT:
230 /* log(LOG_WARNING,
231 "vpo%d: select timeout\n", vpo->vpo_unit); */
232 break;
233 case VP0_EDISCONNECT:
234 log(LOG_WARNING,
235 "vpo%d: can't get printer state\n", vpo->vpo_unit);
236 break;
237 case VP0_ECONNECT:
238 log(LOG_WARNING,
239 "vpo%d: can't get disk state\n", vpo->vpo_unit);
240 break;
241 case VP0_ECMD_TIMEOUT:
242 log(LOG_WARNING,
243 "vpo%d: command timeout\n", vpo->vpo_unit);
244 break;
245 case VP0_EPPDATA_TIMEOUT:
246 log(LOG_WARNING,
247 "vpo%d: EPP data timeout\n", vpo->vpo_unit);
248 break;
249 case VP0_ESTATUS_TIMEOUT:
250 log(LOG_WARNING,
251 "vpo%d: status timeout\n", vpo->vpo_unit);
252 break;
253 case VP0_EDATA_OVERFLOW:
254 log(LOG_WARNING,
255 "vpo%d: data overflow\n", vpo->vpo_unit);
256 break;
257 case VP0_EINTR:
258 log(LOG_WARNING,
259 "vpo%d: ppb request interrupted\n", vpo->vpo_unit);
260 break;
261 default:
262 log(LOG_WARNING,
263 "vpo%d: timeout = %d\n", vpo->vpo_unit, timeout);
264 break;
265 }
266}
267#endif /* VP0_WARNING */
268
269/*
222/*
270 * vpointr()
223 * vpo_intr()
271 */
224 */
272static __inline void
273vpointr(struct vpo_data *vpo, struct scsi_xfer *xs)
225static void
226vpo_intr(struct vpo_data *vpo, struct scsi_xfer *xs)
274{
275
276 int errno; /* error in errno.h */
277
278 if (xs->datalen && !(xs->flags & SCSI_DATA_IN))
279 bcopy(xs->data, vpo->vpo_buffer, xs->datalen);
280
227{
228
229 int errno; /* error in errno.h */
230
231 if (xs->datalen && !(xs->flags & SCSI_DATA_IN))
232 bcopy(xs->data, vpo->vpo_buffer, xs->datalen);
233
281 errno = vpoio_do_scsi(vpo, VP0_INITIATOR,
234 errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
282 xs->sc_link->target, (char *)xs->cmd, xs->cmdlen,
235 xs->sc_link->target, (char *)xs->cmd, xs->cmdlen,
283 vpo->vpo_buffer, xs->datalen, &vpo->vpo_stat, &vpo->vpo_count);
236 vpo->vpo_buffer, xs->datalen, &vpo->vpo_stat, &vpo->vpo_count,
237 &vpo->vpo_error);
284
285#ifdef VP0_DEBUG
286 printf("vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n",
287 errno, vpo->vpo_stat, vpo->vpo_count, vpo->vpo_error);
288#endif
289
290 if (errno) {
291#ifdef VP0_WARNING
292 log(LOG_WARNING, "vpo%d: errno = %d\n", vpo->vpo_unit, errno);
293#endif
294 /* connection to ppbus interrupted */
295 xs->error = XS_DRIVER_STUFFUP;
296 goto error;
297 }
298
299 /* if a timeout occured, no sense */
300 if (vpo->vpo_error) {
238
239#ifdef VP0_DEBUG
240 printf("vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n",
241 errno, vpo->vpo_stat, vpo->vpo_count, vpo->vpo_error);
242#endif
243
244 if (errno) {
245#ifdef VP0_WARNING
246 log(LOG_WARNING, "vpo%d: errno = %d\n", vpo->vpo_unit, errno);
247#endif
248 /* connection to ppbus interrupted */
249 xs->error = XS_DRIVER_STUFFUP;
250 goto error;
251 }
252
253 /* if a timeout occured, no sense */
254 if (vpo->vpo_error) {
301#ifdef VP0_WARNING
302 vpo_warning(vpo, xs, vpo->vpo_error);
303#endif
304 xs->error = XS_TIMEOUT;
305 goto error;
306 }
307
308#define RESERVED_BITS_MASK 0x3e /* 00111110b */
309#define NO_SENSE 0x0
310#define CHECK_CONDITION 0x02
311
312 switch (vpo->vpo_stat & RESERVED_BITS_MASK) {
313 case NO_SENSE:
314 break;
315
316 case CHECK_CONDITION:
317 vpo->vpo_sense.cmd.op_code = REQUEST_SENSE;
318 vpo->vpo_sense.cmd.length = sizeof(xs->sense);
319 vpo->vpo_sense.cmd.control = 0;
320
255 xs->error = XS_TIMEOUT;
256 goto error;
257 }
258
259#define RESERVED_BITS_MASK 0x3e /* 00111110b */
260#define NO_SENSE 0x0
261#define CHECK_CONDITION 0x02
262
263 switch (vpo->vpo_stat & RESERVED_BITS_MASK) {
264 case NO_SENSE:
265 break;
266
267 case CHECK_CONDITION:
268 vpo->vpo_sense.cmd.op_code = REQUEST_SENSE;
269 vpo->vpo_sense.cmd.length = sizeof(xs->sense);
270 vpo->vpo_sense.cmd.control = 0;
271
321 errno = vpoio_do_scsi(vpo, VP0_INITIATOR,
272 errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
322 xs->sc_link->target, (char *)&vpo->vpo_sense.cmd,
323 sizeof(vpo->vpo_sense.cmd),
324 (char *)&xs->sense, sizeof(xs->sense),
273 xs->sc_link->target, (char *)&vpo->vpo_sense.cmd,
274 sizeof(vpo->vpo_sense.cmd),
275 (char *)&xs->sense, sizeof(xs->sense),
325 &vpo->vpo_sense.stat, &vpo->vpo_sense.count);
276 &vpo->vpo_sense.stat, &vpo->vpo_sense.count,
277 &vpo->vpo_error);
326
327 if (errno)
328 /* connection to ppbus interrupted */
329 xs->error = XS_DRIVER_STUFFUP;
330 else
331 xs->error = XS_SENSE;
332
333 goto error;

--- 37 unchanged lines hidden (view full) ---

371#ifdef VP0_DEBUG
372 printf("vpo_scsi_cmd(): xs->flags = 0x%x, "\
373 "xs->data = 0x%x, xs->datalen = %d\ncommand : %*D\n",
374 xs->flags, xs->data, xs->datalen,
375 xs->cmdlen, xs->cmd, " " );
376#endif
377
378 if (xs->flags & SCSI_NOMASK) {
278
279 if (errno)
280 /* connection to ppbus interrupted */
281 xs->error = XS_DRIVER_STUFFUP;
282 else
283 xs->error = XS_SENSE;
284
285 goto error;

--- 37 unchanged lines hidden (view full) ---

323#ifdef VP0_DEBUG
324 printf("vpo_scsi_cmd(): xs->flags = 0x%x, "\
325 "xs->data = 0x%x, xs->datalen = %d\ncommand : %*D\n",
326 xs->flags, xs->data, xs->datalen,
327 xs->cmdlen, xs->cmd, " " );
328#endif
329
330 if (xs->flags & SCSI_NOMASK) {
379 vpointr(vpodata[xs->sc_link->adapter_unit], xs);
331 vpo_intr(vpodata[xs->sc_link->adapter_unit], xs);
380 return COMPLETE;
381 }
382
332 return COMPLETE;
333 }
334
383 s = VP0_SPL();
335 s = splbio();
384
336
385 vpointr(vpodata[xs->sc_link->adapter_unit], xs);
337 vpo_intr(vpodata[xs->sc_link->adapter_unit], xs);
386
387 splx(s);
388 return SUCCESSFULLY_QUEUED;
389}
338
339 splx(s);
340 return SUCCESSFULLY_QUEUED;
341}
390
391#define vpoio_d_pulse(vpo,b) { \
392 ppb_wdtr(&(vpo)->vpo_dev, b); \
393 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
394 ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \
395 ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \
396 ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \
397 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
398 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
399 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
400 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
401 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
402 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
403 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
404}
405
406#define vpoio_c_pulse(vpo,b) { \
407 ppb_wdtr(&(vpo)->vpo_dev, b); \
408 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
409 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
410 ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \
411 ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \
412 ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \
413 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
414 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
415 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
416 ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
417}
418
419static int
420vpoio_disconnect(struct vpo_data *vpo)
421{
422
423 vpoio_d_pulse(vpo, 0);
424 vpoio_d_pulse(vpo, 0x3c);
425 vpoio_d_pulse(vpo, 0x20);
426 vpoio_d_pulse(vpo, 0xf);
427
428 return (ppb_release_bus(&vpo->vpo_dev));
429}
430
431/*
432 * how : PPB_WAIT or PPB_DONTWAIT
433 */
434static int
435vpoio_connect(struct vpo_data *vpo, int how)
436{
437 int error;
438
439 if ((error = ppb_request_bus(&vpo->vpo_dev, how)))
440 return error;
441
442 vpoio_c_pulse(vpo, 0);
443 vpoio_c_pulse(vpo, 0x3c);
444 vpoio_c_pulse(vpo, 0x20);
445
446 if (PPB_IN_EPP_MODE(&vpo->vpo_dev)) {
447 vpoio_c_pulse(vpo, 0xcf);
448 } else {
449 vpoio_c_pulse(vpo, 0x8f);
450 }
451
452 return (0);
453}
454
455/*
456 * vpoio_in_disk_mode()
457 *
458 * Check if we are in disk mode
459 */
460static int
461vpoio_in_disk_mode(struct vpo_data *vpo)
462{
463
464 /* first, set H_AUTO high */
465 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
466
467 /* when H_AUTO is set low, H_FLT should be high */
468 ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE);
469 if ((ppb_rstr(&vpo->vpo_dev) & H_FLT) == 0)
470 return (0);
471
472 /* when H_AUTO is set high, H_FLT should be low */
473 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
474 if ((ppb_rstr(&vpo->vpo_dev) & H_FLT) != 0)
475 return (0);
476
477 return (1);
478}
479
480/*
481 * vpoio_reset()
482 *
483 * SCSI reset signal, the drive must be in disk mode
484 */
485static void
486vpoio_reset (struct vpo_data *vpo)
487{
488
489 /*
490 * SCSI reset signal.
491 */
492 ppb_wdtr(&vpo->vpo_dev, (1 << 7));
493 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_nINIT | H_STROBE);
494 DELAY(25);
495 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
496
497 return;
498}
499
500
501/*
502 * vpo_detect()
503 *
504 * Detect and initialise the VP0 adapter.
505 */
506static int
507vpo_detect(struct vpo_data *vpo)
508{
509
510 vpoio_disconnect(vpo);
511 vpoio_connect(vpo, PPB_DONTWAIT);
512
513 if (!vpoio_in_disk_mode(vpo)) {
514 vpoio_disconnect(vpo);
515 return (VP0_EINITFAILED);
516 }
517
518 /* send SCSI reset signal */
519 vpoio_reset (vpo);
520
521 vpoio_disconnect(vpo);
522
523 if (vpoio_in_disk_mode(vpo))
524 return (VP0_EINITFAILED);
525
526 return (0);
527}
528
529#define vpo_wctr(dev,byte,delay) { \
530 int i; int iter = delay / MHZ_16_IO_DURATION; \
531 for (i = 0; i < iter; i++) { \
532 ppb_wctr(dev, byte); \
533 } \
534}
535
536#define vpoio_spp_outbyte(vpo,byte) { \
537 ppb_wdtr(&vpo->vpo_dev, byte); \
538 ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \
539 vpo_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE, \
540 VP0_SPP_WRITE_PULSE); \
541}
542
543#define vpoio_nibble_inbyte(vpo,buffer) { \
544 register char h, l; \
545 vpo_wctr(&vpo->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE, \
546 VP0_NIBBLE_READ_PULSE); \
547 h = ppb_rstr(&vpo->vpo_dev); \
548 ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \
549 l = ppb_rstr(&vpo->vpo_dev); \
550 *buffer = ((l >> 4) & 0x0f) + (h & 0xf0); \
551}
552
553#define vpoio_ps2_inbyte(vpo,buffer) { \
554 *buffer = ppb_rdtr(&vpo->vpo_dev); \
555 ppb_wctr(&vpo->vpo_dev, PCD | H_nAUTO | H_SELIN | H_INIT | H_nSTROBE); \
556 ppb_wctr(&vpo->vpo_dev, PCD | H_AUTO | H_SELIN | H_INIT | H_nSTROBE); \
557}
558
559/*
560 * vpoio_outstr()
561 */
562static int
563vpoio_outstr(struct vpo_data *vpo, char *buffer, int size)
564{
565
566 register int k;
567 int error = 0;
568 int r, mode, epp;
569
570 mode = ppb_get_mode(&vpo->vpo_dev);
571 switch (mode) {
572 case PPB_NIBBLE:
573 case PPB_PS2:
574 for (k = 0; k < size; k++) {
575 vpoio_spp_outbyte(vpo, *buffer++);
576 }
577 break;
578
579 case PPB_EPP:
580 case PPB_ECP_EPP:
581 epp = ppb_get_epp_protocol(&vpo->vpo_dev);
582
583 ppb_reset_epp_timeout(&vpo->vpo_dev);
584 ppb_wctr(&vpo->vpo_dev,
585 H_AUTO | H_SELIN | H_INIT | H_STROBE);
586
587 if (epp == EPP_1_7)
588 for (k = 0; k < size; k++) {
589 ppb_wepp(&vpo->vpo_dev, *buffer++);
590 if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
591 error = VP0_EPPDATA_TIMEOUT;
592 break;
593 }
594 }
595 else {
596 if (((long) buffer | size) & 0x03)
597 ppb_outsb_epp(&vpo->vpo_dev,
598 buffer, size);
599 else
600 ppb_outsl_epp(&vpo->vpo_dev,
601 buffer, size/4);
602
603 if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
604 error = VP0_EPPDATA_TIMEOUT;
605 break;
606 }
607 }
608 ppb_wctr(&vpo->vpo_dev,
609 H_AUTO | H_nSELIN | H_INIT | H_STROBE);
610 /* ppb_ecp_sync(&vpo->vpo_dev); */
611 break;
612
613 default:
614 printf("vpoio_outstr(): unknown transfer mode (%d)!\n",
615 mode);
616 return (1); /* XXX */
617 }
618
619 return (error);
620}
621
622/*
623 * vpoio_instr()
624 */
625static int
626vpoio_instr(struct vpo_data *vpo, char *buffer, int size)
627{
628
629 register int k;
630 int error = 0;
631 int r, mode, epp;
632
633 mode = ppb_get_mode(&vpo->vpo_dev);
634 switch (mode) {
635 case PPB_NIBBLE:
636 for (k = 0; k < size; k++) {
637 vpoio_nibble_inbyte(vpo, buffer++);
638 }
639 ppb_wctr(&vpo->vpo_dev,
640 H_AUTO | H_nSELIN | H_INIT | H_STROBE);
641 break;
642
643 case PPB_PS2:
644 ppb_wctr(&vpo->vpo_dev, PCD |
645 H_AUTO | H_SELIN | H_INIT | H_nSTROBE);
646
647 for (k = 0; k < size; k++) {
648 vpoio_ps2_inbyte(vpo, buffer++);
649 }
650 ppb_wctr(&vpo->vpo_dev,
651 H_AUTO | H_nSELIN | H_INIT | H_STROBE);
652 break;
653
654 case PPB_EPP:
655 case PPB_ECP_EPP:
656 epp = ppb_get_epp_protocol(&vpo->vpo_dev);
657
658 ppb_reset_epp_timeout(&vpo->vpo_dev);
659 ppb_wctr(&vpo->vpo_dev, PCD |
660 H_AUTO | H_SELIN | H_INIT | H_STROBE);
661
662 if (epp == EPP_1_7)
663 for (k = 0; k < size; k++) {
664 *buffer++ = ppb_repp(&vpo->vpo_dev);
665 if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
666 error = VP0_EPPDATA_TIMEOUT;
667 break;
668 }
669 }
670 else {
671 if (((long) buffer | size) & 0x03)
672 ppb_insb_epp(&vpo->vpo_dev,
673 buffer, size);
674 else
675 ppb_insl_epp(&vpo->vpo_dev,
676 buffer, size/4);
677
678 if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
679 error = VP0_EPPDATA_TIMEOUT;
680 break;
681 }
682 }
683 ppb_wctr(&vpo->vpo_dev, PCD |
684 H_AUTO | H_nSELIN | H_INIT | H_STROBE);
685 /* ppb_ecp_sync(&vpo->vpo_dev); */
686 break;
687
688 default:
689 printf("vpoio_instr(): unknown transfer mode (%d)!\n",
690 mode);
691 return (1); /* XXX */
692 }
693
694 return (error);
695}
696
697static __inline char
698vpoio_select(struct vpo_data *vpo, int initiator, int target)
699{
700
701 register int k;
702
703 ppb_wdtr(&vpo->vpo_dev, (1 << target));
704 ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE);
705 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
706 ppb_wdtr(&vpo->vpo_dev, (1 << initiator));
707 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_nINIT | H_STROBE);
708
709 k = 0;
710 while (!(ppb_rstr(&vpo->vpo_dev) & 0x40) && (k++ < VP0_SELTMO))
711 barrier();
712
713 if (k >= VP0_SELTMO)
714 return (VP0_ESELECT_TIMEOUT);
715
716 return (0);
717}
718
719/*
720 * vpoio_wait()
721 *
722 * H_SELIN must be low.
723 */
724static __inline char
725vpoio_wait(struct vpo_data *vpo, int tmo)
726{
727
728 register int k;
729 register char r;
730
731#if 0 /* broken */
732 if (ppb_poll_device(&vpo->vpo_dev, 150, nBUSY, nBUSY, PPB_INTR))
733 return (0);
734
735 return (ppb_rstr(&vpo->vpo_dev) & 0xf0);
736#endif
737
738 k = 0;
739 while (!((r = ppb_rstr(&vpo->vpo_dev)) & nBUSY) && (k++ < tmo))
740 barrier();
741
742 /*
743 * Return some status information.
744 * Semantics : 0xc0 = ZIP wants more data
745 * 0xd0 = ZIP wants to send more data
746 * 0xe0 = ZIP wants command
747 * 0xf0 = end of transfer, ZIP is sending status
748 */
749 if (k < tmo)
750 return (r & 0xf0);
751
752 return (0); /* command timed out */
753}
754
755static __inline int
756vpoio_do_scsi(struct vpo_data *vpo, int host, int target, char *command,
757 int clen, char *buffer, int blen, int *result, int *count)
758{
759
760 register char r;
761 char l, h = 0;
762 int rw, len, error = 0;
763 register int k;
764
765 /*
766 * enter disk state, allocate the ppbus
767 *
768 * XXX
769 * Should we allow this call to be interruptible?
770 * The only way to report the interruption is to return
771 * EIO do upper SCSI code :^(
772 */
773 if ((error = vpoio_connect(vpo, PPB_WAIT|PPB_INTR)))
774 return (error);
775
776 if (!vpoio_in_disk_mode(vpo)) {
777 vpo->vpo_error = VP0_ECONNECT; goto error;
778 }
779
780 if ((vpo->vpo_error = vpoio_select(vpo,host,target)))
781 goto error;
782
783 /*
784 * Send the command ...
785 *
786 * set H_SELIN low for vpoio_wait().
787 */
788 ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
789
790#ifdef VP0_DEBUG
791 printf("vpo%d: drive selected, now sending the command...\n",
792 vpo->vpo_unit);
793#endif
794
795 for (k = 0; k < clen; k++) {
796 if (vpoio_wait(vpo, VP0_FAST_SPINTMO) != (char)0xe0) {
797 vpo->vpo_error = VP0_ECMD_TIMEOUT;
798 goto error;
799 }
800 if (vpoio_outstr(vpo, &command[k], 1)) {
801 vpo->vpo_error = VP0_EPPDATA_TIMEOUT;
802 goto error;
803 }
804 }
805
806#ifdef VP0_DEBUG
807 printf("vpo%d: command sent, now completing the request...\n",
808 vpo->vpo_unit);
809#endif
810
811 /*
812 * Completion ...
813 */
814 rw = ((command[0] == READ_COMMAND) || (command[0] == READ_BIG) ||
815 (command[0] == WRITE_COMMAND) || (command[0] == WRITE_BIG));
816
817 *count = 0;
818 for (;;) {
819
820 if (!(r = vpoio_wait(vpo, VP0_LOW_SPINTMO))) {
821 vpo->vpo_error = VP0_ESTATUS_TIMEOUT; goto error;
822 }
823
824 /* stop when the ZIP wants to send status */
825 if (r == (char)0xf0)
826 break;
827
828 if (*count >= blen) {
829 vpo->vpo_error = VP0_EDATA_OVERFLOW;
830 goto error;
831 }
832 len = (rw && ((blen - *count) >= VP0_SECTOR_SIZE)) ?
833 VP0_SECTOR_SIZE : 1;
834
835 /* ZIP wants to send data? */
836 if (r == (char)0xc0)
837 error = vpoio_outstr(vpo, &buffer[*count], len);
838 else
839 error = vpoio_instr(vpo, &buffer[*count], len);
840
841 if (error) {
842 vpo->vpo_error = error;
843 goto error;
844 }
845
846 *count += len;
847 }
848
849 if (vpoio_instr(vpo, &l, 1)) {
850 vpo->vpo_error = VP0_EOTHER; goto error;
851 }
852
853 /* check if the ZIP wants to send more status */
854 if (vpoio_wait(vpo, VP0_FAST_SPINTMO) == (char)0xf0)
855 if (vpoio_instr(vpo, &h, 1)) {
856 vpo->vpo_error = VP0_EOTHER+2; goto error;
857 }
858
859 *result = ((int) h << 8) | ((int) l & 0xff);
860
861error:
862 /* return to printer state, release the ppbus */
863 vpoio_disconnect(vpo);
864 return (0);
865}