vpo.c revision 312850
118334Speter/*-
2169689Skan * Copyright (c) 1997, 1998, 1999 Nicolas Souchu
3169689Skan * All rights reserved.
418334Speter *
590075Sobrien * Redistribution and use in source and binary forms, with or without
618334Speter * modification, are permitted provided that the following conditions
790075Sobrien * are met:
890075Sobrien * 1. Redistributions of source code must retain the above copyright
990075Sobrien *    notice, this list of conditions and the following disclaimer.
1090075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1118334Speter *    notice, this list of conditions and the following disclaimer in the
1290075Sobrien *    documentation and/or other materials provided with the distribution.
1390075Sobrien *
1490075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1590075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1618334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1718334Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1890075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2118334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2218334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2350397Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24132718Skan * SUCH DAMAGE.
25132718Skan *
2650397Sobrien */
2718334Speter
2818334Speter#include <sys/cdefs.h>
2990075Sobrien__FBSDID("$FreeBSD: stable/10/sys/dev/ppbus/vpo.c 312850 2017-01-26 21:35:58Z mav $");
3018334Speter
3150397Sobrien#include <sys/param.h>
3250397Sobrien#include <sys/systm.h>
3390075Sobrien#include <sys/module.h>
3496263Sobrien#include <sys/bus.h>
3590075Sobrien#include <sys/lock.h>
3690075Sobrien#include <sys/mutex.h>
37169689Skan#include <sys/malloc.h>
38169689Skan
39169689Skan#include <cam/cam.h>
40169689Skan#include <cam/cam_ccb.h>
4118334Speter#include <cam/cam_sim.h>
42169689Skan#include <cam/cam_xpt_sim.h>
43169689Skan#include <cam/cam_debug.h>
44169689Skan#include <cam/cam_periph.h>
45169689Skan
4618334Speter#include <cam/scsi/scsi_all.h>
47117395Skan#include <cam/scsi/scsi_message.h>
4852284Sobrien#include <cam/scsi/scsi_da.h>
49169689Skan
50169689Skan#include <sys/kernel.h>
5152284Sobrien
5252284Sobrien#include "opt_vpo.h"
5318334Speter
54117395Skan#include <dev/ppbus/ppbconf.h>
5552284Sobrien#include <dev/ppbus/vpoio.h>
56117395Skan
57132718Skan#include "ppbus_if.h"
58117395Skan
59117395Skanstruct vpo_sense {
6090075Sobrien	struct scsi_sense cmd;
61169689Skan	unsigned int stat;
62169689Skan	unsigned int count;
6390075Sobrien};
6490075Sobrien
6596263Sobrienstruct vpo_data {
66169689Skan	device_t vpo_dev;
67169689Skan	int vpo_stat;
68169689Skan	int vpo_count;
6952284Sobrien	int vpo_error;
70132718Skan
71132718Skan	int vpo_isplus;
7290075Sobrien
7352284Sobrien	struct cam_sim  *sim;
7490075Sobrien
75132718Skan	struct vpo_sense vpo_sense;
7652284Sobrien
77169689Skan	struct vpoio_data vpo_io;	/* interface to low level functions */
7852284Sobrien};
79169689Skan
8052284Sobrien#define DEVTOSOFTC(dev) \
81169689Skan	((struct vpo_data *)device_get_softc(dev))
82169689Skan
83169689Skan/* cam related functions */
8452284Sobrienstatic void	vpo_action(struct cam_sim *sim, union ccb *ccb);
85169689Skanstatic void	vpo_poll(struct cam_sim *sim);
86169689Skan
87169689Skanstatic void
88169689Skanvpo_identify(driver_t *driver, device_t parent)
89169689Skan{
90169689Skan
91169689Skan	device_t dev;
92169689Skan
93169689Skan	dev = device_find_child(parent, "vpo", -1);
9452284Sobrien	if (!dev)
9552284Sobrien		BUS_ADD_CHILD(parent, 0, "vpo", -1);
9652284Sobrien}
9790075Sobrien
98132718Skan/*
9952284Sobrien * vpo_probe()
10052284Sobrien */
101169689Skanstatic int
10252284Sobrienvpo_probe(device_t dev)
103169689Skan{
10452284Sobrien	device_t ppbus = device_get_parent(dev);
10552284Sobrien	struct vpo_data *vpo;
10652284Sobrien	int error;
10752284Sobrien
10852284Sobrien	vpo = DEVTOSOFTC(dev);
10952284Sobrien	vpo->vpo_dev = dev;
11052284Sobrien
11152284Sobrien	/* check ZIP before ZIP+ or imm_probe() will send controls to
11252284Sobrien	 * the printer or whatelse connected to the port */
11352284Sobrien	ppb_lock(ppbus);
11452284Sobrien	if ((error = vpoio_probe(dev, &vpo->vpo_io)) == 0) {
11552284Sobrien		vpo->vpo_isplus = 0;
116169689Skan		device_set_desc(dev,
117169689Skan				"Iomega VPI0 Parallel to SCSI interface");
11852284Sobrien	} else if ((error = imm_probe(dev, &vpo->vpo_io)) == 0) {
11952284Sobrien		vpo->vpo_isplus = 1;
12052284Sobrien		device_set_desc(dev,
121169689Skan				"Iomega Matchmaker Parallel to SCSI interface");
12252284Sobrien	} else {
123169689Skan		ppb_unlock(ppbus);
12452284Sobrien		return (error);
125169689Skan	}
12652284Sobrien	ppb_unlock(ppbus);
12790075Sobrien
12890075Sobrien	return (0);
12990075Sobrien}
130169689Skan
13190075Sobrien/*
132169689Skan * vpo_attach()
13352284Sobrien */
13452284Sobrienstatic int
13590075Sobrienvpo_attach(device_t dev)
13690075Sobrien{
137169689Skan	struct vpo_data *vpo = DEVTOSOFTC(dev);
138169689Skan	device_t ppbus = device_get_parent(dev);
13990075Sobrien	struct ppb_data *ppb = device_get_softc(ppbus);	/* XXX: layering */
140169689Skan	struct cam_devq *devq;
14190075Sobrien	int error;
14290075Sobrien
14390075Sobrien	/* low level attachment */
14490075Sobrien	if (vpo->vpo_isplus) {
145169689Skan		if ((error = imm_attach(&vpo->vpo_io)))
14618334Speter			return (error);
14790075Sobrien	} else {
14890075Sobrien		if ((error = vpoio_attach(&vpo->vpo_io)))
14990075Sobrien			return (error);
15090075Sobrien	}
15118334Speter
152169689Skan	/*
153169689Skan	**	Now tell the generic SCSI layer
15490075Sobrien	**	about our bus.
155169689Skan	*/
15690075Sobrien	devq = cam_simq_alloc(/*maxopenings*/1);
15718334Speter	/* XXX What about low-level detach on error? */
15890075Sobrien	if (devq == NULL)
159169689Skan		return (ENXIO);
16018334Speter
16190075Sobrien	vpo->sim = cam_sim_alloc(vpo_action, vpo_poll, "vpo", vpo,
16252284Sobrien				 device_get_unit(dev), ppb->ppc_lock,
163169689Skan				 /*untagged*/1, /*tagged*/0, devq);
164169689Skan	if (vpo->sim == NULL) {
16590075Sobrien		cam_simq_free(devq);
16690075Sobrien		return (ENXIO);
167169689Skan	}
168169689Skan
16952284Sobrien	ppb_lock(ppbus);
17090075Sobrien	if (xpt_bus_register(vpo->sim, dev, /*bus*/0) != CAM_SUCCESS) {
17118334Speter		cam_sim_free(vpo->sim, /*free_devq*/TRUE);
172169689Skan		ppb_unlock(ppbus);
173169689Skan		return (ENXIO);
17490075Sobrien	}
175169689Skan	ppb_unlock(ppbus);
17690075Sobrien
17718334Speter	return (0);
17890075Sobrien}
17990075Sobrien
18090075Sobrien/*
18190075Sobrien * vpo_intr()
18290075Sobrien */
18352284Sobrienstatic void
184169689Skanvpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio)
18518334Speter{
186169689Skan	int errno;	/* error in errno.h */
18752284Sobrien#ifdef VP0_DEBUG
188169689Skan	int i;
189169689Skan#endif
19052284Sobrien	uint8_t *ptr;
19190075Sobrien
19252284Sobrien	ptr = scsiio_cdb_ptr(csio);
193169689Skan	if (vpo->vpo_isplus) {
19490075Sobrien		errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
195169689Skan			csio->ccb_h.target_id,
196169689Skan			ptr, csio->cdb_len,
197169689Skan			(char *)csio->data_ptr, csio->dxfer_len,
198169689Skan			&vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error);
199169689Skan	} else {
20090075Sobrien		errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
201169689Skan			csio->ccb_h.target_id,
202169689Skan			ptr, csio->cdb_len,
20318334Speter			(char *)csio->data_ptr, csio->dxfer_len,
20418334Speter			&vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error);
20590075Sobrien	}
20690075Sobrien
20790075Sobrien#ifdef VP0_DEBUG
20890075Sobrien	printf("vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n",
20990075Sobrien		 errno, vpo->vpo_stat, vpo->vpo_count, vpo->vpo_error);
210169689Skan
21152284Sobrien	/* dump of command */
212169689Skan	for (i=0; i<csio->cdb_len; i++)
213169689Skan		printf("%x ", ((char *)ptr)[i]);
21452284Sobrien
215169689Skan	printf("\n");
216169689Skan#endif
217169689Skan
21890075Sobrien	if (errno) {
21990075Sobrien		/* connection to ppbus interrupted */
22090075Sobrien		csio->ccb_h.status = CAM_CMD_TIMEOUT;
22190075Sobrien		return;
22290075Sobrien	}
22390075Sobrien
22490075Sobrien	/* if a timeout occured, no sense */
22590075Sobrien	if (vpo->vpo_error) {
22690075Sobrien		if (vpo->vpo_error != VP0_ESELECT_TIMEOUT)
22790075Sobrien			device_printf(vpo->vpo_dev, "VP0 error/timeout (%d)\n",
22890075Sobrien				vpo->vpo_error);
229169689Skan
230169689Skan		csio->ccb_h.status = CAM_CMD_TIMEOUT;
231169689Skan		return;
232169689Skan	}
233169689Skan
234169689Skan	/* check scsi status */
23590075Sobrien	if (vpo->vpo_stat != SCSI_STATUS_OK) {
23690075Sobrien	   csio->scsi_status = vpo->vpo_stat;
23790075Sobrien
23818334Speter	   /* check if we have to sense the drive */
23990075Sobrien	   if ((vpo->vpo_stat & SCSI_STATUS_CHECK_COND) != 0) {
24090075Sobrien
24190075Sobrien		vpo->vpo_sense.cmd.opcode = REQUEST_SENSE;
24290075Sobrien		vpo->vpo_sense.cmd.length = csio->sense_len;
243169689Skan		vpo->vpo_sense.cmd.control = 0;
24490075Sobrien
24590075Sobrien		if (vpo->vpo_isplus) {
24690075Sobrien			errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
24718334Speter				csio->ccb_h.target_id,
248117395Skan				(char *)&vpo->vpo_sense.cmd,
249117395Skan				sizeof(vpo->vpo_sense.cmd),
25090075Sobrien				(char *)&csio->sense_data, csio->sense_len,
251132718Skan				&vpo->vpo_sense.stat, &vpo->vpo_sense.count,
252132718Skan				&vpo->vpo_error);
25352284Sobrien		} else {
25496263Sobrien			errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
255132718Skan				csio->ccb_h.target_id,
25696263Sobrien				(char *)&vpo->vpo_sense.cmd,
25796263Sobrien				sizeof(vpo->vpo_sense.cmd),
258102780Skan				(char *)&csio->sense_data, csio->sense_len,
259102780Skan				&vpo->vpo_sense.stat, &vpo->vpo_sense.count,
260102780Skan				&vpo->vpo_error);
261102780Skan		}
262102780Skan
263102780Skan
264102780Skan#ifdef VP0_DEBUG
265102780Skan		printf("(sense) vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n",
26696263Sobrien			errno, vpo->vpo_sense.stat, vpo->vpo_sense.count, vpo->vpo_error);
267132718Skan#endif
26896263Sobrien
269169689Skan		/* check sense return status */
270169689Skan		if (errno == 0 && vpo->vpo_sense.stat == SCSI_STATUS_OK) {
27196263Sobrien		   /* sense ok */
27296263Sobrien		   csio->ccb_h.status = CAM_AUTOSNS_VALID | CAM_SCSI_STATUS_ERROR;
27396263Sobrien		   csio->sense_resid = csio->sense_len - vpo->vpo_sense.count;
27496263Sobrien
27596263Sobrien#ifdef VP0_DEBUG
276132718Skan		   /* dump of sense info */
27796263Sobrien		   printf("(sense) ");
27896263Sobrien		   for (i=0; i<vpo->vpo_sense.count; i++)
27996263Sobrien			printf("%x ", ((char *)&csio->sense_data)[i]);
280119256Skan		   printf("\n");
281119256Skan#endif
282119256Skan
283119256Skan		} else {
28496263Sobrien		   /* sense failed */
285119256Skan		   csio->ccb_h.status = CAM_AUTOSENSE_FAIL;
286119256Skan		}
287119256Skan	   } else {
288119256Skan		/* no sense */
289119256Skan		csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
290119256Skan	   }
291169689Skan
292119256Skan	   return;
293119256Skan	}
29496263Sobrien
295119256Skan	csio->resid = csio->dxfer_len - vpo->vpo_count;
296119256Skan	csio->ccb_h.status = CAM_REQ_CMP;
29796263Sobrien}
29896263Sobrien
29996263Sobrienstatic void
30096263Sobrienvpo_action(struct cam_sim *sim, union ccb *ccb)
30196263Sobrien{
30296263Sobrien	struct vpo_data *vpo = (struct vpo_data *)sim->softc;
30396263Sobrien
30496263Sobrien	ppb_assert_locked(device_get_parent(vpo->vpo_dev));
30596263Sobrien	switch (ccb->ccb_h.func_code) {
306169689Skan	case XPT_SCSI_IO:
307169689Skan	{
308169689Skan		struct ccb_scsiio *csio;
309169689Skan
310169689Skan		csio = &ccb->csio;
311169689Skan
312169689Skan		if (ccb->ccb_h.flags & CAM_CDB_PHYS) {
313169689Skan			ccb->ccb_h.status = CAM_REQ_INVALID;
314169689Skan			xpt_done(ccb);
315169689Skan			break;
316169689Skan		}
317169689Skan#ifdef VP0_DEBUG
318169689Skan		device_printf(vpo->vpo_dev, "XPT_SCSI_IO (0x%x) request\n",
319169689Skan		    scsiio_cdb_ptr(csio));
320169689Skan#endif
321169689Skan		vpo_intr(vpo, csio);
322169689Skan
323169689Skan		xpt_done(ccb);
324169689Skan
325169689Skan		break;
326169689Skan	}
327169689Skan	case XPT_CALC_GEOMETRY:
328169689Skan	{
329169689Skan		struct	  ccb_calc_geometry *ccg;
330169689Skan
331169689Skan		ccg = &ccb->ccg;
332169689Skan
33390075Sobrien#ifdef VP0_DEBUG
33490075Sobrien		device_printf(vpo->vpo_dev, "XPT_CALC_GEOMETRY (bs=%d,vs=%jd,c=%d,h=%d,spt=%d) request\n",
335169689Skan			ccg->block_size,
33690075Sobrien			(intmax_t)ccg->volume_size,
33796263Sobrien			ccg->cylinders,
33890075Sobrien			ccg->heads,
33952284Sobrien			ccg->secs_per_track);
34090075Sobrien#endif
34152284Sobrien
342169689Skan		ccg->heads = 64;
34390075Sobrien		ccg->secs_per_track = 32;
344169689Skan		ccg->cylinders = ccg->volume_size /
34590075Sobrien				 (ccg->heads * ccg->secs_per_track);
34690075Sobrien
347169689Skan		ccb->ccb_h.status = CAM_REQ_CMP;
34890075Sobrien		xpt_done(ccb);
349169689Skan		break;
35090075Sobrien	}
35190075Sobrien	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
352169689Skan	{
35352284Sobrien
35496263Sobrien#ifdef VP0_DEBUG
355169689Skan		device_printf(vpo->vpo_dev, "XPT_RESET_BUS request\n");
356102780Skan#endif
357102780Skan
358102780Skan		if (vpo->vpo_isplus) {
359102780Skan			if (imm_reset_bus(&vpo->vpo_io)) {
360102780Skan				ccb->ccb_h.status = CAM_REQ_CMP_ERR;
36196263Sobrien				xpt_done(ccb);
36296263Sobrien				return;
36390075Sobrien			}
36496263Sobrien		} else {
36596263Sobrien			if (vpoio_reset_bus(&vpo->vpo_io)) {
366169689Skan				ccb->ccb_h.status = CAM_REQ_CMP_ERR;
36796263Sobrien				xpt_done(ccb);
36896263Sobrien				return;
369169689Skan			}
370169689Skan		}
371169689Skan
372169689Skan		ccb->ccb_h.status = CAM_REQ_CMP;
373169689Skan		xpt_done(ccb);
37496263Sobrien		break;
37596263Sobrien	}
376169689Skan	case XPT_PATH_INQ:		/* Path routing inquiry */
377169689Skan	{
378169689Skan		struct ccb_pathinq *cpi = &ccb->cpi;
379169689Skan
380169689Skan#ifdef VP0_DEBUG
381169689Skan		device_printf(vpo->vpo_dev, "XPT_PATH_INQ request\n");
382169689Skan#endif
383169689Skan		cpi->version_num = 1; /* XXX??? */
384169689Skan		cpi->hba_inquiry = 0;
385169689Skan		cpi->target_sprt = 0;
386169689Skan		cpi->hba_misc = 0;
387169689Skan		cpi->hba_eng_cnt = 0;
388169689Skan		cpi->max_target = 7;
389169689Skan		cpi->max_lun = 0;
390169689Skan		cpi->initiator_id = VP0_INITIATOR;
391169689Skan		cpi->bus_id = sim->bus_id;
392169689Skan		cpi->base_transfer_speed = 93;
393169689Skan		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
394169689Skan		strncpy(cpi->hba_vid, "Iomega", HBA_IDLEN);
395169689Skan		strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
396169689Skan		cpi->unit_number = sim->unit_number;
397169689Skan		cpi->transport = XPORT_PPB;
398169689Skan		cpi->transport_version = 0;
399169689Skan
400169689Skan		cpi->ccb_h.status = CAM_REQ_CMP;
401169689Skan		xpt_done(ccb);
402169689Skan		break;
403169689Skan	}
404169689Skan	default:
405169689Skan		ccb->ccb_h.status = CAM_REQ_INVALID;
406169689Skan		xpt_done(ccb);
407169689Skan		break;
408117395Skan	}
409117395Skan
410132718Skan	return;
41196263Sobrien}
412169689Skan
41396263Sobrienstatic void
414169689Skanvpo_poll(struct cam_sim *sim)
41596263Sobrien{
41696263Sobrien
41796263Sobrien	/* The ZIP is actually always polled throw vpo_action(). */
41896263Sobrien}
419169689Skan
420169689Skanstatic devclass_t vpo_devclass;
421169689Skan
422169689Skanstatic device_method_t vpo_methods[] = {
423169689Skan	/* device interface */
424169689Skan	DEVMETHOD(device_identify,	vpo_identify),
425169689Skan	DEVMETHOD(device_probe,		vpo_probe),
426169689Skan	DEVMETHOD(device_attach,	vpo_attach),
427169689Skan
42896263Sobrien	{ 0, 0 }
429169689Skan};
430169689Skan
431169689Skanstatic driver_t vpo_driver = {
43296263Sobrien	"vpo",
43396263Sobrien	vpo_methods,
43496263Sobrien	sizeof(struct vpo_data),
43596263Sobrien};
436169689SkanDRIVER_MODULE(vpo, ppbus, vpo_driver, vpo_devclass, 0, 0);
437169689SkanMODULE_DEPEND(vpo, ppbus, 1, 1, 1);
438169689SkanMODULE_DEPEND(vpo, cam, 1, 1, 1);
439169689Skan