2002-08-09 20:54:06 +00:00
|
|
|
/*-
|
2007-02-27 09:00:51 +00:00
|
|
|
* Copyright (c) 2001-2007 Thomas Quinot <thomas@cuivre.fr.eu.org>
|
2002-08-09 20:54:06 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer,
|
|
|
|
* without modification, immediately at the beginning of the file.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
|
|
* derived from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2003-08-24 17:55:58 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
2002-08-09 20:54:06 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/bus.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/ata.h>
|
2003-08-24 09:22:26 +00:00
|
|
|
#include <sys/taskqueue.h>
|
|
|
|
#include <sys/lock.h>
|
|
|
|
#include <sys/mutex.h>
|
2004-01-12 07:16:07 +00:00
|
|
|
#include <sys/sema.h>
|
2004-01-14 21:26:35 +00:00
|
|
|
#include <vm/uma.h>
|
2005-04-05 02:03:31 +00:00
|
|
|
#include <machine/resource.h>
|
2002-08-09 20:54:06 +00:00
|
|
|
#include <machine/bus.h>
|
|
|
|
|
|
|
|
#include <cam/cam.h>
|
|
|
|
#include <cam/cam_ccb.h>
|
|
|
|
#include <cam/cam_periph.h>
|
|
|
|
#include <cam/cam_sim.h>
|
|
|
|
#include <cam/cam_xpt_sim.h>
|
|
|
|
#include <cam/cam_debug.h>
|
|
|
|
#include <cam/scsi/scsi_all.h>
|
|
|
|
|
|
|
|
#include <dev/ata/ata-all.h>
|
2005-04-05 02:03:31 +00:00
|
|
|
#include <ata_if.h>
|
|
|
|
|
|
|
|
/* private data associated with an ATA bus */
|
|
|
|
struct atapi_xpt_softc {
|
2005-04-30 16:22:07 +00:00
|
|
|
struct ata_device atapi_cam_dev; /* must be first */
|
|
|
|
device_t dev;
|
|
|
|
device_t parent;
|
|
|
|
struct ata_channel *ata_ch;
|
|
|
|
struct cam_path *path;
|
|
|
|
struct cam_sim *sim;
|
|
|
|
int flags;
|
|
|
|
#define BUS_REGISTERED 0x01
|
|
|
|
#define RESOURCE_SHORTAGE 0x02
|
|
|
|
#define DETACHING 0x04
|
2005-04-05 02:03:31 +00:00
|
|
|
|
|
|
|
TAILQ_HEAD(,atapi_hcb) pending_hcbs;
|
|
|
|
struct ata_device *atadev[2];
|
2005-04-30 16:22:07 +00:00
|
|
|
struct mtx state_lock;
|
2005-04-05 02:03:31 +00:00
|
|
|
};
|
2002-08-09 20:54:06 +00:00
|
|
|
|
|
|
|
/* hardware command descriptor block */
|
|
|
|
struct atapi_hcb {
|
|
|
|
struct atapi_xpt_softc *softc;
|
2005-04-30 16:22:07 +00:00
|
|
|
int unit;
|
|
|
|
int bus;
|
|
|
|
int target;
|
|
|
|
int lun;
|
|
|
|
union ccb *ccb;
|
|
|
|
int flags;
|
|
|
|
#define QUEUED 0x0001
|
2004-02-11 10:14:08 +00:00
|
|
|
#define AUTOSENSE 0x0002
|
2005-04-30 16:22:07 +00:00
|
|
|
char *dxfer_alloc;
|
2002-08-09 20:54:06 +00:00
|
|
|
TAILQ_ENTRY(atapi_hcb) chain;
|
|
|
|
};
|
|
|
|
|
2002-10-22 20:18:51 +00:00
|
|
|
enum reinit_reason { BOOT_ATTACH, ATTACH, RESET };
|
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
/* Device methods */
|
2009-02-04 20:23:42 +00:00
|
|
|
static void atapi_cam_identify(driver_t *dev, device_t parent);
|
2005-04-05 02:03:31 +00:00
|
|
|
static int atapi_cam_probe(device_t dev);
|
|
|
|
static int atapi_cam_attach(device_t dev);
|
|
|
|
static int atapi_cam_detach(device_t dev);
|
|
|
|
static int atapi_cam_reinit(device_t dev);
|
2002-08-09 20:54:06 +00:00
|
|
|
|
|
|
|
/* CAM XPT methods */
|
|
|
|
static void atapi_action(struct cam_sim *, union ccb *);
|
|
|
|
static void atapi_poll(struct cam_sim *);
|
|
|
|
static void atapi_async(void *, u_int32_t, struct cam_path *, void *);
|
2003-08-24 09:22:26 +00:00
|
|
|
static void atapi_cb(struct ata_request *);
|
2002-08-09 20:54:06 +00:00
|
|
|
|
2005-04-15 10:20:52 +00:00
|
|
|
/* Module methods */
|
|
|
|
static int atapi_cam_event_handler(module_t mod, int what, void *arg);
|
|
|
|
|
2002-08-09 20:54:06 +00:00
|
|
|
/* internal functions */
|
2002-10-22 20:18:51 +00:00
|
|
|
static void reinit_bus(struct atapi_xpt_softc *scp, enum reinit_reason reason);
|
2002-08-09 20:54:06 +00:00
|
|
|
static void setup_async_cb(struct atapi_xpt_softc *, uint32_t);
|
|
|
|
static void cam_rescan(struct cam_sim *);
|
|
|
|
static void free_hcb_and_ccb_done(struct atapi_hcb *, u_int32_t);
|
|
|
|
static struct atapi_hcb *allocate_hcb(struct atapi_xpt_softc *, int, int, union ccb *);
|
|
|
|
static void free_hcb(struct atapi_hcb *hcb);
|
|
|
|
static void free_softc(struct atapi_xpt_softc *scp);
|
|
|
|
|
2005-10-31 15:41:29 +00:00
|
|
|
static MALLOC_DEFINE(M_ATACAM, "ata_cam", "ATA driver CAM-XPT layer");
|
2002-08-09 20:54:06 +00:00
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
static device_method_t atapi_cam_methods[] = {
|
2005-04-30 16:22:07 +00:00
|
|
|
DEVMETHOD(device_identify, atapi_cam_identify),
|
|
|
|
DEVMETHOD(device_probe, atapi_cam_probe),
|
|
|
|
DEVMETHOD(device_attach, atapi_cam_attach),
|
|
|
|
DEVMETHOD(device_detach, atapi_cam_detach),
|
|
|
|
DEVMETHOD(ata_reinit, atapi_cam_reinit),
|
2012-03-21 16:59:39 +00:00
|
|
|
DEVMETHOD_END
|
2005-04-05 02:03:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static driver_t atapi_cam_driver = {
|
|
|
|
"atapicam",
|
|
|
|
atapi_cam_methods,
|
|
|
|
sizeof(struct atapi_xpt_softc)
|
|
|
|
};
|
|
|
|
|
2005-04-30 16:22:07 +00:00
|
|
|
static devclass_t atapi_cam_devclass;
|
2005-04-15 10:20:52 +00:00
|
|
|
DRIVER_MODULE(atapicam, ata,
|
|
|
|
atapi_cam_driver,
|
|
|
|
atapi_cam_devclass,
|
|
|
|
atapi_cam_event_handler,
|
|
|
|
/*arg*/NULL);
|
2005-04-05 02:03:31 +00:00
|
|
|
MODULE_VERSION(atapicam, 1);
|
|
|
|
MODULE_DEPEND(atapicam, ata, 1, 1, 1);
|
2005-04-08 22:51:50 +00:00
|
|
|
MODULE_DEPEND(atapicam, cam, 1, 1, 1);
|
2005-04-05 02:03:31 +00:00
|
|
|
|
2005-04-15 10:20:52 +00:00
|
|
|
static void
|
2009-02-04 20:23:42 +00:00
|
|
|
atapi_cam_identify(driver_t *driver, device_t parent)
|
2005-04-05 02:03:31 +00:00
|
|
|
{
|
2005-04-15 10:20:52 +00:00
|
|
|
struct atapi_xpt_softc *scp =
|
2009-02-28 22:07:15 +00:00
|
|
|
malloc (sizeof (struct atapi_xpt_softc), M_ATACAM, M_NOWAIT|M_ZERO);
|
2005-04-15 10:20:52 +00:00
|
|
|
device_t child;
|
|
|
|
|
|
|
|
if (scp == NULL) {
|
|
|
|
printf ("atapi_cam_identify: out of memory");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
/* Assume one atapicam instance per parent channel instance. */
|
2005-04-15 10:20:52 +00:00
|
|
|
child = device_add_child(parent, "atapicam", -1);
|
|
|
|
if (child == NULL) {
|
|
|
|
printf ("atapi_cam_identify: out of memory, can't add child");
|
2009-02-28 22:07:15 +00:00
|
|
|
free (scp, M_ATACAM);
|
2005-04-15 10:20:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
scp->atapi_cam_dev.unit = -1;
|
|
|
|
scp->atapi_cam_dev.dev = child;
|
|
|
|
device_quiet(child);
|
|
|
|
device_set_softc(child, scp);
|
2005-04-05 02:03:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
atapi_cam_probe(device_t dev)
|
|
|
|
{
|
2005-04-15 10:20:52 +00:00
|
|
|
struct ata_device *atadev = device_get_softc (dev);
|
|
|
|
|
|
|
|
KASSERT(atadev != NULL, ("expect valid struct ata_device"));
|
2009-02-28 22:07:15 +00:00
|
|
|
if (atadev->unit < 0) {
|
|
|
|
device_set_desc(dev, "ATAPI CAM Attachment");
|
|
|
|
return (0);
|
|
|
|
} else {
|
|
|
|
return ENXIO;
|
|
|
|
}
|
2005-04-05 02:03:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
atapi_cam_attach(device_t dev)
|
2002-08-09 20:54:06 +00:00
|
|
|
{
|
|
|
|
struct atapi_xpt_softc *scp = NULL;
|
|
|
|
struct cam_devq *devq = NULL;
|
|
|
|
struct cam_sim *sim = NULL;
|
|
|
|
struct cam_path *path = NULL;
|
2005-04-05 02:03:31 +00:00
|
|
|
int unit, error;
|
2003-08-24 09:22:26 +00:00
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
scp = (struct atapi_xpt_softc *)device_get_softc(dev);
|
|
|
|
if (scp == NULL) {
|
|
|
|
device_printf(dev, "Cannot get softc\n");
|
|
|
|
return (ENOMEM);
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
2003-08-24 09:22:26 +00:00
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
mtx_init(&scp->state_lock, "ATAPICAM lock", NULL, MTX_DEF);
|
2002-08-09 20:54:06 +00:00
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
scp->dev = dev;
|
|
|
|
scp->parent = device_get_parent(dev);
|
|
|
|
scp->ata_ch = device_get_softc(scp->parent);
|
2002-08-09 20:54:06 +00:00
|
|
|
TAILQ_INIT(&scp->pending_hcbs);
|
2010-02-03 21:26:54 +00:00
|
|
|
unit = device_get_unit(device_get_parent(dev));
|
2002-08-09 20:54:06 +00:00
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
if ((devq = cam_simq_alloc(16)) == NULL) {
|
|
|
|
error = ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
2002-08-09 20:54:06 +00:00
|
|
|
|
|
|
|
if ((sim = cam_sim_alloc(atapi_action, atapi_poll, "ata",
|
2007-05-02 15:30:24 +00:00
|
|
|
(void *)scp, unit, &scp->state_lock, 1, 1, devq)) == NULL) {
|
2005-04-05 02:03:31 +00:00
|
|
|
error = ENOMEM;
|
|
|
|
goto out;
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
scp->sim = sim;
|
|
|
|
|
2007-05-02 15:30:24 +00:00
|
|
|
mtx_lock(&scp->state_lock);
|
2007-06-17 05:55:54 +00:00
|
|
|
if (xpt_bus_register(sim, dev, 0) != CAM_SUCCESS) {
|
2005-04-05 02:03:31 +00:00
|
|
|
error = EINVAL;
|
2007-05-02 15:30:24 +00:00
|
|
|
mtx_unlock(&scp->state_lock);
|
2005-04-05 02:03:31 +00:00
|
|
|
goto out;
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
scp->flags |= BUS_REGISTERED;
|
|
|
|
|
|
|
|
if (xpt_create_path(&path, /*periph*/ NULL,
|
|
|
|
cam_sim_path(sim), CAM_TARGET_WILDCARD,
|
|
|
|
CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
|
2005-04-05 02:03:31 +00:00
|
|
|
error = ENOMEM;
|
2007-05-02 15:30:24 +00:00
|
|
|
mtx_unlock(&scp->state_lock);
|
2005-04-05 02:03:31 +00:00
|
|
|
goto out;
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
scp->path = path;
|
|
|
|
|
2002-08-28 07:03:44 +00:00
|
|
|
CAM_DEBUG(path, CAM_DEBUG_TRACE, ("Registered SIM for ata%d\n", unit));
|
2002-08-09 20:54:06 +00:00
|
|
|
|
|
|
|
setup_async_cb(scp, AC_LOST_DEVICE);
|
2002-10-22 20:18:51 +00:00
|
|
|
reinit_bus(scp, cold ? BOOT_ATTACH : ATTACH);
|
2005-04-05 02:03:31 +00:00
|
|
|
error = 0;
|
2007-05-02 15:30:24 +00:00
|
|
|
mtx_unlock(&scp->state_lock);
|
2002-08-09 20:54:06 +00:00
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
out:
|
|
|
|
if (error != 0)
|
|
|
|
free_softc(scp);
|
|
|
|
|
|
|
|
return (error);
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
static int
|
|
|
|
atapi_cam_detach(device_t dev)
|
2002-08-09 20:54:06 +00:00
|
|
|
{
|
2005-04-05 02:03:31 +00:00
|
|
|
struct atapi_xpt_softc *scp = device_get_softc(dev);
|
2003-08-24 09:22:26 +00:00
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
mtx_lock(&scp->state_lock);
|
2009-01-08 17:26:51 +00:00
|
|
|
if (xpt_sim_opened(scp->sim)) {
|
|
|
|
mtx_unlock(&scp->state_lock);
|
|
|
|
return (EBUSY);
|
|
|
|
}
|
2007-05-02 15:30:24 +00:00
|
|
|
xpt_freeze_simq(scp->sim, 1 /*count*/);
|
2005-04-05 02:03:31 +00:00
|
|
|
scp->flags |= DETACHING;
|
|
|
|
mtx_unlock(&scp->state_lock);
|
|
|
|
free_softc(scp);
|
|
|
|
return (0);
|
2002-10-22 20:18:51 +00:00
|
|
|
}
|
2002-08-09 20:54:06 +00:00
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
static int
|
|
|
|
atapi_cam_reinit(device_t dev) {
|
|
|
|
struct atapi_xpt_softc *scp = device_get_softc(dev);
|
2003-05-14 14:20:22 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* scp might be null if the bus is being reinitialised during
|
|
|
|
* the boot-up sequence, before the ATAPI bus is registered.
|
|
|
|
*/
|
|
|
|
|
2003-08-24 09:22:26 +00:00
|
|
|
if (scp != NULL) {
|
2007-05-02 15:30:24 +00:00
|
|
|
mtx_lock(&scp->state_lock);
|
2003-05-14 14:20:22 +00:00
|
|
|
reinit_bus(scp, RESET);
|
2007-05-02 15:30:24 +00:00
|
|
|
mtx_unlock(&scp->state_lock);
|
2003-08-24 09:22:26 +00:00
|
|
|
}
|
2005-04-05 02:03:31 +00:00
|
|
|
return (0);
|
2002-10-22 20:18:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
reinit_bus(struct atapi_xpt_softc *scp, enum reinit_reason reason) {
|
2007-03-13 20:38:16 +00:00
|
|
|
struct ata_device *old_atadev[2], *atadev;
|
2005-04-05 02:03:31 +00:00
|
|
|
device_t *children;
|
2007-03-13 20:38:16 +00:00
|
|
|
int nchildren, i, dev_changed;
|
2003-08-24 09:22:26 +00:00
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
if (device_get_children(scp->parent, &children, &nchildren) != 0) {
|
|
|
|
return;
|
|
|
|
}
|
2003-08-24 09:22:26 +00:00
|
|
|
|
2007-03-13 20:38:16 +00:00
|
|
|
old_atadev[0] = scp->atadev[0];
|
|
|
|
old_atadev[1] = scp->atadev[1];
|
2005-04-05 02:03:31 +00:00
|
|
|
scp->atadev[0] = NULL;
|
|
|
|
scp->atadev[1] = NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < nchildren; i++) {
|
|
|
|
/* XXX Does the child need to actually be attached yet? */
|
|
|
|
if (children[i] != NULL) {
|
|
|
|
atadev = device_get_softc(children[i]);
|
|
|
|
if ((atadev->unit == ATA_MASTER) &&
|
|
|
|
(scp->ata_ch->devices & ATA_ATAPI_MASTER) != 0)
|
|
|
|
scp->atadev[0] = atadev;
|
|
|
|
if ((atadev->unit == ATA_SLAVE) &&
|
|
|
|
(scp->ata_ch->devices & ATA_ATAPI_SLAVE) != 0)
|
|
|
|
scp->atadev[1] = atadev;
|
|
|
|
}
|
|
|
|
}
|
2007-03-13 20:38:16 +00:00
|
|
|
dev_changed = (old_atadev[0] != scp->atadev[0])
|
|
|
|
|| (old_atadev[1] != scp->atadev[1]);
|
2005-04-05 02:03:31 +00:00
|
|
|
free(children, M_TEMP);
|
2002-10-22 20:18:51 +00:00
|
|
|
|
|
|
|
switch (reason) {
|
|
|
|
case BOOT_ATTACH:
|
MFp4: Large set of CAM inprovements.
- Unify bus reset/probe sequence. Whenever bus attached at boot or later,
CAM will automatically reset and scan it. It allows to remove duplicate
code from many drivers.
- Any bus, attached before CAM completed it's boot-time initialization,
will equally join to the process, delaying boot if needed.
- New kern.cam.boot_delay loader tunable should help controllers that
are still unable to register their buses in time (such as slow USB/
PCCard/ CardBus devices), by adding one more event to wait on boot.
- To allow synchronization between different CAM levels, concept of
requests priorities was extended. Priorities now split between several
"run levels". Device can be freezed at specified level, allowing higher
priority requests to pass. For example, no payload requests allowed,
until PMP driver enable port. ATA XPT negotiate transfer parameters,
periph driver configure caching and so on.
- Frozen requests are no more counted by request allocation scheduler.
It fixes deadlocks, when frozen low priority payload requests occupying
slots, required by higher levels to manage theit execution.
- Two last changes were holding proper ATA reinitialization and error
recovery implementation. Now it is done: SATA controllers and Port
Multipliers now implement automatic hot-plug and should correctly
recover from timeouts and bus resets.
- Improve SCSI error recovery for devices on buses without automatic sense
reporting, such as ATAPI or USB. For example, it allows CAM to wait, while
CD drive loads disk, instead of immediately return error status.
- Decapitalize diagnostic messages and make them more readable and sensible.
- Teach PMP driver to limit maximum speed on fan-out ports.
- Make boot wait for PMP scan completes, and make rescan more reliable.
- Fix pass driver, to return CCB to user level in case of error.
- Increase number of retries in cd driver, as device may return several UAs.
2010-01-28 08:41:30 +00:00
|
|
|
case ATTACH:
|
2002-10-22 20:18:51 +00:00
|
|
|
break;
|
|
|
|
case RESET:
|
|
|
|
xpt_async(AC_BUS_RESET, scp->path, NULL);
|
2007-03-13 20:38:16 +00:00
|
|
|
|
|
|
|
if (!dev_changed)
|
|
|
|
break;
|
|
|
|
|
2002-10-22 20:18:51 +00:00
|
|
|
cam_rescan(scp->sim);
|
|
|
|
break;
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
setup_async_cb(struct atapi_xpt_softc *scp, uint32_t events)
|
|
|
|
{
|
|
|
|
struct ccb_setasync csa;
|
|
|
|
|
|
|
|
xpt_setup_ccb(&csa.ccb_h, scp->path, /*priority*/ 5);
|
|
|
|
csa.ccb_h.func_code = XPT_SASYNC_CB;
|
|
|
|
csa.event_enable = events;
|
|
|
|
csa.callback = &atapi_async;
|
|
|
|
csa.callback_arg = scp->sim;
|
|
|
|
xpt_action((union ccb *) &csa);
|
|
|
|
}
|
|
|
|
|
2003-08-24 09:22:26 +00:00
|
|
|
static void
|
2002-08-09 20:54:06 +00:00
|
|
|
atapi_action(struct cam_sim *sim, union ccb *ccb)
|
|
|
|
{
|
|
|
|
struct atapi_xpt_softc *softc = (struct atapi_xpt_softc*)cam_sim_softc(sim);
|
|
|
|
struct ccb_hdr *ccb_h = &ccb->ccb_h;
|
|
|
|
struct atapi_hcb *hcb = NULL;
|
2003-08-24 09:22:26 +00:00
|
|
|
struct ata_request *request = NULL;
|
2002-08-09 20:54:06 +00:00
|
|
|
int unit = cam_sim_unit(sim);
|
|
|
|
int bus = cam_sim_bus(sim);
|
2003-08-24 09:22:26 +00:00
|
|
|
int len;
|
2002-08-09 20:54:06 +00:00
|
|
|
char *buf;
|
|
|
|
|
|
|
|
switch (ccb_h->func_code) {
|
|
|
|
case XPT_PATH_INQ: {
|
|
|
|
struct ccb_pathinq *cpi = &ccb->cpi;
|
2005-04-05 02:03:31 +00:00
|
|
|
int tid = ccb_h->target_id;
|
2002-08-09 20:54:06 +00:00
|
|
|
|
|
|
|
cpi->version_num = 1;
|
|
|
|
cpi->hba_inquiry = 0;
|
2003-02-27 20:56:56 +00:00
|
|
|
cpi->target_sprt = 0;
|
2003-07-28 06:15:59 +00:00
|
|
|
cpi->hba_misc = PIM_NO_6_BYTE;
|
2002-08-09 20:54:06 +00:00
|
|
|
cpi->hba_eng_cnt = 0;
|
|
|
|
bzero(cpi->vuhba_flags, sizeof(cpi->vuhba_flags));
|
|
|
|
cpi->max_target = 1;
|
2002-08-10 11:56:03 +00:00
|
|
|
cpi->max_lun = 0;
|
2002-08-09 20:54:06 +00:00
|
|
|
cpi->async_flags = 0;
|
|
|
|
cpi->hpath_id = 0;
|
|
|
|
cpi->initiator_id = 7;
|
2002-08-10 11:56:03 +00:00
|
|
|
strncpy(cpi->sim_vid, "FreeBSD", sizeof(cpi->sim_vid));
|
2002-08-09 20:54:06 +00:00
|
|
|
strncpy(cpi->hba_vid, "ATAPI", sizeof(cpi->hba_vid));
|
|
|
|
strncpy(cpi->dev_name, cam_sim_name(sim), sizeof cpi->dev_name);
|
|
|
|
cpi->unit_number = cam_sim_unit(sim);
|
|
|
|
cpi->bus_id = cam_sim_bus(sim);
|
2003-09-11 17:34:47 +00:00
|
|
|
cpi->base_transfer_speed = 3300;
|
Separate the parallel scsi knowledge out of the core of the XPT, and
modularize it so that new transports can be created.
Add a transport for SATA
Add a periph+protocol layer for ATA
Add a driver for AHCI-compliant hardware.
Add a maxio field to CAM so that drivers can advertise their max
I/O capability. Modify various drivers so that they are insulated
from the value of MAXPHYS.
The new ATA/SATA code supports AHCI-compliant hardware, and will override
the classic ATA driver if it is loaded as a module at boot time or compiled
into the kernel. The stack now support NCQ (tagged queueing) for increased
performance on modern SATA drives. It also supports port multipliers.
ATA drives are accessed via 'ada' device nodes. ATAPI drives are
accessed via 'cd' device nodes. They can all be enumerated and manipulated
via camcontrol, just like SCSI drives. SCSI commands are not translated to
their ATA equivalents; ATA native commands are used throughout the entire
stack, including camcontrol. See the camcontrol manpage for further
details. Testing this code may require that you update your fstab, and
possibly modify your BIOS to enable AHCI functionality, if available.
This code is very experimental at the moment. The userland ABI/API has
changed, so applications will need to be recompiled. It may change
further in the near future. The 'ada' device name may also change as
more infrastructure is completed in this project. The goal is to
eventually put all CAM busses and devices until newbus, allowing for
interesting topology and management options.
Few functional changes will be seen with existing SCSI/SAS/FC drivers,
though the userland ABI has still changed. In the future, transports
specific modules for SAS and FC may appear in order to better support
the topologies and capabilities of these technologies.
The modularization of CAM and the addition of the ATA/SATA modules is
meant to break CAM out of the mold of being specific to SCSI, letting it
grow to be a framework for arbitrary transports and protocols. It also
allows drivers to be written to support discrete hardware without
jeopardizing the stability of non-related hardware. While only an AHCI
driver is provided now, a Silicon Image driver is also in the works.
Drivers for ICH1-4, ICH5-6, PIIX, classic IDE, and any other hardware
is possible and encouraged. Help with new transports is also encouraged.
Submitted by: scottl, mav
Approved by: re
2009-07-10 08:18:08 +00:00
|
|
|
cpi->transport = XPORT_SPI;
|
2006-10-31 05:53:29 +00:00
|
|
|
cpi->transport_version = 2;
|
|
|
|
cpi->protocol = PROTO_SCSI;
|
|
|
|
cpi->protocol_version = SCSI_REV_2;
|
2003-09-11 17:34:47 +00:00
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
if (softc->ata_ch && tid != CAM_TARGET_WILDCARD) {
|
|
|
|
if (softc->atadev[tid] == NULL) {
|
|
|
|
ccb->ccb_h.status = CAM_DEV_NOT_THERE;
|
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (softc->atadev[ccb_h->target_id]->mode) {
|
2002-08-09 20:54:06 +00:00
|
|
|
case ATA_PIO1:
|
|
|
|
cpi->base_transfer_speed = 5200;
|
|
|
|
break;
|
|
|
|
case ATA_PIO2:
|
|
|
|
cpi->base_transfer_speed = 7000;
|
|
|
|
break;
|
|
|
|
case ATA_PIO3:
|
|
|
|
cpi->base_transfer_speed = 11000;
|
|
|
|
break;
|
|
|
|
case ATA_PIO4:
|
|
|
|
case ATA_DMA:
|
|
|
|
case ATA_WDMA2:
|
|
|
|
cpi->base_transfer_speed = 16000;
|
|
|
|
break;
|
|
|
|
case ATA_UDMA2:
|
|
|
|
cpi->base_transfer_speed = 33000;
|
|
|
|
break;
|
|
|
|
case ATA_UDMA4:
|
|
|
|
cpi->base_transfer_speed = 66000;
|
|
|
|
break;
|
|
|
|
case ATA_UDMA5:
|
|
|
|
cpi->base_transfer_speed = 100000;
|
|
|
|
break;
|
|
|
|
case ATA_UDMA6:
|
|
|
|
cpi->base_transfer_speed = 133000;
|
|
|
|
break;
|
2009-10-26 11:26:49 +00:00
|
|
|
case ATA_SA150:
|
|
|
|
cpi->base_transfer_speed = 150000;
|
|
|
|
break;
|
|
|
|
case ATA_SA300:
|
|
|
|
cpi->base_transfer_speed = 300000;
|
|
|
|
break;
|
2003-09-11 17:34:47 +00:00
|
|
|
default:
|
|
|
|
break;
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
}
|
Separate the parallel scsi knowledge out of the core of the XPT, and
modularize it so that new transports can be created.
Add a transport for SATA
Add a periph+protocol layer for ATA
Add a driver for AHCI-compliant hardware.
Add a maxio field to CAM so that drivers can advertise their max
I/O capability. Modify various drivers so that they are insulated
from the value of MAXPHYS.
The new ATA/SATA code supports AHCI-compliant hardware, and will override
the classic ATA driver if it is loaded as a module at boot time or compiled
into the kernel. The stack now support NCQ (tagged queueing) for increased
performance on modern SATA drives. It also supports port multipliers.
ATA drives are accessed via 'ada' device nodes. ATAPI drives are
accessed via 'cd' device nodes. They can all be enumerated and manipulated
via camcontrol, just like SCSI drives. SCSI commands are not translated to
their ATA equivalents; ATA native commands are used throughout the entire
stack, including camcontrol. See the camcontrol manpage for further
details. Testing this code may require that you update your fstab, and
possibly modify your BIOS to enable AHCI functionality, if available.
This code is very experimental at the moment. The userland ABI/API has
changed, so applications will need to be recompiled. It may change
further in the near future. The 'ada' device name may also change as
more infrastructure is completed in this project. The goal is to
eventually put all CAM busses and devices until newbus, allowing for
interesting topology and management options.
Few functional changes will be seen with existing SCSI/SAS/FC drivers,
though the userland ABI has still changed. In the future, transports
specific modules for SAS and FC may appear in order to better support
the topologies and capabilities of these technologies.
The modularization of CAM and the addition of the ATA/SATA modules is
meant to break CAM out of the mold of being specific to SCSI, letting it
grow to be a framework for arbitrary transports and protocols. It also
allows drivers to be written to support discrete hardware without
jeopardizing the stability of non-related hardware. While only an AHCI
driver is provided now, a Silicon Image driver is also in the works.
Drivers for ICH1-4, ICH5-6, PIIX, classic IDE, and any other hardware
is possible and encouraged. Help with new transports is also encouraged.
Submitted by: scottl, mav
Approved by: re
2009-07-10 08:18:08 +00:00
|
|
|
cpi->maxio = softc->ata_ch->dma.max_iosize ?
|
|
|
|
softc->ata_ch->dma.max_iosize : DFLTPHYS;
|
2002-08-09 20:54:06 +00:00
|
|
|
ccb->ccb_h.status = CAM_REQ_CMP;
|
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-10-22 20:18:51 +00:00
|
|
|
case XPT_RESET_DEV: {
|
|
|
|
int tid = ccb_h->target_id;
|
|
|
|
|
2002-08-28 07:03:44 +00:00
|
|
|
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE, ("dev reset\n"));
|
2007-05-02 15:30:24 +00:00
|
|
|
mtx_unlock(&softc->state_lock);
|
2005-05-16 13:07:27 +00:00
|
|
|
ata_controlcmd(softc->atadev[tid]->dev, ATA_DEVICE_RESET, 0, 0, 0);
|
2007-05-02 15:30:24 +00:00
|
|
|
mtx_lock(&softc->state_lock);
|
2002-08-09 20:54:06 +00:00
|
|
|
ccb->ccb_h.status = CAM_REQ_CMP;
|
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
2002-10-22 20:18:51 +00:00
|
|
|
}
|
2002-08-09 20:54:06 +00:00
|
|
|
|
|
|
|
case XPT_RESET_BUS:
|
2002-08-28 07:03:44 +00:00
|
|
|
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE, ("bus reset\n"));
|
2007-05-02 15:30:24 +00:00
|
|
|
mtx_unlock(&softc->state_lock);
|
2005-04-05 02:03:31 +00:00
|
|
|
ata_reinit(softc->parent);
|
2007-05-02 15:30:24 +00:00
|
|
|
mtx_lock(&softc->state_lock);
|
2002-08-09 20:54:06 +00:00
|
|
|
ccb->ccb_h.status = CAM_REQ_CMP;
|
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case XPT_SET_TRAN_SETTINGS:
|
|
|
|
/* ignore these, we're not doing SCSI here */
|
2002-08-28 07:03:44 +00:00
|
|
|
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE,
|
|
|
|
("SET_TRAN_SETTINGS not supported\n"));
|
2002-08-10 19:48:27 +00:00
|
|
|
ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
|
2002-08-09 20:54:06 +00:00
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case XPT_GET_TRAN_SETTINGS: {
|
|
|
|
struct ccb_trans_settings *cts = &ccb->cts;
|
2006-10-31 05:53:29 +00:00
|
|
|
cts->protocol = PROTO_SCSI;
|
|
|
|
cts->protocol_version = SCSI_REV_2;
|
Separate the parallel scsi knowledge out of the core of the XPT, and
modularize it so that new transports can be created.
Add a transport for SATA
Add a periph+protocol layer for ATA
Add a driver for AHCI-compliant hardware.
Add a maxio field to CAM so that drivers can advertise their max
I/O capability. Modify various drivers so that they are insulated
from the value of MAXPHYS.
The new ATA/SATA code supports AHCI-compliant hardware, and will override
the classic ATA driver if it is loaded as a module at boot time or compiled
into the kernel. The stack now support NCQ (tagged queueing) for increased
performance on modern SATA drives. It also supports port multipliers.
ATA drives are accessed via 'ada' device nodes. ATAPI drives are
accessed via 'cd' device nodes. They can all be enumerated and manipulated
via camcontrol, just like SCSI drives. SCSI commands are not translated to
their ATA equivalents; ATA native commands are used throughout the entire
stack, including camcontrol. See the camcontrol manpage for further
details. Testing this code may require that you update your fstab, and
possibly modify your BIOS to enable AHCI functionality, if available.
This code is very experimental at the moment. The userland ABI/API has
changed, so applications will need to be recompiled. It may change
further in the near future. The 'ada' device name may also change as
more infrastructure is completed in this project. The goal is to
eventually put all CAM busses and devices until newbus, allowing for
interesting topology and management options.
Few functional changes will be seen with existing SCSI/SAS/FC drivers,
though the userland ABI has still changed. In the future, transports
specific modules for SAS and FC may appear in order to better support
the topologies and capabilities of these technologies.
The modularization of CAM and the addition of the ATA/SATA modules is
meant to break CAM out of the mold of being specific to SCSI, letting it
grow to be a framework for arbitrary transports and protocols. It also
allows drivers to be written to support discrete hardware without
jeopardizing the stability of non-related hardware. While only an AHCI
driver is provided now, a Silicon Image driver is also in the works.
Drivers for ICH1-4, ICH5-6, PIIX, classic IDE, and any other hardware
is possible and encouraged. Help with new transports is also encouraged.
Submitted by: scottl, mav
Approved by: re
2009-07-10 08:18:08 +00:00
|
|
|
cts->transport = XPORT_SPI;
|
2006-10-31 05:53:29 +00:00
|
|
|
cts->transport_version = XPORT_VERSION_UNSPECIFIED;
|
|
|
|
cts->proto_specific.valid = 0;
|
|
|
|
cts->xport_specific.valid = 0;
|
|
|
|
/* nothing more to do */
|
2002-08-09 20:54:06 +00:00
|
|
|
ccb->ccb_h.status = CAM_REQ_CMP;
|
2006-10-31 05:53:29 +00:00
|
|
|
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE, ("GET_TRAN_SETTINGS\n"));
|
2002-08-09 20:54:06 +00:00
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case XPT_CALC_GEOMETRY: {
|
2002-08-28 07:03:44 +00:00
|
|
|
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE, ("CALC_GEOMETRY\n"));
|
2003-06-14 22:17:41 +00:00
|
|
|
cam_calc_geometry(&ccb->ccg, /*extended*/1);
|
2002-08-09 20:54:06 +00:00
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case XPT_SCSI_IO: {
|
|
|
|
struct ccb_scsiio *csio = &ccb->csio;
|
|
|
|
int tid = ccb_h->target_id, lid = ccb_h->target_lun;
|
2007-03-13 20:42:49 +00:00
|
|
|
int request_flags = ATA_R_ATAPI;
|
2002-08-09 20:54:06 +00:00
|
|
|
|
2002-08-28 07:03:44 +00:00
|
|
|
CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE, ("XPT_SCSI_IO\n"));
|
2002-08-09 20:54:06 +00:00
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
if (softc->flags & DETACHING) {
|
|
|
|
ccb->ccb_h.status = CAM_REQ_ABORTED;
|
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-04-30 16:22:07 +00:00
|
|
|
if (softc->atadev[tid] == NULL) {
|
2005-04-05 02:03:31 +00:00
|
|
|
ccb->ccb_h.status = CAM_DEV_NOT_THERE;
|
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-08-09 20:54:06 +00:00
|
|
|
/* check that this request was not aborted already */
|
|
|
|
if ((ccb_h->status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
|
2002-08-28 07:03:44 +00:00
|
|
|
printf("XPT_SCSI_IO received but already in progress?\n");
|
2002-08-09 20:54:06 +00:00
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (lid > 0) {
|
2002-08-28 07:03:44 +00:00
|
|
|
CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE,
|
|
|
|
("SCSI IO received for invalid lun %d\n", lid));
|
2003-08-24 09:22:26 +00:00
|
|
|
goto action_invalid;
|
|
|
|
}
|
|
|
|
if (csio->cdb_len > sizeof request->u.atapi.ccb) {
|
|
|
|
CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE,
|
|
|
|
("CAM CCB too long for ATAPI"));
|
|
|
|
goto action_invalid;
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
if ((ccb_h->flags & CAM_SCATTER_VALID)) {
|
|
|
|
/* scatter-gather not supported */
|
|
|
|
xpt_print_path(ccb_h->path);
|
2003-08-24 09:22:26 +00:00
|
|
|
printf("ATAPI/CAM does not support scatter-gather yet!\n");
|
2003-09-19 16:25:44 +00:00
|
|
|
goto action_invalid;
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
2003-08-24 09:22:26 +00:00
|
|
|
|
2003-09-19 16:25:44 +00:00
|
|
|
switch (ccb_h->flags & CAM_DIR_MASK) {
|
|
|
|
case CAM_DIR_IN:
|
2007-04-30 09:33:57 +00:00
|
|
|
request_flags |= ATA_R_READ;
|
2003-09-19 16:25:44 +00:00
|
|
|
break;
|
|
|
|
case CAM_DIR_OUT:
|
2007-04-30 09:33:57 +00:00
|
|
|
request_flags |= ATA_R_WRITE;
|
2003-09-19 16:25:44 +00:00
|
|
|
break;
|
|
|
|
case CAM_DIR_NONE:
|
2003-12-05 01:02:46 +00:00
|
|
|
/* No flags need to be set */
|
2003-09-19 16:25:44 +00:00
|
|
|
break;
|
|
|
|
default:
|
2005-04-05 02:03:31 +00:00
|
|
|
device_printf(softc->dev, "unknown IO operation\n");
|
2003-09-19 16:25:44 +00:00
|
|
|
goto action_invalid;
|
2003-09-24 18:40:10 +00:00
|
|
|
}
|
2003-09-19 16:25:44 +00:00
|
|
|
|
2003-08-24 09:22:26 +00:00
|
|
|
if ((hcb = allocate_hcb(softc, unit, bus, ccb)) == NULL) {
|
|
|
|
printf("cannot allocate ATAPI/CAM hcb\n");
|
2002-08-09 20:54:06 +00:00
|
|
|
goto action_oom;
|
2003-08-24 09:22:26 +00:00
|
|
|
}
|
2008-04-17 12:29:35 +00:00
|
|
|
if ((request = ata_alloc_request()) == NULL) {
|
2003-08-24 09:22:26 +00:00
|
|
|
printf("cannot allocate ATAPI/CAM request\n");
|
|
|
|
goto action_oom;
|
|
|
|
}
|
2002-08-09 20:54:06 +00:00
|
|
|
|
|
|
|
bcopy((ccb_h->flags & CAM_CDB_POINTER) ?
|
|
|
|
csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes,
|
2003-08-24 09:22:26 +00:00
|
|
|
request->u.atapi.ccb, csio->cdb_len);
|
2002-08-09 20:54:06 +00:00
|
|
|
#ifdef CAMDEBUG
|
2002-08-28 07:03:44 +00:00
|
|
|
if (CAM_DEBUGGED(ccb_h->path, CAM_DEBUG_CDB)) {
|
|
|
|
char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
|
|
|
|
|
|
|
|
printf("atapi_action: hcb@%p: %s\n", hcb,
|
2003-08-24 09:22:26 +00:00
|
|
|
scsi_cdb_string(request->u.atapi.ccb, cdb_str, sizeof(cdb_str)));
|
2002-08-28 07:03:44 +00:00
|
|
|
}
|
2007-03-13 20:42:49 +00:00
|
|
|
if (CAM_DEBUGGED(ccb_h->path, CAM_DEBUG_SUBTRACE)) {
|
|
|
|
request_flags |= ATA_R_DEBUG;
|
|
|
|
}
|
2002-08-09 20:54:06 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
len = csio->dxfer_len;
|
|
|
|
buf = csio->data_ptr;
|
|
|
|
|
|
|
|
/* some SCSI commands require special processing */
|
2003-08-24 09:22:26 +00:00
|
|
|
switch (request->u.atapi.ccb[0]) {
|
2002-08-09 20:54:06 +00:00
|
|
|
case INQUIRY: {
|
|
|
|
/*
|
|
|
|
* many ATAPI devices seem to report more than
|
|
|
|
* SHORT_INQUIRY_LENGTH bytes of available INQUIRY
|
|
|
|
* information, but respond with some incorrect condition
|
|
|
|
* when actually asked for it, so we are going to pretend
|
|
|
|
* that only SHORT_INQUIRY_LENGTH are expected, anyway.
|
|
|
|
*/
|
2003-08-24 09:22:26 +00:00
|
|
|
struct scsi_inquiry *inq = (struct scsi_inquiry *) &request->u.atapi.ccb[0];
|
2002-08-09 20:54:06 +00:00
|
|
|
|
|
|
|
if (inq->byte2 == 0 && inq->page_code == 0 &&
|
Add the CAM Target Layer (CTL).
CTL is a disk and processor device emulation subsystem originally written
for Copan Systems under Linux starting in 2003. It has been shipping in
Copan (now SGI) products since 2005.
It was ported to FreeBSD in 2008, and thanks to an agreement between SGI
(who acquired Copan's assets in 2010) and Spectra Logic in 2010, CTL is
available under a BSD-style license. The intent behind the agreement was
that Spectra would work to get CTL into the FreeBSD tree.
Some CTL features:
- Disk and processor device emulation.
- Tagged queueing
- SCSI task attribute support (ordered, head of queue, simple tags)
- SCSI implicit command ordering support. (e.g. if a read follows a mode
select, the read will be blocked until the mode select completes.)
- Full task management support (abort, LUN reset, target reset, etc.)
- Support for multiple ports
- Support for multiple simultaneous initiators
- Support for multiple simultaneous backing stores
- Persistent reservation support
- Mode sense/select support
- Error injection support
- High Availability support (1)
- All I/O handled in-kernel, no userland context switch overhead.
(1) HA Support is just an API stub, and needs much more to be fully
functional.
ctl.c: The core of CTL. Command handlers and processing,
character driver, and HA support are here.
ctl.h: Basic function declarations and data structures.
ctl_backend.c,
ctl_backend.h: The basic CTL backend API.
ctl_backend_block.c,
ctl_backend_block.h: The block and file backend. This allows for using
a disk or a file as the backing store for a LUN.
Multiple threads are started to do I/O to the
backing device, primarily because the VFS API
requires that to get any concurrency.
ctl_backend_ramdisk.c: A "fake" ramdisk backend. It only allocates a
small amount of memory to act as a source and sink
for reads and writes from an initiator. Therefore
it cannot be used for any real data, but it can be
used to test for throughput. It can also be used
to test initiators' support for extremely large LUNs.
ctl_cmd_table.c: This is a table with all 256 possible SCSI opcodes,
and command handler functions defined for supported
opcodes.
ctl_debug.h: Debugging support.
ctl_error.c,
ctl_error.h: CTL-specific wrappers around the CAM sense building
functions.
ctl_frontend.c,
ctl_frontend.h: These files define the basic CTL frontend port API.
ctl_frontend_cam_sim.c: This is a CTL frontend port that is also a CAM SIM.
This frontend allows for using CTL without any
target-capable hardware. So any LUNs you create in
CTL are visible in CAM via this port.
ctl_frontend_internal.c,
ctl_frontend_internal.h:
This is a frontend port written for Copan to do
some system-specific tasks that required sending
commands into CTL from inside the kernel. This
isn't entirely relevant to FreeBSD in general,
but can perhaps be repurposed.
ctl_ha.h: This is a stubbed-out High Availability API. Much
more is needed for full HA support. See the
comments in the header and the description of what
is needed in the README.ctl.txt file for more
details.
ctl_io.h: This defines most of the core CTL I/O structures.
union ctl_io is conceptually very similar to CAM's
union ccb.
ctl_ioctl.h: This defines all ioctls available through the CTL
character device, and the data structures needed
for those ioctls.
ctl_mem_pool.c,
ctl_mem_pool.h: Generic memory pool implementation used by the
internal frontend.
ctl_private.h: Private data structres (e.g. CTL softc) and
function prototypes. This also includes the SCSI
vendor and product names used by CTL.
ctl_scsi_all.c,
ctl_scsi_all.h: CTL wrappers around CAM sense printing functions.
ctl_ser_table.c: Command serialization table. This defines what
happens when one type of command is followed by
another type of command.
ctl_util.c,
ctl_util.h: CTL utility functions, primarily designed to be
used from userland. See ctladm for the primary
consumer of these functions. These include CDB
building functions.
scsi_ctl.c: CAM target peripheral driver and CTL frontend port.
This is the path into CTL for commands from
target-capable hardware/SIMs.
README.ctl.txt: CTL code features, roadmap, to-do list.
usr.sbin/Makefile: Add ctladm.
ctladm/Makefile,
ctladm/ctladm.8,
ctladm/ctladm.c,
ctladm/ctladm.h,
ctladm/util.c: ctladm(8) is the CTL management utility.
It fills a role similar to camcontrol(8).
It allow configuring LUNs, issuing commands,
injecting errors and various other control
functions.
usr.bin/Makefile: Add ctlstat.
ctlstat/Makefile
ctlstat/ctlstat.8,
ctlstat/ctlstat.c: ctlstat(8) fills a role similar to iostat(8).
It reports I/O statistics for CTL.
sys/conf/files: Add CTL files.
sys/conf/NOTES: Add device ctl.
sys/cam/scsi_all.h: To conform to more recent specs, the inquiry CDB
length field is now 2 bytes long.
Add several mode page definitions for CTL.
sys/cam/scsi_all.c: Handle the new 2 byte inquiry length.
sys/dev/ciss/ciss.c,
sys/dev/ata/atapi-cam.c,
sys/cam/scsi/scsi_targ_bh.c,
scsi_target/scsi_cmds.c,
mlxcontrol/interface.c: Update for 2 byte inquiry length field.
scsi_da.h: Add versions of the format and rigid disk pages
that are in a more reasonable format for CTL.
amd64/conf/GENERIC,
i386/conf/GENERIC,
ia64/conf/GENERIC,
sparc64/conf/GENERIC: Add device ctl.
i386/conf/PAE: The CTL frontend SIM at least does not compile
cleanly on PAE.
Sponsored by: Copan Systems, SGI and Spectra Logic
MFC after: 1 month
2012-01-12 00:34:33 +00:00
|
|
|
scsi_2btoul(inq->length) > SHORT_INQUIRY_LENGTH) {
|
2002-08-09 20:54:06 +00:00
|
|
|
bzero(buf, len);
|
Add the CAM Target Layer (CTL).
CTL is a disk and processor device emulation subsystem originally written
for Copan Systems under Linux starting in 2003. It has been shipping in
Copan (now SGI) products since 2005.
It was ported to FreeBSD in 2008, and thanks to an agreement between SGI
(who acquired Copan's assets in 2010) and Spectra Logic in 2010, CTL is
available under a BSD-style license. The intent behind the agreement was
that Spectra would work to get CTL into the FreeBSD tree.
Some CTL features:
- Disk and processor device emulation.
- Tagged queueing
- SCSI task attribute support (ordered, head of queue, simple tags)
- SCSI implicit command ordering support. (e.g. if a read follows a mode
select, the read will be blocked until the mode select completes.)
- Full task management support (abort, LUN reset, target reset, etc.)
- Support for multiple ports
- Support for multiple simultaneous initiators
- Support for multiple simultaneous backing stores
- Persistent reservation support
- Mode sense/select support
- Error injection support
- High Availability support (1)
- All I/O handled in-kernel, no userland context switch overhead.
(1) HA Support is just an API stub, and needs much more to be fully
functional.
ctl.c: The core of CTL. Command handlers and processing,
character driver, and HA support are here.
ctl.h: Basic function declarations and data structures.
ctl_backend.c,
ctl_backend.h: The basic CTL backend API.
ctl_backend_block.c,
ctl_backend_block.h: The block and file backend. This allows for using
a disk or a file as the backing store for a LUN.
Multiple threads are started to do I/O to the
backing device, primarily because the VFS API
requires that to get any concurrency.
ctl_backend_ramdisk.c: A "fake" ramdisk backend. It only allocates a
small amount of memory to act as a source and sink
for reads and writes from an initiator. Therefore
it cannot be used for any real data, but it can be
used to test for throughput. It can also be used
to test initiators' support for extremely large LUNs.
ctl_cmd_table.c: This is a table with all 256 possible SCSI opcodes,
and command handler functions defined for supported
opcodes.
ctl_debug.h: Debugging support.
ctl_error.c,
ctl_error.h: CTL-specific wrappers around the CAM sense building
functions.
ctl_frontend.c,
ctl_frontend.h: These files define the basic CTL frontend port API.
ctl_frontend_cam_sim.c: This is a CTL frontend port that is also a CAM SIM.
This frontend allows for using CTL without any
target-capable hardware. So any LUNs you create in
CTL are visible in CAM via this port.
ctl_frontend_internal.c,
ctl_frontend_internal.h:
This is a frontend port written for Copan to do
some system-specific tasks that required sending
commands into CTL from inside the kernel. This
isn't entirely relevant to FreeBSD in general,
but can perhaps be repurposed.
ctl_ha.h: This is a stubbed-out High Availability API. Much
more is needed for full HA support. See the
comments in the header and the description of what
is needed in the README.ctl.txt file for more
details.
ctl_io.h: This defines most of the core CTL I/O structures.
union ctl_io is conceptually very similar to CAM's
union ccb.
ctl_ioctl.h: This defines all ioctls available through the CTL
character device, and the data structures needed
for those ioctls.
ctl_mem_pool.c,
ctl_mem_pool.h: Generic memory pool implementation used by the
internal frontend.
ctl_private.h: Private data structres (e.g. CTL softc) and
function prototypes. This also includes the SCSI
vendor and product names used by CTL.
ctl_scsi_all.c,
ctl_scsi_all.h: CTL wrappers around CAM sense printing functions.
ctl_ser_table.c: Command serialization table. This defines what
happens when one type of command is followed by
another type of command.
ctl_util.c,
ctl_util.h: CTL utility functions, primarily designed to be
used from userland. See ctladm for the primary
consumer of these functions. These include CDB
building functions.
scsi_ctl.c: CAM target peripheral driver and CTL frontend port.
This is the path into CTL for commands from
target-capable hardware/SIMs.
README.ctl.txt: CTL code features, roadmap, to-do list.
usr.sbin/Makefile: Add ctladm.
ctladm/Makefile,
ctladm/ctladm.8,
ctladm/ctladm.c,
ctladm/ctladm.h,
ctladm/util.c: ctladm(8) is the CTL management utility.
It fills a role similar to camcontrol(8).
It allow configuring LUNs, issuing commands,
injecting errors and various other control
functions.
usr.bin/Makefile: Add ctlstat.
ctlstat/Makefile
ctlstat/ctlstat.8,
ctlstat/ctlstat.c: ctlstat(8) fills a role similar to iostat(8).
It reports I/O statistics for CTL.
sys/conf/files: Add CTL files.
sys/conf/NOTES: Add device ctl.
sys/cam/scsi_all.h: To conform to more recent specs, the inquiry CDB
length field is now 2 bytes long.
Add several mode page definitions for CTL.
sys/cam/scsi_all.c: Handle the new 2 byte inquiry length.
sys/dev/ciss/ciss.c,
sys/dev/ata/atapi-cam.c,
sys/cam/scsi/scsi_targ_bh.c,
scsi_target/scsi_cmds.c,
mlxcontrol/interface.c: Update for 2 byte inquiry length field.
scsi_da.h: Add versions of the format and rigid disk pages
that are in a more reasonable format for CTL.
amd64/conf/GENERIC,
i386/conf/GENERIC,
ia64/conf/GENERIC,
sparc64/conf/GENERIC: Add device ctl.
i386/conf/PAE: The CTL frontend SIM at least does not compile
cleanly on PAE.
Sponsored by: Copan Systems, SGI and Spectra Logic
MFC after: 1 month
2012-01-12 00:34:33 +00:00
|
|
|
len = SHORT_INQUIRY_LENGTH;
|
|
|
|
scsi_ulto2b(len, inq->length);
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case READ_6:
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
|
|
|
|
case WRITE_6:
|
2003-08-24 09:22:26 +00:00
|
|
|
CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE,
|
2002-08-28 07:03:44 +00:00
|
|
|
("Translating %s into _10 equivalent\n",
|
2003-08-24 09:22:26 +00:00
|
|
|
(request->u.atapi.ccb[0] == READ_6) ? "READ_6" : "WRITE_6"));
|
|
|
|
request->u.atapi.ccb[0] |= 0x20;
|
|
|
|
request->u.atapi.ccb[9] = request->u.atapi.ccb[5];
|
|
|
|
request->u.atapi.ccb[8] = request->u.atapi.ccb[4];
|
|
|
|
request->u.atapi.ccb[7] = 0;
|
|
|
|
request->u.atapi.ccb[6] = 0;
|
|
|
|
request->u.atapi.ccb[5] = request->u.atapi.ccb[3];
|
|
|
|
request->u.atapi.ccb[4] = request->u.atapi.ccb[2];
|
|
|
|
request->u.atapi.ccb[3] = request->u.atapi.ccb[1] & 0x1f;
|
|
|
|
request->u.atapi.ccb[2] = 0;
|
|
|
|
request->u.atapi.ccb[1] = 0;
|
2007-04-30 09:33:57 +00:00
|
|
|
/* FALLTHROUGH */
|
|
|
|
|
|
|
|
case READ_10:
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case WRITE_10:
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case READ_12:
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case WRITE_12:
|
|
|
|
/*
|
|
|
|
* Enable DMA (if target supports it) for READ and WRITE commands
|
|
|
|
* only, as some combinations of drive, controller and chipset do
|
|
|
|
* not behave correctly when DMA is enabled for other commands.
|
|
|
|
*/
|
|
|
|
if (softc->atadev[tid]->mode >= ATA_DMA)
|
|
|
|
request_flags |= ATA_R_DMA;
|
2002-08-09 20:54:06 +00:00
|
|
|
break;
|
2007-04-30 09:33:57 +00:00
|
|
|
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN && (len & 1)) {
|
|
|
|
/* ATA always transfers an even number of bytes */
|
2003-09-19 16:25:44 +00:00
|
|
|
if ((buf = hcb->dxfer_alloc
|
2005-04-30 16:22:07 +00:00
|
|
|
= malloc(++len, M_ATACAM, M_NOWAIT | M_ZERO)) == NULL) {
|
2003-08-24 09:22:26 +00:00
|
|
|
printf("cannot allocate ATAPI/CAM buffer\n");
|
2002-08-09 20:54:06 +00:00
|
|
|
goto action_oom;
|
2003-08-28 03:56:04 +00:00
|
|
|
}
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
2008-04-17 12:29:35 +00:00
|
|
|
request->dev = softc->atadev[tid]->dev;
|
2003-08-24 09:22:26 +00:00
|
|
|
request->driver = hcb;
|
|
|
|
request->data = buf;
|
|
|
|
request->bytecount = len;
|
|
|
|
request->transfersize = min(request->bytecount, 65534);
|
2009-10-26 11:23:41 +00:00
|
|
|
request->timeout = (ccb_h->timeout + 999) / 1000;
|
2003-08-24 09:22:26 +00:00
|
|
|
request->callback = &atapi_cb;
|
2003-09-19 16:25:44 +00:00
|
|
|
request->flags = request_flags;
|
2003-08-24 09:22:26 +00:00
|
|
|
|
2007-03-13 20:42:49 +00:00
|
|
|
/*
|
|
|
|
* no retries are to be performed at the ATA level; any retries
|
2007-04-30 09:26:43 +00:00
|
|
|
* will be done by CAM.
|
2007-03-13 20:42:49 +00:00
|
|
|
*/
|
|
|
|
request->retries = 0;
|
|
|
|
|
2002-08-09 20:54:06 +00:00
|
|
|
TAILQ_INSERT_TAIL(&softc->pending_hcbs, hcb, chain);
|
2003-09-19 16:25:44 +00:00
|
|
|
hcb->flags |= QUEUED;
|
|
|
|
ccb_h->status |= CAM_SIM_QUEUED;
|
2005-04-05 02:03:31 +00:00
|
|
|
mtx_unlock(&softc->state_lock);
|
2003-08-24 09:22:26 +00:00
|
|
|
|
|
|
|
ata_queue_request(request);
|
2007-05-02 15:30:24 +00:00
|
|
|
mtx_lock(&softc->state_lock);
|
2003-08-24 09:22:26 +00:00
|
|
|
return;
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2002-08-28 07:03:44 +00:00
|
|
|
CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE,
|
|
|
|
("unsupported function code 0x%02x\n", ccb_h->func_code));
|
2003-08-24 09:22:26 +00:00
|
|
|
goto action_invalid;
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
|
2003-09-19 16:25:44 +00:00
|
|
|
/* NOTREACHED */
|
|
|
|
|
2002-08-09 20:54:06 +00:00
|
|
|
action_oom:
|
2003-08-24 09:22:26 +00:00
|
|
|
if (request != NULL)
|
|
|
|
ata_free_request(request);
|
2002-08-09 20:54:06 +00:00
|
|
|
if (hcb != NULL)
|
|
|
|
free_hcb(hcb);
|
|
|
|
xpt_print_path(ccb_h->path);
|
2002-08-28 07:03:44 +00:00
|
|
|
printf("out of memory, freezing queue.\n");
|
2002-08-09 20:54:06 +00:00
|
|
|
softc->flags |= RESOURCE_SHORTAGE;
|
|
|
|
xpt_freeze_simq(sim, /*count*/ 1);
|
|
|
|
ccb_h->status = CAM_REQUEUE_REQ;
|
|
|
|
xpt_done(ccb);
|
2003-08-24 09:22:26 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
action_invalid:
|
2003-09-19 16:25:44 +00:00
|
|
|
ccb_h->status = CAM_REQ_INVALID;
|
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
|
2003-08-24 09:22:26 +00:00
|
|
|
static void
|
2002-08-09 20:54:06 +00:00
|
|
|
atapi_poll(struct cam_sim *sim)
|
|
|
|
{
|
2010-02-03 21:45:09 +00:00
|
|
|
struct atapi_xpt_softc *softc =
|
|
|
|
(struct atapi_xpt_softc*)cam_sim_softc(sim);
|
|
|
|
|
|
|
|
mtx_unlock(&softc->state_lock);
|
|
|
|
ata_interrupt(softc->ata_ch);
|
|
|
|
mtx_lock(&softc->state_lock);
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
|
2003-08-24 09:22:26 +00:00
|
|
|
static void
|
|
|
|
atapi_cb(struct ata_request *request)
|
2002-08-09 20:54:06 +00:00
|
|
|
{
|
2005-04-05 15:08:19 +00:00
|
|
|
struct atapi_xpt_softc *scp;
|
2003-11-09 20:46:08 +00:00
|
|
|
struct atapi_hcb *hcb;
|
|
|
|
struct ccb_scsiio *csio;
|
2003-09-21 16:49:53 +00:00
|
|
|
u_int32_t rc;
|
2003-08-24 09:22:26 +00:00
|
|
|
|
2003-11-09 20:46:08 +00:00
|
|
|
hcb = (struct atapi_hcb *)request->driver;
|
2005-04-05 15:08:19 +00:00
|
|
|
scp = hcb->softc;
|
2003-11-09 20:46:08 +00:00
|
|
|
csio = &hcb->ccb->csio;
|
|
|
|
|
2005-04-05 15:08:19 +00:00
|
|
|
#ifdef CAMDEBUG
|
2006-03-31 08:09:05 +00:00
|
|
|
# define err (request->u.atapi.sense.key)
|
2003-09-21 16:49:53 +00:00
|
|
|
if (CAM_DEBUGGED(csio->ccb_h.path, CAM_DEBUG_CDB)) {
|
2007-03-13 20:42:49 +00:00
|
|
|
printf("atapi_cb: hcb@%p sense = %02x: sk = %01x%s%s%s\n",
|
|
|
|
hcb, err, err & 0x0f,
|
|
|
|
(err & 0x80) ? ", Filemark" : "",
|
|
|
|
(err & 0x40) ? ", EOM" : "",
|
|
|
|
(err & 0x20) ? ", ILI" : "");
|
|
|
|
device_printf(request->dev,
|
|
|
|
"cmd %s status %02x result %02x error %02x\n",
|
|
|
|
ata_cmd2str(request),
|
|
|
|
request->status, request->result, request->error);
|
2003-09-21 16:49:53 +00:00
|
|
|
}
|
2002-08-09 20:54:06 +00:00
|
|
|
#endif
|
2003-09-21 16:49:53 +00:00
|
|
|
|
2004-02-11 10:14:08 +00:00
|
|
|
if ((hcb->flags & AUTOSENSE) != 0) {
|
|
|
|
rc = CAM_SCSI_STATUS_ERROR;
|
|
|
|
if (request->result == 0) {
|
|
|
|
csio->ccb_h.status |= CAM_AUTOSNS_VALID;
|
|
|
|
}
|
|
|
|
} else if (request->result != 0) {
|
2007-03-13 20:42:49 +00:00
|
|
|
if ((request->flags & ATA_R_TIMEOUT) != 0) {
|
|
|
|
rc = CAM_CMD_TIMEOUT;
|
|
|
|
} else {
|
|
|
|
rc = CAM_SCSI_STATUS_ERROR;
|
|
|
|
csio->scsi_status = SCSI_STATUS_CHECK_COND;
|
2004-02-11 10:14:08 +00:00
|
|
|
|
2007-03-13 20:42:49 +00:00
|
|
|
if ((csio->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) {
|
2004-03-04 15:37:39 +00:00
|
|
|
#if 0
|
2007-03-13 20:42:49 +00:00
|
|
|
static const int8_t ccb[16] = { ATAPI_REQUEST_SENSE, 0, 0, 0,
|
|
|
|
sizeof(struct atapi_sense), 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0 };
|
|
|
|
|
|
|
|
bcopy (ccb, request->u.atapi.ccb, sizeof ccb);
|
|
|
|
request->data = (caddr_t)&csio->sense_data;
|
|
|
|
request->bytecount = sizeof(struct atapi_sense);
|
|
|
|
request->transfersize = min(request->bytecount, 65534);
|
2009-10-26 11:23:41 +00:00
|
|
|
request->timeout = (csio->ccb_h.timeout + 999) / 1000;
|
2007-03-13 20:42:49 +00:00
|
|
|
request->retries = 2;
|
|
|
|
request->flags = ATA_R_QUIET|ATA_R_ATAPI|ATA_R_IMMEDIATE;
|
|
|
|
hcb->flags |= AUTOSENSE;
|
|
|
|
|
|
|
|
ata_queue_request(request);
|
|
|
|
return;
|
2004-03-04 15:37:39 +00:00
|
|
|
#else
|
2007-03-13 20:42:49 +00:00
|
|
|
/*
|
|
|
|
* Use auto-sense data from the ATA layer, if it has
|
|
|
|
* issued a REQUEST SENSE automatically and that operation
|
|
|
|
* returned without error.
|
|
|
|
*/
|
2007-04-30 09:26:43 +00:00
|
|
|
if (request->u.atapi.sense.key != 0 && request->error == 0) {
|
2007-03-13 20:42:49 +00:00
|
|
|
bcopy (&request->u.atapi.sense, &csio->sense_data, sizeof(struct atapi_sense));
|
|
|
|
csio->ccb_h.status |= CAM_AUTOSNS_VALID;
|
|
|
|
}
|
2004-03-04 15:37:39 +00:00
|
|
|
}
|
|
|
|
#endif
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
2003-09-21 16:49:53 +00:00
|
|
|
} else {
|
|
|
|
rc = CAM_REQ_CMP;
|
|
|
|
csio->scsi_status = SCSI_STATUS_OK;
|
2002-08-28 07:00:58 +00:00
|
|
|
if (((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) &&
|
2002-08-09 20:54:06 +00:00
|
|
|
hcb->dxfer_alloc != NULL)
|
2003-08-24 09:22:26 +00:00
|
|
|
{
|
2002-08-09 20:54:06 +00:00
|
|
|
bcopy(hcb->dxfer_alloc, csio->data_ptr, csio->dxfer_len);
|
2003-08-24 09:22:26 +00:00
|
|
|
}
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
2003-11-09 20:46:08 +00:00
|
|
|
|
2005-04-05 15:08:19 +00:00
|
|
|
mtx_lock(&scp->state_lock);
|
2003-09-21 16:49:53 +00:00
|
|
|
free_hcb_and_ccb_done(hcb, rc);
|
2005-04-05 15:08:19 +00:00
|
|
|
mtx_unlock(&scp->state_lock);
|
2003-11-09 20:46:08 +00:00
|
|
|
|
|
|
|
ata_free_request(request);
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_hcb_and_ccb_done(struct atapi_hcb *hcb, u_int32_t status)
|
|
|
|
{
|
2005-04-05 02:03:31 +00:00
|
|
|
struct atapi_xpt_softc *softc;
|
|
|
|
union ccb *ccb;
|
2002-08-09 20:54:06 +00:00
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
if (hcb == NULL)
|
|
|
|
return;
|
2003-08-24 09:22:26 +00:00
|
|
|
|
2005-04-05 02:03:31 +00:00
|
|
|
softc = hcb->softc;
|
|
|
|
ccb = hcb->ccb;
|
|
|
|
|
|
|
|
/* we're about to free a hcb, so the shortage has ended */
|
|
|
|
if (softc->flags & RESOURCE_SHORTAGE) {
|
|
|
|
softc->flags &= ~RESOURCE_SHORTAGE;
|
|
|
|
status |= CAM_RELEASE_SIMQ;
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
2005-04-05 02:03:31 +00:00
|
|
|
free_hcb(hcb);
|
2003-08-24 09:22:26 +00:00
|
|
|
ccb->ccb_h.status =
|
2002-08-09 20:54:06 +00:00
|
|
|
status | (ccb->ccb_h.status & ~(CAM_STATUS_MASK | CAM_SIM_QUEUED));
|
|
|
|
xpt_done(ccb);
|
|
|
|
}
|
|
|
|
|
2003-08-24 09:22:26 +00:00
|
|
|
static void
|
2002-08-09 20:54:06 +00:00
|
|
|
atapi_async(void *callback_arg, u_int32_t code,
|
|
|
|
struct cam_path* path, void *arg)
|
|
|
|
{
|
|
|
|
int targ;
|
|
|
|
|
2003-08-24 09:22:26 +00:00
|
|
|
GIANT_REQUIRED;
|
|
|
|
|
2002-08-09 20:54:06 +00:00
|
|
|
switch (code) {
|
|
|
|
case AC_LOST_DEVICE:
|
|
|
|
targ = xpt_path_target_id(path);
|
|
|
|
xpt_print_path(path);
|
|
|
|
if (targ == -1)
|
|
|
|
printf("Lost host adapter\n");
|
|
|
|
else
|
|
|
|
printf("Lost target %d???\n", targ);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cam_rescan(struct cam_sim *sim)
|
|
|
|
{
|
2007-05-02 15:30:24 +00:00
|
|
|
union ccb *ccb;
|
|
|
|
|
|
|
|
ccb = xpt_alloc_ccb_nowait();
|
|
|
|
if (ccb == NULL)
|
|
|
|
return;
|
MFp4: Large set of CAM inprovements.
- Unify bus reset/probe sequence. Whenever bus attached at boot or later,
CAM will automatically reset and scan it. It allows to remove duplicate
code from many drivers.
- Any bus, attached before CAM completed it's boot-time initialization,
will equally join to the process, delaying boot if needed.
- New kern.cam.boot_delay loader tunable should help controllers that
are still unable to register their buses in time (such as slow USB/
PCCard/ CardBus devices), by adding one more event to wait on boot.
- To allow synchronization between different CAM levels, concept of
requests priorities was extended. Priorities now split between several
"run levels". Device can be freezed at specified level, allowing higher
priority requests to pass. For example, no payload requests allowed,
until PMP driver enable port. ATA XPT negotiate transfer parameters,
periph driver configure caching and so on.
- Frozen requests are no more counted by request allocation scheduler.
It fixes deadlocks, when frozen low priority payload requests occupying
slots, required by higher levels to manage theit execution.
- Two last changes were holding proper ATA reinitialization and error
recovery implementation. Now it is done: SATA controllers and Port
Multipliers now implement automatic hot-plug and should correctly
recover from timeouts and bus resets.
- Improve SCSI error recovery for devices on buses without automatic sense
reporting, such as ATAPI or USB. For example, it allows CAM to wait, while
CD drive loads disk, instead of immediately return error status.
- Decapitalize diagnostic messages and make them more readable and sensible.
- Teach PMP driver to limit maximum speed on fan-out ports.
- Make boot wait for PMP scan completes, and make rescan more reliable.
- Fix pass driver, to return CCB to user level in case of error.
- Increase number of retries in cd driver, as device may return several UAs.
2010-01-28 08:41:30 +00:00
|
|
|
if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(sim),
|
2004-01-18 17:21:15 +00:00
|
|
|
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
|
2007-05-02 15:30:24 +00:00
|
|
|
xpt_free_ccb(ccb);
|
2002-08-09 20:54:06 +00:00
|
|
|
return;
|
2004-01-18 17:21:15 +00:00
|
|
|
}
|
MFp4: Large set of CAM inprovements.
- Unify bus reset/probe sequence. Whenever bus attached at boot or later,
CAM will automatically reset and scan it. It allows to remove duplicate
code from many drivers.
- Any bus, attached before CAM completed it's boot-time initialization,
will equally join to the process, delaying boot if needed.
- New kern.cam.boot_delay loader tunable should help controllers that
are still unable to register their buses in time (such as slow USB/
PCCard/ CardBus devices), by adding one more event to wait on boot.
- To allow synchronization between different CAM levels, concept of
requests priorities was extended. Priorities now split between several
"run levels". Device can be freezed at specified level, allowing higher
priority requests to pass. For example, no payload requests allowed,
until PMP driver enable port. ATA XPT negotiate transfer parameters,
periph driver configure caching and so on.
- Frozen requests are no more counted by request allocation scheduler.
It fixes deadlocks, when frozen low priority payload requests occupying
slots, required by higher levels to manage theit execution.
- Two last changes were holding proper ATA reinitialization and error
recovery implementation. Now it is done: SATA controllers and Port
Multipliers now implement automatic hot-plug and should correctly
recover from timeouts and bus resets.
- Improve SCSI error recovery for devices on buses without automatic sense
reporting, such as ATAPI or USB. For example, it allows CAM to wait, while
CD drive loads disk, instead of immediately return error status.
- Decapitalize diagnostic messages and make them more readable and sensible.
- Teach PMP driver to limit maximum speed on fan-out ports.
- Make boot wait for PMP scan completes, and make rescan more reliable.
- Fix pass driver, to return CCB to user level in case of error.
- Increase number of retries in cd driver, as device may return several UAs.
2010-01-28 08:41:30 +00:00
|
|
|
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("Rescanning ATAPI bus.\n"));
|
|
|
|
xpt_rescan(ccb);
|
2002-08-09 20:54:06 +00:00
|
|
|
/* scan is in progress now */
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct atapi_hcb *
|
|
|
|
allocate_hcb(struct atapi_xpt_softc *softc, int unit, int bus, union ccb *ccb)
|
|
|
|
{
|
|
|
|
struct atapi_hcb *hcb = (struct atapi_hcb *)
|
|
|
|
malloc(sizeof(struct atapi_hcb), M_ATACAM, M_NOWAIT | M_ZERO);
|
|
|
|
|
|
|
|
if (hcb != NULL) {
|
|
|
|
hcb->softc = softc;
|
|
|
|
hcb->unit = unit;
|
|
|
|
hcb->bus = bus;
|
|
|
|
hcb->ccb = ccb;
|
|
|
|
}
|
|
|
|
return hcb;
|
|
|
|
}
|
|
|
|
|
2003-08-24 09:22:26 +00:00
|
|
|
static void
|
2002-08-09 20:54:06 +00:00
|
|
|
free_hcb(struct atapi_hcb *hcb)
|
|
|
|
{
|
2003-09-19 16:25:44 +00:00
|
|
|
if ((hcb->flags & QUEUED) != 0)
|
|
|
|
TAILQ_REMOVE(&hcb->softc->pending_hcbs, hcb, chain);
|
2002-08-09 20:54:06 +00:00
|
|
|
if (hcb->dxfer_alloc != NULL)
|
|
|
|
free(hcb->dxfer_alloc, M_ATACAM);
|
|
|
|
free(hcb, M_ATACAM);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_softc(struct atapi_xpt_softc *scp)
|
|
|
|
{
|
2010-06-05 08:58:03 +00:00
|
|
|
struct atapi_hcb *hcb, *thcb;
|
2002-08-09 20:54:06 +00:00
|
|
|
|
|
|
|
if (scp != NULL) {
|
2005-04-05 02:03:31 +00:00
|
|
|
mtx_lock(&scp->state_lock);
|
2010-06-05 08:58:03 +00:00
|
|
|
TAILQ_FOREACH_SAFE(hcb, &scp->pending_hcbs, chain, thcb) {
|
2002-08-09 20:54:06 +00:00
|
|
|
free_hcb_and_ccb_done(hcb, CAM_UNREC_HBA_ERROR);
|
|
|
|
}
|
|
|
|
if (scp->path != NULL) {
|
|
|
|
setup_async_cb(scp, 0);
|
|
|
|
xpt_free_path(scp->path);
|
|
|
|
}
|
|
|
|
if ((scp->flags & BUS_REGISTERED) != 0) {
|
|
|
|
if (xpt_bus_deregister(cam_sim_path(scp->sim)) == CAM_REQ_CMP)
|
|
|
|
scp->flags &= ~BUS_REGISTERED;
|
|
|
|
}
|
|
|
|
if (scp->sim != NULL) {
|
|
|
|
if ((scp->flags & BUS_REGISTERED) == 0)
|
|
|
|
cam_sim_free(scp->sim, /*free_devq*/TRUE);
|
|
|
|
else
|
|
|
|
printf("Can't free %s SIM (still registered)\n",
|
|
|
|
cam_sim_name(scp->sim));
|
|
|
|
}
|
2005-04-05 02:03:31 +00:00
|
|
|
mtx_destroy(&scp->state_lock);
|
2002-08-09 20:54:06 +00:00
|
|
|
}
|
|
|
|
}
|
2005-04-15 10:20:52 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
atapi_cam_event_handler(module_t mod, int what, void *arg) {
|
|
|
|
device_t *devlist;
|
|
|
|
int devcount;
|
|
|
|
|
|
|
|
switch (what) {
|
|
|
|
case MOD_UNLOAD:
|
|
|
|
if (devclass_get_devices(atapi_cam_devclass, &devlist, &devcount)
|
|
|
|
!= 0)
|
|
|
|
return ENXIO;
|
|
|
|
if (devlist != NULL) {
|
|
|
|
while (devlist != NULL && devcount > 0) {
|
|
|
|
device_t child = devlist[--devcount];
|
2009-02-28 22:07:15 +00:00
|
|
|
struct atapi_xpt_softc *scp = device_get_softc(child);
|
2005-04-15 10:20:52 +00:00
|
|
|
|
2009-02-28 22:07:15 +00:00
|
|
|
device_delete_child(device_get_parent(child),child);
|
|
|
|
if (scp != NULL)
|
|
|
|
free(scp, M_ATACAM);
|
2005-04-15 10:20:52 +00:00
|
|
|
}
|
|
|
|
free(devlist, M_TEMP);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|