2 * Copyright (c) 1997, 1998, 1999 Nicolas Souchu
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/sys/dev/ppbus/vpo.c,v 1.20.2.1 2000/05/07 21:08:18 n_hibma Exp $
27 * $DragonFly: src/sys/dev/disk/vpo/vpo.c,v 1.12 2008/05/18 20:30:23 pavalos Exp $
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/module.h>
34 #include <sys/malloc.h>
35 #include <sys/devicestat.h> /* for struct devstat */
36 #include <sys/thread2.h> /* for crit_*() */
38 #include <machine/clock.h>
40 #include <bus/cam/cam.h>
41 #include <bus/cam/cam_ccb.h>
42 #include <bus/cam/cam_sim.h>
43 #include <bus/cam/cam_xpt_sim.h>
44 #include <bus/cam/cam_debug.h>
45 #include <bus/cam/cam_periph.h>
47 #include <bus/cam/scsi/scsi_all.h>
48 #include <bus/cam/scsi/scsi_message.h>
49 #include <bus/cam/scsi/scsi_da.h>
51 #include <sys/kernel.h>
55 #include <bus/ppbus/ppbconf.h>
61 struct scsi_sense cmd
;
67 unsigned short vpo_unit
;
77 struct vpo_sense vpo_sense
;
79 struct vpoio_data vpo_io
; /* interface to low level functions */
82 #define DEVTOSOFTC(dev) \
83 ((struct vpo_data *)device_get_softc(dev))
85 /* cam related functions */
86 static void vpo_action(struct cam_sim
*sim
, union ccb
*ccb
);
87 static void vpo_poll(struct cam_sim
*sim
);
88 static void vpo_cam_rescan_callback(struct cam_periph
*periph
,
90 static void vpo_cam_rescan(struct vpo_data
*vpo
);
96 vpo_probe(device_t dev
)
101 vpo
= DEVTOSOFTC(dev
);
102 bzero(vpo
, sizeof(struct vpo_data
));
104 /* vpo dependent initialisation */
105 vpo
->vpo_unit
= device_get_unit(dev
);
107 /* low level probe */
108 vpoio_set_unit(&vpo
->vpo_io
, vpo
->vpo_unit
);
110 /* check ZIP before ZIP+ or imm_probe() will send controls to
111 * the printer or whatelse connected to the port */
112 if ((error
= vpoio_probe(dev
, &vpo
->vpo_io
)) == 0) {
115 "Iomega VPI0 Parallel to SCSI interface");
116 } else if ((error
= imm_probe(dev
, &vpo
->vpo_io
)) == 0) {
119 "Iomega Matchmaker Parallel to SCSI interface");
131 vpo_attach(device_t dev
)
133 struct vpo_data
*vpo
= DEVTOSOFTC(dev
);
134 struct cam_devq
*devq
;
137 /* low level attachment */
138 if (vpo
->vpo_isplus
) {
139 if ((error
= imm_attach(&vpo
->vpo_io
)))
142 if ((error
= vpoio_attach(&vpo
->vpo_io
)))
147 ** Now tell the generic SCSI layer
150 devq
= cam_simq_alloc(/*maxopenings*/1);
151 /* XXX What about low-level detach on error? */
155 vpo
->sim
= cam_sim_alloc(vpo_action
, vpo_poll
, "vpo", vpo
,
156 device_get_unit(dev
), &sim_mplock
,
157 /*untagged*/1, /*tagged*/0, devq
);
158 cam_simq_release(devq
);
159 if (vpo
->sim
== NULL
) {
163 if (xpt_bus_register(vpo
->sim
, /*bus*/0) != CAM_SUCCESS
) {
164 cam_sim_free(vpo
->sim
);
170 vpo_cam_rescan(vpo
); /* have CAM rescan the bus */
176 vpo_cam_rescan_callback(struct cam_periph
*periph
, union ccb
*ccb
)
182 vpo_cam_rescan(struct vpo_data
*vpo
)
184 struct cam_path
*path
;
185 union ccb
*ccb
= kmalloc(sizeof(union ccb
), M_TEMP
, M_WAITOK
| M_ZERO
);
187 if (xpt_create_path(&path
, xpt_periph
, cam_sim_path(vpo
->sim
), 0, 0)
189 /* A failure is benign as the user can do a manual rescan */
193 xpt_setup_ccb(&ccb
->ccb_h
, path
, 5/*priority (low)*/);
194 ccb
->ccb_h
.func_code
= XPT_SCAN_BUS
;
195 ccb
->ccb_h
.cbfcnp
= vpo_cam_rescan_callback
;
196 ccb
->crcn
.flags
= CAM_FLAG_NONE
;
199 /* The scan is in progress now. */
206 vpo_intr(struct vpo_data
*vpo
, struct ccb_scsiio
*csio
)
215 if (vpo
->vpo_isplus
) {
216 error
= imm_do_scsi(&vpo
->vpo_io
, VP0_INITIATOR
,
217 csio
->ccb_h
.target_id
,
218 (char *)&csio
->cdb_io
.cdb_bytes
, csio
->cdb_len
,
219 (char *)csio
->data_ptr
, csio
->dxfer_len
,
220 &vpo
->vpo_stat
, &vpo
->vpo_count
, &vpo
->vpo_error
);
222 error
= vpoio_do_scsi(&vpo
->vpo_io
, VP0_INITIATOR
,
223 csio
->ccb_h
.target_id
,
224 (char *)&csio
->cdb_io
.cdb_bytes
, csio
->cdb_len
,
225 (char *)csio
->data_ptr
, csio
->dxfer_len
,
226 &vpo
->vpo_stat
, &vpo
->vpo_count
, &vpo
->vpo_error
);
230 kprintf("vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n",
231 error
, vpo
->vpo_stat
, vpo
->vpo_count
, vpo
->vpo_error
);
233 /* dump of command */
234 for (i
=0; i
<csio
->cdb_len
; i
++)
235 kprintf("%x ", ((char *)&csio
->cdb_io
.cdb_bytes
)[i
]);
241 /* connection to ppbus interrupted */
242 csio
->ccb_h
.status
= CAM_CMD_TIMEOUT
;
246 /* if a timeout occured, no sense */
247 if (vpo
->vpo_error
) {
248 if (vpo
->vpo_error
!= VP0_ESELECT_TIMEOUT
)
249 kprintf("vpo%d: VP0 error/timeout (%d)\n",
250 vpo
->vpo_unit
, vpo
->vpo_error
);
252 csio
->ccb_h
.status
= CAM_CMD_TIMEOUT
;
256 /* check scsi status */
257 if (vpo
->vpo_stat
!= SCSI_STATUS_OK
) {
258 csio
->scsi_status
= vpo
->vpo_stat
;
260 /* check if we have to sense the drive */
261 if ((vpo
->vpo_stat
& SCSI_STATUS_CHECK_COND
) != 0) {
263 vpo
->vpo_sense
.cmd
.opcode
= REQUEST_SENSE
;
264 vpo
->vpo_sense
.cmd
.length
= csio
->sense_len
;
265 vpo
->vpo_sense
.cmd
.control
= 0;
267 if (vpo
->vpo_isplus
) {
268 error
= imm_do_scsi(&vpo
->vpo_io
, VP0_INITIATOR
,
269 csio
->ccb_h
.target_id
,
270 (char *)&vpo
->vpo_sense
.cmd
,
271 sizeof(vpo
->vpo_sense
.cmd
),
272 (char *)&csio
->sense_data
, csio
->sense_len
,
273 &vpo
->vpo_sense
.stat
, &vpo
->vpo_sense
.count
,
276 error
= vpoio_do_scsi(&vpo
->vpo_io
, VP0_INITIATOR
,
277 csio
->ccb_h
.target_id
,
278 (char *)&vpo
->vpo_sense
.cmd
,
279 sizeof(vpo
->vpo_sense
.cmd
),
280 (char *)&csio
->sense_data
, csio
->sense_len
,
281 &vpo
->vpo_sense
.stat
, &vpo
->vpo_sense
.count
,
287 kprintf("(sense) vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n",
288 error
, vpo
->vpo_sense
.stat
, vpo
->vpo_sense
.count
, vpo
->vpo_error
);
291 /* check sense return status */
292 if (error
== 0 && vpo
->vpo_sense
.stat
== SCSI_STATUS_OK
) {
294 csio
->ccb_h
.status
= CAM_AUTOSNS_VALID
| CAM_SCSI_STATUS_ERROR
;
295 csio
->sense_resid
= csio
->sense_len
- vpo
->vpo_sense
.count
;
298 /* dump of sense info */
300 for (i
=0; i
<vpo
->vpo_sense
.count
; i
++)
301 kprintf("%x ", ((char *)&csio
->sense_data
)[i
]);
307 csio
->ccb_h
.status
= CAM_AUTOSENSE_FAIL
;
311 csio
->ccb_h
.status
= CAM_SCSI_STATUS_ERROR
;
317 csio
->resid
= csio
->dxfer_len
- vpo
->vpo_count
;
318 csio
->ccb_h
.status
= CAM_REQ_CMP
;
327 vpo_action(struct cam_sim
*sim
, union ccb
*ccb
)
330 struct vpo_data
*vpo
= (struct vpo_data
*)sim
->softc
;
332 switch (ccb
->ccb_h
.func_code
) {
335 struct ccb_scsiio
*csio
;
340 kprintf("vpo%d: XPT_SCSI_IO (0x%x) request\n",
341 vpo
->vpo_unit
, csio
->cdb_io
.cdb_bytes
[0]);
350 case XPT_CALC_GEOMETRY
:
352 struct ccb_calc_geometry
*ccg
;
357 kprintf("vpo%d: XPT_CALC_GEOMETRY (bs=%d,vs=%ju,c=%d,h=%d,spt=%d) request\n",
360 (uintmax_t)ccg
->volume_size
,
363 ccg
->secs_per_track
);
367 ccg
->secs_per_track
= 32;
368 ccg
->cylinders
= ccg
->volume_size
/
369 (ccg
->heads
* ccg
->secs_per_track
);
371 ccb
->ccb_h
.status
= CAM_REQ_CMP
;
375 case XPT_RESET_BUS
: /* Reset the specified SCSI bus */
379 kprintf("vpo%d: XPT_RESET_BUS request\n", vpo
->vpo_unit
);
382 if (vpo
->vpo_isplus
) {
383 if (imm_reset_bus(&vpo
->vpo_io
)) {
384 ccb
->ccb_h
.status
= CAM_REQ_CMP_ERR
;
389 if (vpoio_reset_bus(&vpo
->vpo_io
)) {
390 ccb
->ccb_h
.status
= CAM_REQ_CMP_ERR
;
396 ccb
->ccb_h
.status
= CAM_REQ_CMP
;
400 case XPT_PATH_INQ
: /* Path routing inquiry */
402 struct ccb_pathinq
*cpi
= &ccb
->cpi
;
405 kprintf("vpo%d: XPT_PATH_INQ request\n", vpo
->vpo_unit
);
407 cpi
->version_num
= 1; /* XXX??? */
408 cpi
->hba_inquiry
= 0;
409 cpi
->target_sprt
= 0;
411 cpi
->hba_eng_cnt
= 0;
414 cpi
->initiator_id
= VP0_INITIATOR
;
415 cpi
->bus_id
= sim
->bus_id
;
416 cpi
->base_transfer_speed
= 93;
417 strncpy(cpi
->sim_vid
, "FreeBSD", SIM_IDLEN
);
418 strncpy(cpi
->hba_vid
, "Iomega", HBA_IDLEN
);
419 strncpy(cpi
->dev_name
, sim
->sim_name
, DEV_IDLEN
);
420 cpi
->unit_number
= sim
->unit_number
;
422 cpi
->ccb_h
.status
= CAM_REQ_CMP
;
427 ccb
->ccb_h
.status
= CAM_REQ_INVALID
;
436 vpo_poll(struct cam_sim
*sim
)
438 /* The ZIP is actually always polled throw vpo_action() */
443 * Always create a "vpo" device under ppbus. Use device_identify to
444 * create the static entry for any attached ppbus.
446 static devclass_t vpo_devclass
;
448 static device_method_t vpo_methods
[] = {
449 /* device interface */
450 DEVMETHOD(device_identify
, bus_generic_identify
),
451 DEVMETHOD(device_probe
, vpo_probe
),
452 DEVMETHOD(device_attach
, vpo_attach
),
456 static driver_t vpo_driver
= {
459 sizeof(struct vpo_data
),
461 DRIVER_MODULE(vpo
, ppbus
, vpo_driver
, vpo_devclass
, 0, 0);