2005-01-06 01:43:34 +00:00
|
|
|
/*-
|
2003-11-12 03:29:57 +00:00
|
|
|
* Copyright (c) 2003 Hidetoshi Shimokawa
|
|
|
|
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
|
2002-09-13 12:31:56 +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.
|
|
|
|
* 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. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the acknowledgement as bellow:
|
|
|
|
*
|
|
|
|
* This product includes software developed by K. Kobayashi and H. Shimokawa
|
|
|
|
*
|
|
|
|
* 4. 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.
|
|
|
|
*
|
|
|
|
* $FreeBSD$
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/module.h>
|
|
|
|
#include <sys/bus.h>
|
2004-03-26 23:17:10 +00:00
|
|
|
#include <sys/kernel.h>
|
2002-09-13 12:31:56 +00:00
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <machine/bus.h>
|
|
|
|
#include <sys/malloc.h>
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__FreeBSD__) && __FreeBSD_version >= 501102
|
2003-07-01 15:52:06 +00:00
|
|
|
#include <sys/lock.h>
|
|
|
|
#include <sys/mutex.h>
|
2003-07-18 14:31:16 +00:00
|
|
|
#endif
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__DragonFly__) || __FreeBSD_version < 500106
|
2003-03-12 10:36:53 +00:00
|
|
|
#include <sys/devicestat.h> /* for struct devstat */
|
|
|
|
#endif
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2004-03-26 23:17:10 +00:00
|
|
|
#ifdef __DragonFly__
|
|
|
|
#include <bus/cam/cam.h>
|
|
|
|
#include <bus/cam/cam_ccb.h>
|
|
|
|
#include <bus/cam/cam_sim.h>
|
|
|
|
#include <bus/cam/cam_xpt_sim.h>
|
|
|
|
#include <bus/cam/cam_debug.h>
|
|
|
|
#include <bus/cam/cam_periph.h>
|
|
|
|
#include <bus/cam/scsi/scsi_all.h>
|
|
|
|
|
|
|
|
#include <bus/firewire/firewire.h>
|
|
|
|
#include <bus/firewire/firewirereg.h>
|
|
|
|
#include <bus/firewire/fwdma.h>
|
|
|
|
#include <bus/firewire/iec13213.h>
|
|
|
|
#include "sbp.h"
|
|
|
|
#else
|
2002-09-13 12:31:56 +00:00
|
|
|
#include <cam/cam.h>
|
|
|
|
#include <cam/cam_ccb.h>
|
|
|
|
#include <cam/cam_sim.h>
|
|
|
|
#include <cam/cam_xpt_sim.h>
|
|
|
|
#include <cam/cam_debug.h>
|
|
|
|
#include <cam/cam_periph.h>
|
|
|
|
#include <cam/scsi/scsi_all.h>
|
|
|
|
|
|
|
|
#include <dev/firewire/firewire.h>
|
|
|
|
#include <dev/firewire/firewirereg.h>
|
2003-04-17 03:38:03 +00:00
|
|
|
#include <dev/firewire/fwdma.h>
|
2002-09-13 12:31:56 +00:00
|
|
|
#include <dev/firewire/iec13213.h>
|
2003-10-02 04:06:56 +00:00
|
|
|
#include <dev/firewire/sbp.h>
|
2004-03-26 23:17:10 +00:00
|
|
|
#endif
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
#define ccb_sdev_ptr spriv_ptr0
|
|
|
|
#define ccb_sbp_ptr spriv_ptr1
|
|
|
|
|
2003-02-27 12:51:24 +00:00
|
|
|
#define SBP_NUM_TARGETS 8 /* MAX 64 */
|
2003-10-18 04:59:47 +00:00
|
|
|
/*
|
|
|
|
* Scan_bus doesn't work for more than 8 LUNs
|
|
|
|
* because of CAM_SCSI2_MAXLUN in cam_xpt.c
|
|
|
|
*/
|
|
|
|
#define SBP_NUM_LUNS 64
|
2007-03-16 01:23:36 +00:00
|
|
|
#define SBP_MAXPHYS MIN(MAXPHYS, (512*1024) /* 512KB */)
|
2003-04-17 03:38:03 +00:00
|
|
|
#define SBP_DMA_SIZE PAGE_SIZE
|
|
|
|
#define SBP_LOGIN_SIZE sizeof(struct sbp_login_res)
|
|
|
|
#define SBP_QUEUE_LEN ((SBP_DMA_SIZE - SBP_LOGIN_SIZE) / sizeof(struct sbp_ocb))
|
2002-09-13 12:31:56 +00:00
|
|
|
#define SBP_NUM_OCB (SBP_QUEUE_LEN * SBP_NUM_TARGETS)
|
2003-04-17 03:38:03 +00:00
|
|
|
|
2003-02-27 12:51:24 +00:00
|
|
|
/*
|
|
|
|
* STATUS FIFO addressing
|
|
|
|
* bit
|
|
|
|
* -----------------------
|
2004-06-15 16:03:49 +00:00
|
|
|
* 0- 1( 2): 0 (alignment)
|
2003-02-27 12:51:24 +00:00
|
|
|
* 2- 7( 6): target
|
|
|
|
* 8-15( 8): lun
|
2003-10-02 04:06:56 +00:00
|
|
|
* 16-31( 8): reserved
|
2003-02-27 12:51:24 +00:00
|
|
|
* 32-47(16): SBP_BIND_HI
|
|
|
|
* 48-64(16): bus_id, node_id
|
|
|
|
*/
|
2002-09-13 12:31:56 +00:00
|
|
|
#define SBP_BIND_HI 0x1
|
2003-10-02 04:06:56 +00:00
|
|
|
#define SBP_DEV2ADDR(t, l) \
|
|
|
|
(((u_int64_t)SBP_BIND_HI << 32) \
|
|
|
|
| (((l) & 0xff) << 8) \
|
|
|
|
| (((t) & 0x3f) << 2))
|
2002-09-13 12:31:56 +00:00
|
|
|
#define SBP_ADDR2TRG(a) (((a) >> 2) & 0x3f)
|
|
|
|
#define SBP_ADDR2LUN(a) (((a) >> 8) & 0xff)
|
2003-10-02 04:06:56 +00:00
|
|
|
#define SBP_INITIATOR 7
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
static char *orb_fun_name[] = {
|
2003-10-02 04:06:56 +00:00
|
|
|
ORB_FUN_NAMES
|
2002-09-13 12:31:56 +00:00
|
|
|
};
|
|
|
|
|
2003-02-21 02:27:13 +00:00
|
|
|
static int debug = 0;
|
2002-09-13 12:31:56 +00:00
|
|
|
static int auto_login = 1;
|
2004-01-08 14:58:09 +00:00
|
|
|
static int max_speed = -1;
|
2003-02-21 02:09:04 +00:00
|
|
|
static int sbp_cold = 1;
|
2003-11-10 03:51:23 +00:00
|
|
|
static int ex_login = 1;
|
|
|
|
static int login_delay = 1000; /* msec */
|
|
|
|
static int scan_delay = 500; /* msec */
|
2004-03-26 23:17:10 +00:00
|
|
|
static int use_doorbell = 0;
|
|
|
|
static int sbp_tags = 0;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
SYSCTL_DECL(_hw_firewire);
|
2011-11-07 15:43:11 +00:00
|
|
|
static SYSCTL_NODE(_hw_firewire, OID_AUTO, sbp, CTLFLAG_RD, 0,
|
|
|
|
"SBP-II Subsystem");
|
2002-09-13 12:31:56 +00:00
|
|
|
SYSCTL_INT(_debug, OID_AUTO, sbp_debug, CTLFLAG_RW, &debug, 0,
|
|
|
|
"SBP debug flag");
|
|
|
|
SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, auto_login, CTLFLAG_RW, &auto_login, 0,
|
|
|
|
"SBP perform login automatically");
|
|
|
|
SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, max_speed, CTLFLAG_RW, &max_speed, 0,
|
|
|
|
"SBP transfer max speed");
|
2003-10-31 12:05:55 +00:00
|
|
|
SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, exclusive_login, CTLFLAG_RW,
|
2004-06-18 08:02:49 +00:00
|
|
|
&ex_login, 0, "SBP enable exclusive login");
|
2003-11-10 03:51:23 +00:00
|
|
|
SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, login_delay, CTLFLAG_RW,
|
|
|
|
&login_delay, 0, "SBP login delay in msec");
|
|
|
|
SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, scan_delay, CTLFLAG_RW,
|
|
|
|
&scan_delay, 0, "SBP scan delay in msec");
|
2004-03-26 23:17:10 +00:00
|
|
|
SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, use_doorbell, CTLFLAG_RW,
|
|
|
|
&use_doorbell, 0, "SBP use doorbell request");
|
|
|
|
SYSCTL_INT(_hw_firewire_sbp, OID_AUTO, tags, CTLFLAG_RW, &sbp_tags, 0,
|
|
|
|
"SBP tagged queuing support");
|
2003-11-10 03:51:23 +00:00
|
|
|
|
|
|
|
TUNABLE_INT("hw.firewire.sbp.auto_login", &auto_login);
|
|
|
|
TUNABLE_INT("hw.firewire.sbp.max_speed", &max_speed);
|
|
|
|
TUNABLE_INT("hw.firewire.sbp.exclusive_login", &ex_login);
|
|
|
|
TUNABLE_INT("hw.firewire.sbp.login_delay", &login_delay);
|
|
|
|
TUNABLE_INT("hw.firewire.sbp.scan_delay", &scan_delay);
|
2004-03-26 23:17:10 +00:00
|
|
|
TUNABLE_INT("hw.firewire.sbp.use_doorbell", &use_doorbell);
|
|
|
|
TUNABLE_INT("hw.firewire.sbp.tags", &sbp_tags);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
#define NEED_RESPONSE 0
|
|
|
|
|
2003-04-17 03:38:03 +00:00
|
|
|
#define SBP_SEG_MAX rounddown(0xffff, PAGE_SIZE)
|
|
|
|
#ifdef __sparc64__ /* iommu */
|
2007-03-16 01:23:36 +00:00
|
|
|
#define SBP_IND_MAX howmany(SBP_MAXPHYS, SBP_SEG_MAX)
|
2003-04-17 03:38:03 +00:00
|
|
|
#else
|
2007-03-16 01:23:36 +00:00
|
|
|
#define SBP_IND_MAX howmany(SBP_MAXPHYS, PAGE_SIZE)
|
2003-04-17 03:38:03 +00:00
|
|
|
#endif
|
2002-09-13 12:31:56 +00:00
|
|
|
struct sbp_ocb {
|
|
|
|
STAILQ_ENTRY(sbp_ocb) ocb;
|
|
|
|
union ccb *ccb;
|
2003-04-17 03:38:03 +00:00
|
|
|
bus_addr_t bus_addr;
|
2004-05-22 16:14:17 +00:00
|
|
|
uint32_t orb[8];
|
|
|
|
#define IND_PTR_OFFSET (8*sizeof(uint32_t))
|
2003-10-02 04:06:56 +00:00
|
|
|
struct ind_ptr ind_ptr[SBP_IND_MAX];
|
2002-09-13 12:31:56 +00:00
|
|
|
struct sbp_dev *sdev;
|
2003-04-17 03:38:03 +00:00
|
|
|
int flags; /* XXX should be removed */
|
2002-09-13 12:31:56 +00:00
|
|
|
bus_dmamap_t dmamap;
|
2013-09-25 17:16:21 +00:00
|
|
|
struct callout_handle timeout_ch;
|
2002-09-13 12:31:56 +00:00
|
|
|
};
|
2003-04-17 03:38:03 +00:00
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
#define OCB_ACT_MGM 0
|
|
|
|
#define OCB_ACT_CMD 1
|
2003-04-17 03:38:03 +00:00
|
|
|
#define OCB_MATCH(o,s) ((o)->bus_addr == ntohl((s)->orb_lo))
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
struct sbp_dev{
|
|
|
|
#define SBP_DEV_RESET 0 /* accept login */
|
|
|
|
#define SBP_DEV_LOGIN 1 /* to login */
|
2003-05-05 14:50:24 +00:00
|
|
|
#if 0
|
2002-09-13 12:31:56 +00:00
|
|
|
#define SBP_DEV_RECONN 2 /* to reconnect */
|
2003-02-04 17:08:45 +00:00
|
|
|
#endif
|
2002-09-13 12:31:56 +00:00
|
|
|
#define SBP_DEV_TOATTACH 3 /* to attach */
|
|
|
|
#define SBP_DEV_PROBE 4 /* scan lun */
|
|
|
|
#define SBP_DEV_ATTACHED 5 /* in operation */
|
|
|
|
#define SBP_DEV_DEAD 6 /* unavailable unit */
|
|
|
|
#define SBP_DEV_RETRY 7 /* unavailable unit */
|
2004-05-22 16:14:17 +00:00
|
|
|
uint8_t status:4,
|
2003-05-05 14:50:24 +00:00
|
|
|
timeout:4;
|
2004-05-22 16:14:17 +00:00
|
|
|
uint8_t type;
|
|
|
|
uint16_t lun_id;
|
|
|
|
uint16_t freeze;
|
2003-10-18 04:59:47 +00:00
|
|
|
#define ORB_LINK_DEAD (1 << 0)
|
|
|
|
#define VALID_LUN (1 << 1)
|
|
|
|
#define ORB_POINTER_ACTIVE (1 << 2)
|
|
|
|
#define ORB_POINTER_NEED (1 << 3)
|
2004-03-26 23:17:10 +00:00
|
|
|
#define ORB_DOORBELL_ACTIVE (1 << 4)
|
|
|
|
#define ORB_DOORBELL_NEED (1 << 5)
|
|
|
|
#define ORB_SHORTAGE (1 << 6)
|
2004-05-22 16:14:17 +00:00
|
|
|
uint16_t flags;
|
2002-09-13 12:31:56 +00:00
|
|
|
struct cam_path *path;
|
|
|
|
struct sbp_target *target;
|
2003-04-17 03:38:03 +00:00
|
|
|
struct fwdma_alloc dma;
|
|
|
|
struct sbp_login_res *login;
|
2003-02-27 12:51:24 +00:00
|
|
|
struct callout login_callout;
|
2003-04-17 03:38:03 +00:00
|
|
|
struct sbp_ocb *ocb;
|
2002-09-13 12:31:56 +00:00
|
|
|
STAILQ_HEAD(, sbp_ocb) ocbs;
|
2003-04-17 03:38:03 +00:00
|
|
|
STAILQ_HEAD(, sbp_ocb) free_ocbs;
|
2004-03-26 23:17:10 +00:00
|
|
|
struct sbp_ocb *last_ocb;
|
2002-09-13 12:31:56 +00:00
|
|
|
char vendor[32];
|
|
|
|
char product[32];
|
|
|
|
char revision[10];
|
2009-02-18 18:41:34 +00:00
|
|
|
char bustgtlun[32];
|
2002-09-13 12:31:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct sbp_target {
|
|
|
|
int target_id;
|
|
|
|
int num_lun;
|
2003-10-18 04:59:47 +00:00
|
|
|
struct sbp_dev **luns;
|
2002-09-13 12:31:56 +00:00
|
|
|
struct sbp_softc *sbp;
|
|
|
|
struct fw_device *fwdev;
|
2004-05-22 16:14:17 +00:00
|
|
|
uint32_t mgm_hi, mgm_lo;
|
2003-02-27 12:51:24 +00:00
|
|
|
struct sbp_ocb *mgm_ocb_cur;
|
|
|
|
STAILQ_HEAD(, sbp_ocb) mgm_ocb_queue;
|
|
|
|
struct callout mgm_ocb_timeout;
|
|
|
|
struct callout scan_callout;
|
2003-04-17 03:38:03 +00:00
|
|
|
STAILQ_HEAD(, fw_xfer) xferlist;
|
|
|
|
int n_xfer;
|
2002-09-13 12:31:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct sbp_softc {
|
|
|
|
struct firewire_dev_comm fd;
|
|
|
|
struct cam_sim *sim;
|
2003-02-27 12:51:24 +00:00
|
|
|
struct cam_path *path;
|
2002-09-13 12:31:56 +00:00
|
|
|
struct sbp_target targets[SBP_NUM_TARGETS];
|
|
|
|
struct fw_bind fwb;
|
|
|
|
bus_dma_tag_t dmat;
|
2003-11-10 03:51:23 +00:00
|
|
|
struct timeval last_busreset;
|
2004-01-05 14:21:18 +00:00
|
|
|
#define SIMQ_FREEZED 1
|
|
|
|
int flags;
|
2007-06-06 14:31:36 +00:00
|
|
|
struct mtx mtx;
|
2002-09-13 12:31:56 +00:00
|
|
|
};
|
2007-06-06 14:31:36 +00:00
|
|
|
#define SBP_LOCK(sbp) mtx_lock(&(sbp)->mtx)
|
|
|
|
#define SBP_UNLOCK(sbp) mtx_unlock(&(sbp)->mtx)
|
2003-11-10 03:51:23 +00:00
|
|
|
|
2004-01-06 14:30:47 +00:00
|
|
|
static void sbp_post_explore (void *);
|
|
|
|
static void sbp_recv (struct fw_xfer *);
|
|
|
|
static void sbp_mgm_callback (struct fw_xfer *);
|
2003-10-18 04:59:47 +00:00
|
|
|
#if 0
|
2004-01-06 14:30:47 +00:00
|
|
|
static void sbp_cmd_callback (struct fw_xfer *);
|
2003-10-18 04:59:47 +00:00
|
|
|
#endif
|
2004-01-06 14:30:47 +00:00
|
|
|
static void sbp_orb_pointer (struct sbp_dev *, struct sbp_ocb *);
|
2004-03-26 23:17:10 +00:00
|
|
|
static void sbp_doorbell(struct sbp_dev *);
|
2004-01-06 14:30:47 +00:00
|
|
|
static void sbp_execute_ocb (void *, bus_dma_segment_t *, int, int);
|
|
|
|
static void sbp_free_ocb (struct sbp_dev *, struct sbp_ocb *);
|
|
|
|
static void sbp_abort_ocb (struct sbp_ocb *, int);
|
|
|
|
static void sbp_abort_all_ocbs (struct sbp_dev *, int);
|
2007-06-16 00:59:41 +00:00
|
|
|
static struct fw_xfer * sbp_write_cmd_locked (struct sbp_dev *, int, int);
|
2004-01-06 14:30:47 +00:00
|
|
|
static struct fw_xfer * sbp_write_cmd (struct sbp_dev *, int, int);
|
|
|
|
static struct sbp_ocb * sbp_get_ocb (struct sbp_dev *);
|
|
|
|
static struct sbp_ocb * sbp_enqueue_ocb (struct sbp_dev *, struct sbp_ocb *);
|
|
|
|
static struct sbp_ocb * sbp_dequeue_ocb (struct sbp_dev *, struct sbp_status *);
|
2003-10-18 04:59:47 +00:00
|
|
|
static void sbp_cam_detach_sdev(struct sbp_dev *);
|
|
|
|
static void sbp_free_sdev(struct sbp_dev *);
|
2004-01-06 14:30:47 +00:00
|
|
|
static void sbp_cam_detach_target (struct sbp_target *);
|
|
|
|
static void sbp_free_target (struct sbp_target *);
|
|
|
|
static void sbp_mgm_timeout (void *arg);
|
|
|
|
static void sbp_timeout (void *arg);
|
|
|
|
static void sbp_mgm_orb (struct sbp_dev *, int, struct sbp_ocb *);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2011-11-07 06:44:47 +00:00
|
|
|
static MALLOC_DEFINE(M_SBP, "sbp", "SBP-II/FireWire");
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
/* cam related functions */
|
|
|
|
static void sbp_action(struct cam_sim *sim, union ccb *ccb);
|
|
|
|
static void sbp_poll(struct cam_sim *sim);
|
2003-02-27 12:51:24 +00:00
|
|
|
static void sbp_cam_scan_lun(struct cam_periph *, union ccb *);
|
|
|
|
static void sbp_cam_scan_target(void *arg);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
static char *orb_status0[] = {
|
|
|
|
/* 0 */ "No additional information to report",
|
|
|
|
/* 1 */ "Request type not supported",
|
|
|
|
/* 2 */ "Speed not supported",
|
|
|
|
/* 3 */ "Page size not supported",
|
|
|
|
/* 4 */ "Access denied",
|
|
|
|
/* 5 */ "Logical unit not supported",
|
|
|
|
/* 6 */ "Maximum payload too small",
|
|
|
|
/* 7 */ "Reserved for future standardization",
|
|
|
|
/* 8 */ "Resources unavailable",
|
|
|
|
/* 9 */ "Function rejected",
|
|
|
|
/* A */ "Login ID not recognized",
|
|
|
|
/* B */ "Dummy ORB completed",
|
|
|
|
/* C */ "Request aborted",
|
|
|
|
/* FF */ "Unspecified error"
|
|
|
|
#define MAX_ORB_STATUS0 0xd
|
|
|
|
};
|
|
|
|
|
|
|
|
static char *orb_status1_object[] = {
|
|
|
|
/* 0 */ "Operation request block (ORB)",
|
|
|
|
/* 1 */ "Data buffer",
|
|
|
|
/* 2 */ "Page table",
|
|
|
|
/* 3 */ "Unable to specify"
|
|
|
|
};
|
|
|
|
|
|
|
|
static char *orb_status1_serial_bus_error[] = {
|
|
|
|
/* 0 */ "Missing acknowledge",
|
|
|
|
/* 1 */ "Reserved; not to be used",
|
|
|
|
/* 2 */ "Time-out error",
|
|
|
|
/* 3 */ "Reserved; not to be used",
|
|
|
|
/* 4 */ "Busy retry limit exceeded(X)",
|
|
|
|
/* 5 */ "Busy retry limit exceeded(A)",
|
|
|
|
/* 6 */ "Busy retry limit exceeded(B)",
|
|
|
|
/* 7 */ "Reserved for future standardization",
|
|
|
|
/* 8 */ "Reserved for future standardization",
|
|
|
|
/* 9 */ "Reserved for future standardization",
|
|
|
|
/* A */ "Reserved for future standardization",
|
|
|
|
/* B */ "Tardy retry limit exceeded",
|
|
|
|
/* C */ "Conflict error",
|
|
|
|
/* D */ "Data error",
|
|
|
|
/* E */ "Type error",
|
|
|
|
/* F */ "Address error"
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_identify(driver_t *driver, device_t parent)
|
|
|
|
{
|
|
|
|
SBP_DEBUG(0)
|
|
|
|
printf("sbp_identify\n");
|
|
|
|
END_DEBUG
|
|
|
|
|
2009-02-09 16:57:07 +00:00
|
|
|
BUS_ADD_CHILD(parent, 0, "sbp", device_get_unit(parent));
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sbp_probe()
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
sbp_probe(device_t dev)
|
|
|
|
{
|
|
|
|
device_t pa;
|
|
|
|
|
|
|
|
SBP_DEBUG(0)
|
|
|
|
printf("sbp_probe\n");
|
|
|
|
END_DEBUG
|
|
|
|
|
|
|
|
pa = device_get_parent(dev);
|
|
|
|
if(device_get_unit(dev) != device_get_unit(pa)){
|
|
|
|
return(ENXIO);
|
|
|
|
}
|
|
|
|
|
2003-10-02 04:06:56 +00:00
|
|
|
device_set_desc(dev, "SBP-2/SCSI over FireWire");
|
2003-02-27 12:51:24 +00:00
|
|
|
|
2004-07-20 04:49:44 +00:00
|
|
|
#if 0
|
2003-02-27 12:51:24 +00:00
|
|
|
if (bootverbose)
|
|
|
|
debug = bootverbose;
|
2004-07-20 04:49:44 +00:00
|
|
|
#endif
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2009-02-18 18:41:34 +00:00
|
|
|
/*
|
|
|
|
* Display device characteristics on the console
|
|
|
|
*/
|
2002-09-13 12:31:56 +00:00
|
|
|
static void
|
2009-02-18 18:41:34 +00:00
|
|
|
sbp_show_sdev_info(struct sbp_dev *sdev)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
|
|
|
struct fw_device *fwdev;
|
|
|
|
|
|
|
|
fwdev = sdev->target->fwdev;
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s: %s: ordered:%d type:%d EUI:%08x%08x node:%d "
|
|
|
|
"speed:%d maxrec:%d\n",
|
|
|
|
__func__,
|
|
|
|
sdev->bustgtlun,
|
2002-12-31 10:28:49 +00:00
|
|
|
(sdev->type & 0x40) >> 6,
|
|
|
|
(sdev->type & 0x1f),
|
2002-09-13 12:31:56 +00:00
|
|
|
fwdev->eui.hi,
|
|
|
|
fwdev->eui.lo,
|
|
|
|
fwdev->dst,
|
|
|
|
fwdev->speed,
|
2009-02-18 18:41:34 +00:00
|
|
|
fwdev->maxrec);
|
|
|
|
|
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s: %s '%s' '%s' '%s'\n",
|
|
|
|
__func__,
|
|
|
|
sdev->bustgtlun,
|
|
|
|
sdev->vendor,
|
|
|
|
sdev->product,
|
|
|
|
sdev->revision);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
2003-02-01 08:55:33 +00:00
|
|
|
static struct {
|
|
|
|
int bus;
|
|
|
|
int target;
|
|
|
|
struct fw_eui64 eui;
|
|
|
|
} wired[] = {
|
|
|
|
/* Bus Target EUI64 */
|
|
|
|
#if 0
|
|
|
|
{0, 2, {0x00018ea0, 0x01fd0154}}, /* Logitec HDD */
|
|
|
|
{0, 0, {0x00018ea6, 0x00100682}}, /* Logitec DVD */
|
|
|
|
{0, 1, {0x00d03200, 0xa412006a}}, /* Yano HDD */
|
|
|
|
#endif
|
|
|
|
{-1, -1, {0,0}}
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
sbp_new_target(struct sbp_softc *sbp, struct fw_device *fwdev)
|
|
|
|
{
|
|
|
|
int bus, i, target=-1;
|
|
|
|
char w[SBP_NUM_TARGETS];
|
|
|
|
|
|
|
|
bzero(w, sizeof(w));
|
|
|
|
bus = device_get_unit(sbp->fd.dev);
|
|
|
|
|
|
|
|
/* XXX wired-down configuration should be gotten from
|
|
|
|
tunable or device hint */
|
|
|
|
for (i = 0; wired[i].bus >= 0; i ++) {
|
|
|
|
if (wired[i].bus == bus) {
|
|
|
|
w[wired[i].target] = 1;
|
|
|
|
if (wired[i].eui.hi == fwdev->eui.hi &&
|
|
|
|
wired[i].eui.lo == fwdev->eui.lo)
|
|
|
|
target = wired[i].target;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (target >= 0) {
|
|
|
|
if(target < SBP_NUM_TARGETS &&
|
|
|
|
sbp->targets[target].fwdev == NULL)
|
|
|
|
return(target);
|
|
|
|
device_printf(sbp->fd.dev,
|
|
|
|
"target %d is not free for %08x:%08x\n",
|
|
|
|
target, fwdev->eui.hi, fwdev->eui.lo);
|
|
|
|
target = -1;
|
|
|
|
}
|
|
|
|
/* non-wired target */
|
|
|
|
for (i = 0; i < SBP_NUM_TARGETS; i ++)
|
|
|
|
if (sbp->targets[i].fwdev == NULL && w[i] == 0) {
|
|
|
|
target = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
2003-10-18 04:59:47 +00:00
|
|
|
static void
|
|
|
|
sbp_alloc_lun(struct sbp_target *target)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
2002-12-31 10:28:49 +00:00
|
|
|
struct crom_context cc;
|
|
|
|
struct csrreg *reg;
|
2003-10-18 04:59:47 +00:00
|
|
|
struct sbp_dev *sdev, **newluns;
|
|
|
|
struct sbp_softc *sbp;
|
|
|
|
int maxlun, lun, i;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2003-10-18 04:59:47 +00:00
|
|
|
sbp = target->sbp;
|
2002-12-31 10:28:49 +00:00
|
|
|
crom_init_context(&cc, target->fwdev->csrrom);
|
|
|
|
/* XXX shoud parse appropriate unit directories only */
|
|
|
|
maxlun = -1;
|
|
|
|
while (cc.depth >= 0) {
|
|
|
|
reg = crom_search_key(&cc, CROM_LUN);
|
|
|
|
if (reg == NULL)
|
|
|
|
break;
|
2003-02-14 03:09:59 +00:00
|
|
|
lun = reg->val & 0xffff;
|
2003-01-04 06:40:57 +00:00
|
|
|
SBP_DEBUG(0)
|
|
|
|
printf("target %d lun %d found\n", target->target_id, lun);
|
|
|
|
END_DEBUG
|
2002-12-31 10:28:49 +00:00
|
|
|
if (maxlun < lun)
|
|
|
|
maxlun = lun;
|
|
|
|
crom_next(&cc);
|
|
|
|
}
|
2003-02-14 03:09:59 +00:00
|
|
|
if (maxlun < 0)
|
2003-10-18 04:59:47 +00:00
|
|
|
printf("%s:%d no LUN found\n",
|
|
|
|
device_get_nameunit(target->sbp->fd.dev),
|
|
|
|
target->target_id);
|
|
|
|
|
|
|
|
maxlun ++;
|
2003-02-14 03:09:59 +00:00
|
|
|
if (maxlun >= SBP_NUM_LUNS)
|
|
|
|
maxlun = SBP_NUM_LUNS;
|
2003-10-18 04:59:47 +00:00
|
|
|
|
|
|
|
/* Invalidiate stale devices */
|
|
|
|
for (lun = 0; lun < target->num_lun; lun ++) {
|
|
|
|
sdev = target->luns[lun];
|
|
|
|
if (sdev == NULL)
|
|
|
|
continue;
|
|
|
|
sdev->flags &= ~VALID_LUN;
|
|
|
|
if (lun >= maxlun) {
|
|
|
|
/* lost device */
|
|
|
|
sbp_cam_detach_sdev(sdev);
|
|
|
|
sbp_free_sdev(sdev);
|
2009-02-01 23:28:52 +00:00
|
|
|
target->luns[lun] = NULL;
|
2003-10-18 04:59:47 +00:00
|
|
|
}
|
2002-12-31 10:28:49 +00:00
|
|
|
}
|
2003-10-18 04:59:47 +00:00
|
|
|
|
|
|
|
/* Reallocate */
|
|
|
|
if (maxlun != target->num_lun) {
|
|
|
|
newluns = (struct sbp_dev **) realloc(target->luns,
|
|
|
|
sizeof(struct sbp_dev *) * maxlun,
|
|
|
|
M_SBP, M_NOWAIT | M_ZERO);
|
|
|
|
|
|
|
|
if (newluns == NULL) {
|
2004-03-26 23:17:10 +00:00
|
|
|
printf("%s: realloc failed\n", __func__);
|
2003-10-18 04:59:47 +00:00
|
|
|
newluns = target->luns;
|
|
|
|
maxlun = target->num_lun;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We must zero the extended region for the case
|
|
|
|
* realloc() doesn't allocate new buffer.
|
|
|
|
*/
|
|
|
|
if (maxlun > target->num_lun)
|
|
|
|
bzero(&newluns[target->num_lun],
|
|
|
|
sizeof(struct sbp_dev *) *
|
|
|
|
(maxlun - target->num_lun));
|
|
|
|
|
|
|
|
target->luns = newluns;
|
|
|
|
target->num_lun = maxlun;
|
|
|
|
}
|
|
|
|
|
2002-12-31 10:28:49 +00:00
|
|
|
crom_init_context(&cc, target->fwdev->csrrom);
|
|
|
|
while (cc.depth >= 0) {
|
2003-10-18 04:59:47 +00:00
|
|
|
int new = 0;
|
|
|
|
|
2002-12-31 10:28:49 +00:00
|
|
|
reg = crom_search_key(&cc, CROM_LUN);
|
|
|
|
if (reg == NULL)
|
|
|
|
break;
|
2003-02-14 03:09:59 +00:00
|
|
|
lun = reg->val & 0xffff;
|
|
|
|
if (lun >= SBP_NUM_LUNS) {
|
|
|
|
printf("too large lun %d\n", lun);
|
2003-10-18 04:59:47 +00:00
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
|
|
|
|
sdev = target->luns[lun];
|
|
|
|
if (sdev == NULL) {
|
|
|
|
sdev = malloc(sizeof(struct sbp_dev),
|
|
|
|
M_SBP, M_NOWAIT | M_ZERO);
|
|
|
|
if (sdev == NULL) {
|
2004-03-26 23:17:10 +00:00
|
|
|
printf("%s: malloc failed\n", __func__);
|
2003-10-18 04:59:47 +00:00
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
target->luns[lun] = sdev;
|
|
|
|
sdev->lun_id = lun;
|
|
|
|
sdev->target = target;
|
|
|
|
STAILQ_INIT(&sdev->ocbs);
|
|
|
|
CALLOUT_INIT(&sdev->login_callout);
|
|
|
|
sdev->status = SBP_DEV_RESET;
|
|
|
|
new = 1;
|
2009-02-18 18:41:34 +00:00
|
|
|
snprintf(sdev->bustgtlun, 32, "%s:%d:%d",
|
|
|
|
device_get_nameunit(sdev->target->sbp->fd.dev),
|
|
|
|
sdev->target->target_id,
|
|
|
|
sdev->lun_id);
|
2003-02-14 03:09:59 +00:00
|
|
|
}
|
2003-10-18 04:59:47 +00:00
|
|
|
sdev->flags |= VALID_LUN;
|
2003-08-21 08:40:31 +00:00
|
|
|
sdev->type = (reg->val & 0xff0000) >> 16;
|
2003-04-17 03:38:03 +00:00
|
|
|
|
2003-10-18 04:59:47 +00:00
|
|
|
if (new == 0)
|
|
|
|
goto next;
|
|
|
|
|
2003-04-17 03:38:03 +00:00
|
|
|
fwdma_malloc(sbp->fd.fc,
|
2004-05-22 16:14:17 +00:00
|
|
|
/* alignment */ sizeof(uint32_t),
|
2011-03-11 22:19:49 +00:00
|
|
|
SBP_DMA_SIZE, &sdev->dma, BUS_DMA_NOWAIT |
|
|
|
|
BUS_DMA_COHERENT);
|
2003-04-17 03:38:03 +00:00
|
|
|
if (sdev->dma.v_addr == NULL) {
|
|
|
|
printf("%s: dma space allocation failed\n",
|
2004-03-26 23:17:10 +00:00
|
|
|
__func__);
|
2003-10-18 04:59:47 +00:00
|
|
|
free(sdev, M_SBP);
|
|
|
|
target->luns[lun] = NULL;
|
|
|
|
goto next;
|
2003-04-17 03:38:03 +00:00
|
|
|
}
|
|
|
|
sdev->login = (struct sbp_login_res *) sdev->dma.v_addr;
|
|
|
|
sdev->ocb = (struct sbp_ocb *)
|
|
|
|
((char *)sdev->dma.v_addr + SBP_LOGIN_SIZE);
|
|
|
|
bzero((char *)sdev->ocb,
|
|
|
|
sizeof (struct sbp_ocb) * SBP_QUEUE_LEN);
|
|
|
|
|
|
|
|
STAILQ_INIT(&sdev->free_ocbs);
|
|
|
|
for (i = 0; i < SBP_QUEUE_LEN; i++) {
|
|
|
|
struct sbp_ocb *ocb;
|
|
|
|
ocb = &sdev->ocb[i];
|
|
|
|
ocb->bus_addr = sdev->dma.bus_addr
|
|
|
|
+ SBP_LOGIN_SIZE
|
|
|
|
+ sizeof(struct sbp_ocb) * i
|
|
|
|
+ offsetof(struct sbp_ocb, orb[0]);
|
|
|
|
if (bus_dmamap_create(sbp->dmat, 0, &ocb->dmamap)) {
|
|
|
|
printf("sbp_attach: cannot create dmamap\n");
|
2003-10-18 04:59:47 +00:00
|
|
|
/* XXX */
|
|
|
|
goto next;
|
2003-04-17 03:38:03 +00:00
|
|
|
}
|
2013-09-25 17:16:21 +00:00
|
|
|
callout_handle_init(&ocb->timeout_ch);
|
2003-04-17 03:38:03 +00:00
|
|
|
sbp_free_ocb(sdev, ocb);
|
|
|
|
}
|
2003-10-18 04:59:47 +00:00
|
|
|
next:
|
2002-12-31 10:28:49 +00:00
|
|
|
crom_next(&cc);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
2003-10-18 04:59:47 +00:00
|
|
|
|
|
|
|
for (lun = 0; lun < target->num_lun; lun ++) {
|
|
|
|
sdev = target->luns[lun];
|
|
|
|
if (sdev != NULL && (sdev->flags & VALID_LUN) == 0) {
|
|
|
|
sbp_cam_detach_sdev(sdev);
|
|
|
|
sbp_free_sdev(sdev);
|
|
|
|
target->luns[lun] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sbp_target *
|
|
|
|
sbp_alloc_target(struct sbp_softc *sbp, struct fw_device *fwdev)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct sbp_target *target;
|
|
|
|
struct crom_context cc;
|
|
|
|
struct csrreg *reg;
|
|
|
|
|
|
|
|
SBP_DEBUG(1)
|
|
|
|
printf("sbp_alloc_target\n");
|
|
|
|
END_DEBUG
|
|
|
|
i = sbp_new_target(sbp, fwdev);
|
|
|
|
if (i < 0) {
|
|
|
|
device_printf(sbp->fd.dev, "increase SBP_NUM_TARGETS!\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* new target */
|
|
|
|
target = &sbp->targets[i];
|
|
|
|
target->sbp = sbp;
|
|
|
|
target->fwdev = fwdev;
|
|
|
|
target->target_id = i;
|
|
|
|
/* XXX we may want to reload mgm port after each bus reset */
|
|
|
|
/* XXX there might be multiple management agents */
|
|
|
|
crom_init_context(&cc, target->fwdev->csrrom);
|
|
|
|
reg = crom_search_key(&cc, CROM_MGM);
|
|
|
|
if (reg == NULL || reg->val == 0) {
|
|
|
|
printf("NULL management address\n");
|
|
|
|
target->fwdev = NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
target->mgm_hi = 0xffff;
|
|
|
|
target->mgm_lo = 0xf0000000 | (reg->val << 2);
|
|
|
|
target->mgm_ocb_cur = NULL;
|
|
|
|
SBP_DEBUG(1)
|
|
|
|
printf("target:%d mgm_port: %x\n", i, target->mgm_lo);
|
|
|
|
END_DEBUG
|
|
|
|
STAILQ_INIT(&target->xferlist);
|
|
|
|
target->n_xfer = 0;
|
|
|
|
STAILQ_INIT(&target->mgm_ocb_queue);
|
|
|
|
CALLOUT_INIT(&target->mgm_ocb_timeout);
|
|
|
|
CALLOUT_INIT(&target->scan_callout);
|
|
|
|
|
|
|
|
target->luns = NULL;
|
|
|
|
target->num_lun = 0;
|
2003-04-26 16:45:40 +00:00
|
|
|
return target;
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_probe_lun(struct sbp_dev *sdev)
|
|
|
|
{
|
|
|
|
struct fw_device *fwdev;
|
2003-04-26 16:45:40 +00:00
|
|
|
struct crom_context c, *cc = &c;
|
|
|
|
struct csrreg *reg;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
bzero(sdev->vendor, sizeof(sdev->vendor));
|
|
|
|
bzero(sdev->product, sizeof(sdev->product));
|
2003-02-27 12:51:24 +00:00
|
|
|
|
2003-04-26 16:45:40 +00:00
|
|
|
fwdev = sdev->target->fwdev;
|
|
|
|
crom_init_context(cc, fwdev->csrrom);
|
|
|
|
/* get vendor string */
|
|
|
|
crom_search_key(cc, CSRKEY_VENDOR);
|
|
|
|
crom_next(cc);
|
|
|
|
crom_parse_text(cc, sdev->vendor, sizeof(sdev->vendor));
|
2003-04-29 15:01:01 +00:00
|
|
|
/* skip to the unit directory for SBP-2 */
|
2003-04-29 23:40:04 +00:00
|
|
|
while ((reg = crom_search_key(cc, CSRKEY_VER)) != NULL) {
|
2003-04-29 15:01:01 +00:00
|
|
|
if (reg->val == CSRVAL_T10SBP2)
|
|
|
|
break;
|
2003-04-29 23:40:04 +00:00
|
|
|
crom_next(cc);
|
|
|
|
}
|
2003-04-26 16:45:40 +00:00
|
|
|
/* get firmware revision */
|
|
|
|
reg = crom_search_key(cc, CSRKEY_FIRM_VER);
|
|
|
|
if (reg != NULL)
|
|
|
|
snprintf(sdev->revision, sizeof(sdev->revision),
|
|
|
|
"%06x", reg->val);
|
|
|
|
/* get product string */
|
|
|
|
crom_search_key(cc, CSRKEY_MODEL);
|
|
|
|
crom_next(cc);
|
|
|
|
crom_parse_text(cc, sdev->product, sizeof(sdev->product));
|
|
|
|
}
|
2003-02-27 12:51:24 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_login_callout(void *arg)
|
|
|
|
{
|
|
|
|
struct sbp_dev *sdev = (struct sbp_dev *)arg;
|
|
|
|
sbp_mgm_orb(sdev, ORB_FUN_LGI, NULL);
|
|
|
|
}
|
|
|
|
|
2003-11-10 03:51:23 +00:00
|
|
|
static void
|
|
|
|
sbp_login(struct sbp_dev *sdev)
|
|
|
|
{
|
|
|
|
struct timeval delta;
|
|
|
|
struct timeval t;
|
|
|
|
int ticks = 0;
|
|
|
|
|
|
|
|
microtime(&delta);
|
|
|
|
timevalsub(&delta, &sdev->target->sbp->last_busreset);
|
|
|
|
t.tv_sec = login_delay / 1000;
|
|
|
|
t.tv_usec = (login_delay % 1000) * 1000;
|
|
|
|
timevalsub(&t, &delta);
|
|
|
|
if (t.tv_sec >= 0 && t.tv_usec > 0)
|
|
|
|
ticks = (t.tv_sec * 1000 + t.tv_usec / 1000) * hz / 1000;
|
|
|
|
SBP_DEBUG(0)
|
2005-12-24 22:22:17 +00:00
|
|
|
printf("%s: sec = %jd usec = %ld ticks = %d\n", __func__,
|
|
|
|
(intmax_t)t.tv_sec, t.tv_usec, ticks);
|
2003-11-10 03:51:23 +00:00
|
|
|
END_DEBUG
|
|
|
|
callout_reset(&sdev->login_callout, ticks,
|
|
|
|
sbp_login_callout, (void *)(sdev));
|
|
|
|
}
|
|
|
|
|
2003-04-26 16:45:40 +00:00
|
|
|
#define SBP_FWDEV_ALIVE(fwdev) (((fwdev)->status == FWDEVATTACHED) \
|
|
|
|
&& crom_has_specver((fwdev)->csrrom, CSRVAL_ANSIT10, CSRVAL_T10SBP2))
|
2003-02-27 12:51:24 +00:00
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
static void
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_probe_target(void *arg)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
2003-02-27 12:51:24 +00:00
|
|
|
struct sbp_target *target = (struct sbp_target *)arg;
|
2009-02-18 18:41:34 +00:00
|
|
|
struct sbp_softc *sbp = target->sbp;
|
2002-09-13 12:31:56 +00:00
|
|
|
struct sbp_dev *sdev;
|
2003-02-27 12:51:24 +00:00
|
|
|
int i, alive;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2003-02-27 12:51:24 +00:00
|
|
|
alive = SBP_FWDEV_ALIVE(target->fwdev);
|
2002-09-13 12:31:56 +00:00
|
|
|
SBP_DEBUG(1)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sbp->fd.dev, "%s %d%salive\n",
|
|
|
|
__func__, target->target_id,
|
|
|
|
(!alive) ? " not " : "");
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
|
|
|
|
|
|
|
sbp = target->sbp;
|
2003-10-18 04:59:47 +00:00
|
|
|
sbp_alloc_lun(target);
|
|
|
|
|
2003-02-27 12:51:24 +00:00
|
|
|
/* XXX untimeout mgm_ocb and dequeue */
|
2002-09-13 12:31:56 +00:00
|
|
|
for (i=0; i < target->num_lun; i++) {
|
2003-10-18 04:59:47 +00:00
|
|
|
sdev = target->luns[i];
|
|
|
|
if (sdev == NULL)
|
|
|
|
continue;
|
2002-09-13 12:31:56 +00:00
|
|
|
if (alive && (sdev->status != SBP_DEV_DEAD)) {
|
|
|
|
if (sdev->path != NULL) {
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
xpt_freeze_devq(sdev->path, 1);
|
2003-02-27 12:51:24 +00:00
|
|
|
sdev->freeze ++;
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_probe_lun(sdev);
|
2009-02-18 18:41:34 +00:00
|
|
|
sbp_show_sdev_info(sdev);
|
2003-02-27 12:51:24 +00:00
|
|
|
|
|
|
|
sbp_abort_all_ocbs(sdev, CAM_SCSI_BUS_RESET);
|
2002-09-13 12:31:56 +00:00
|
|
|
switch (sdev->status) {
|
2003-02-04 17:08:45 +00:00
|
|
|
case SBP_DEV_RESET:
|
2002-09-13 12:31:56 +00:00
|
|
|
/* new or revived target */
|
2003-04-17 03:38:03 +00:00
|
|
|
if (auto_login)
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_login(sdev);
|
2002-09-13 12:31:56 +00:00
|
|
|
break;
|
2003-02-27 12:51:24 +00:00
|
|
|
case SBP_DEV_TOATTACH:
|
|
|
|
case SBP_DEV_PROBE:
|
|
|
|
case SBP_DEV_ATTACHED:
|
2003-02-04 17:08:45 +00:00
|
|
|
case SBP_DEV_RETRY:
|
|
|
|
default:
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_mgm_orb(sdev, ORB_FUN_RCN, NULL);
|
2003-02-04 17:08:45 +00:00
|
|
|
break;
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (sdev->status) {
|
|
|
|
case SBP_DEV_ATTACHED:
|
|
|
|
SBP_DEBUG(0)
|
|
|
|
/* the device has gone */
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sbp->fd.dev, "%s: lost target\n",
|
|
|
|
__func__);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2003-02-27 12:51:24 +00:00
|
|
|
if (sdev->path) {
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
xpt_freeze_devq(sdev->path, 1);
|
2003-02-27 12:51:24 +00:00
|
|
|
sdev->freeze ++;
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sbp);
|
2003-02-27 12:51:24 +00:00
|
|
|
}
|
2002-09-13 12:31:56 +00:00
|
|
|
sdev->status = SBP_DEV_RETRY;
|
2009-02-01 23:28:52 +00:00
|
|
|
sbp_cam_detach_sdev(sdev);
|
|
|
|
sbp_free_sdev(sdev);
|
|
|
|
target->luns[i] = NULL;
|
2002-09-13 12:31:56 +00:00
|
|
|
break;
|
|
|
|
case SBP_DEV_PROBE:
|
|
|
|
case SBP_DEV_TOATTACH:
|
|
|
|
sdev->status = SBP_DEV_RESET;
|
|
|
|
break;
|
|
|
|
case SBP_DEV_RETRY:
|
|
|
|
case SBP_DEV_RESET:
|
|
|
|
case SBP_DEV_DEAD:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-04-17 03:38:03 +00:00
|
|
|
static void
|
|
|
|
sbp_post_busreset(void *arg)
|
|
|
|
{
|
|
|
|
struct sbp_softc *sbp;
|
|
|
|
|
|
|
|
sbp = (struct sbp_softc *)arg;
|
|
|
|
SBP_DEBUG(0)
|
|
|
|
printf("sbp_post_busreset\n");
|
|
|
|
END_DEBUG
|
2004-01-05 14:21:18 +00:00
|
|
|
if ((sbp->sim->flags & SIMQ_FREEZED) == 0) {
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sbp);
|
2004-01-05 14:21:18 +00:00
|
|
|
xpt_freeze_simq(sbp->sim, /*count*/1);
|
|
|
|
sbp->sim->flags |= SIMQ_FREEZED;
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sbp);
|
2004-01-05 14:21:18 +00:00
|
|
|
}
|
2003-11-10 03:51:23 +00:00
|
|
|
microtime(&sbp->last_busreset);
|
2003-04-17 03:38:03 +00:00
|
|
|
}
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
static void
|
|
|
|
sbp_post_explore(void *arg)
|
|
|
|
{
|
|
|
|
struct sbp_softc *sbp = (struct sbp_softc *)arg;
|
|
|
|
struct sbp_target *target;
|
|
|
|
struct fw_device *fwdev;
|
|
|
|
int i, alive;
|
|
|
|
|
2003-02-21 02:09:04 +00:00
|
|
|
SBP_DEBUG(0)
|
|
|
|
printf("sbp_post_explore (sbp_cold=%d)\n", sbp_cold);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2007-06-07 13:20:48 +00:00
|
|
|
/* We need physical access */
|
|
|
|
if (!firewire_phydma_enable)
|
|
|
|
return;
|
|
|
|
|
2003-11-10 03:51:23 +00:00
|
|
|
if (sbp_cold > 0)
|
|
|
|
sbp_cold --;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/*
|
|
|
|
* XXX don't let CAM the bus rest.
|
|
|
|
* CAM tries to do something with freezed (DEV_RETRY) devices.
|
2003-02-27 12:51:24 +00:00
|
|
|
*/
|
|
|
|
xpt_async(AC_BUS_RESET, sbp->path, /*arg*/ NULL);
|
2002-09-13 12:31:56 +00:00
|
|
|
#endif
|
2003-02-27 12:51:24 +00:00
|
|
|
|
2004-06-15 16:03:49 +00:00
|
|
|
/* Garbage Collection */
|
2002-09-13 12:31:56 +00:00
|
|
|
for(i = 0 ; i < SBP_NUM_TARGETS ; i ++){
|
|
|
|
target = &sbp->targets[i];
|
2003-02-01 14:42:49 +00:00
|
|
|
STAILQ_FOREACH(fwdev, &sbp->fd.fc->devices, link)
|
|
|
|
if (target->fwdev == NULL || target->fwdev == fwdev)
|
|
|
|
break;
|
2003-10-18 04:59:47 +00:00
|
|
|
if (fwdev == NULL) {
|
2002-09-13 12:31:56 +00:00
|
|
|
/* device has removed in lower driver */
|
2003-01-31 14:11:22 +00:00
|
|
|
sbp_cam_detach_target(target);
|
2003-10-18 04:59:47 +00:00
|
|
|
sbp_free_target(target);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* traverse device list */
|
2003-02-01 14:42:49 +00:00
|
|
|
STAILQ_FOREACH(fwdev, &sbp->fd.fc->devices, link) {
|
2002-09-13 12:31:56 +00:00
|
|
|
SBP_DEBUG(0)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sbp->fd.dev,"%s:: EUI:%08x%08x %s attached, state=%d\n",
|
|
|
|
__func__, fwdev->eui.hi, fwdev->eui.lo,
|
|
|
|
(fwdev->status != FWDEVATTACHED) ? "not" : "",
|
|
|
|
fwdev->status);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2003-02-27 12:51:24 +00:00
|
|
|
alive = SBP_FWDEV_ALIVE(fwdev);
|
2002-09-13 12:31:56 +00:00
|
|
|
for(i = 0 ; i < SBP_NUM_TARGETS ; i ++){
|
|
|
|
target = &sbp->targets[i];
|
|
|
|
if(target->fwdev == fwdev ) {
|
|
|
|
/* known target */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(i == SBP_NUM_TARGETS){
|
|
|
|
if (alive) {
|
|
|
|
/* new target */
|
|
|
|
target = sbp_alloc_target(sbp, fwdev);
|
|
|
|
if (target == NULL)
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_probe_target((void *)target);
|
2003-10-18 04:59:47 +00:00
|
|
|
if (target->num_lun == 0)
|
|
|
|
sbp_free_target(target);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sbp);
|
2004-01-05 14:21:18 +00:00
|
|
|
xpt_release_simq(sbp->sim, /*run queue*/TRUE);
|
|
|
|
sbp->sim->flags &= ~SIMQ_FREEZED;
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if NEED_RESPONSE
|
|
|
|
static void
|
|
|
|
sbp_loginres_callback(struct fw_xfer *xfer){
|
2003-04-17 03:38:03 +00:00
|
|
|
int s;
|
2002-09-13 12:31:56 +00:00
|
|
|
struct sbp_dev *sdev;
|
|
|
|
sdev = (struct sbp_dev *)xfer->sc;
|
2003-04-17 03:38:03 +00:00
|
|
|
SBP_DEBUG(1)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,"%s\n", __func__);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2003-04-17 03:38:03 +00:00
|
|
|
/* recycle */
|
|
|
|
s = splfw();
|
|
|
|
STAILQ_INSERT_TAIL(&sdev->target->sbp->fwb.xferlist, xfer, link);
|
|
|
|
splx(s);
|
2002-09-13 12:31:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-04-17 03:38:03 +00:00
|
|
|
static __inline void
|
|
|
|
sbp_xfer_free(struct fw_xfer *xfer)
|
|
|
|
{
|
|
|
|
struct sbp_dev *sdev;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
sdev = (struct sbp_dev *)xfer->sc;
|
|
|
|
fw_xfer_unload(xfer);
|
|
|
|
s = splfw();
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sdev->target->sbp);
|
2003-04-17 03:38:03 +00:00
|
|
|
STAILQ_INSERT_TAIL(&sdev->target->xferlist, xfer, link);
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sdev->target->sbp);
|
2003-04-17 03:38:03 +00:00
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
static void
|
2003-05-05 14:50:24 +00:00
|
|
|
sbp_reset_start_callback(struct fw_xfer *xfer)
|
|
|
|
{
|
|
|
|
struct sbp_dev *tsdev, *sdev = (struct sbp_dev *)xfer->sc;
|
|
|
|
struct sbp_target *target = sdev->target;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (xfer->resp != 0) {
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s: %s failed: resp=%d\n", __func__, sdev->bustgtlun, xfer->resp);
|
2003-05-05 14:50:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < target->num_lun; i++) {
|
2003-10-18 04:59:47 +00:00
|
|
|
tsdev = target->luns[i];
|
|
|
|
if (tsdev != NULL && tsdev->status == SBP_DEV_LOGIN)
|
|
|
|
sbp_login(tsdev);
|
2003-05-05 14:50:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_reset_start(struct sbp_dev *sdev)
|
|
|
|
{
|
|
|
|
struct fw_xfer *xfer;
|
|
|
|
struct fw_pkt *fp;
|
|
|
|
|
|
|
|
SBP_DEBUG(0)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s\n", __func__,sdev->bustgtlun);
|
2003-05-05 14:50:24 +00:00
|
|
|
END_DEBUG
|
|
|
|
|
|
|
|
xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0);
|
2007-03-16 05:39:33 +00:00
|
|
|
xfer->hand = sbp_reset_start_callback;
|
2003-10-02 04:06:56 +00:00
|
|
|
fp = &xfer->send.hdr;
|
2003-05-05 14:50:24 +00:00
|
|
|
fp->mode.wreqq.dest_hi = 0xffff;
|
|
|
|
fp->mode.wreqq.dest_lo = 0xf0000000 | RESET_START;
|
|
|
|
fp->mode.wreqq.data = htonl(0xf);
|
|
|
|
fw_asyreq(xfer->fc, -1, xfer);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_mgm_callback(struct fw_xfer *xfer)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
|
|
|
struct sbp_dev *sdev;
|
2003-05-05 14:50:24 +00:00
|
|
|
int resp;
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
sdev = (struct sbp_dev *)xfer->sc;
|
2003-05-05 14:50:24 +00:00
|
|
|
|
|
|
|
SBP_DEBUG(1)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s\n", __func__, sdev->bustgtlun);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2003-05-05 14:50:24 +00:00
|
|
|
resp = xfer->resp;
|
2003-04-17 03:38:03 +00:00
|
|
|
sbp_xfer_free(xfer);
|
2002-09-13 12:31:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-02-27 12:51:24 +00:00
|
|
|
static struct sbp_dev *
|
|
|
|
sbp_next_dev(struct sbp_target *target, int lun)
|
|
|
|
{
|
2003-10-18 04:59:47 +00:00
|
|
|
struct sbp_dev **sdevp;
|
2003-02-27 12:51:24 +00:00
|
|
|
int i;
|
|
|
|
|
2003-10-18 04:59:47 +00:00
|
|
|
for (i = lun, sdevp = &target->luns[lun]; i < target->num_lun;
|
|
|
|
i++, sdevp++)
|
|
|
|
if (*sdevp != NULL && (*sdevp)->status == SBP_DEV_PROBE)
|
|
|
|
return(*sdevp);
|
|
|
|
return(NULL);
|
2003-02-27 12:51:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define SCAN_PRI 1
|
2002-09-13 12:31:56 +00:00
|
|
|
static void
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_cam_scan_lun(struct cam_periph *periph, union ccb *ccb)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
2003-02-27 12:51:24 +00:00
|
|
|
struct sbp_target *target;
|
2002-09-13 12:31:56 +00:00
|
|
|
struct sbp_dev *sdev;
|
2003-02-27 12:51:24 +00:00
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
sdev = (struct sbp_dev *) ccb->ccb_h.ccb_sdev_ptr;
|
2003-02-27 12:51:24 +00:00
|
|
|
target = sdev->target;
|
2003-02-03 07:33:31 +00:00
|
|
|
SBP_DEBUG(0)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s\n", __func__, sdev->bustgtlun);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2003-02-27 12:51:24 +00:00
|
|
|
if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
|
|
|
|
sdev->status = SBP_DEV_ATTACHED;
|
|
|
|
} else {
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s failed\n", __func__, sdev->bustgtlun);
|
2003-02-27 12:51:24 +00:00
|
|
|
}
|
|
|
|
sdev = sbp_next_dev(target, sdev->lun_id + 1);
|
|
|
|
if (sdev == NULL) {
|
|
|
|
free(ccb, M_SBP);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* reuse ccb */
|
|
|
|
xpt_setup_ccb(&ccb->ccb_h, sdev->path, SCAN_PRI);
|
|
|
|
ccb->ccb_h.ccb_sdev_ptr = sdev;
|
|
|
|
xpt_action(ccb);
|
|
|
|
xpt_release_devq(sdev->path, sdev->freeze, TRUE);
|
|
|
|
sdev->freeze = 1;
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_cam_scan_target(void *arg)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
2003-02-27 12:51:24 +00:00
|
|
|
struct sbp_target *target = (struct sbp_target *)arg;
|
|
|
|
struct sbp_dev *sdev;
|
2003-02-13 13:35:57 +00:00
|
|
|
union ccb *ccb;
|
|
|
|
|
2003-02-27 12:51:24 +00:00
|
|
|
sdev = sbp_next_dev(target, 0);
|
|
|
|
if (sdev == NULL) {
|
|
|
|
printf("sbp_cam_scan_target: nothing to do for target%d\n",
|
|
|
|
target->target_id);
|
2003-02-13 13:35:57 +00:00
|
|
|
return;
|
|
|
|
}
|
2002-09-13 12:31:56 +00:00
|
|
|
SBP_DEBUG(0)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s\n", __func__, sdev->bustgtlun);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2003-02-27 12:51:24 +00:00
|
|
|
ccb = malloc(sizeof(union ccb), M_SBP, M_NOWAIT | M_ZERO);
|
|
|
|
if (ccb == NULL) {
|
|
|
|
printf("sbp_cam_scan_target: malloc failed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
xpt_setup_ccb(&ccb->ccb_h, sdev->path, SCAN_PRI);
|
2002-09-13 12:31:56 +00:00
|
|
|
ccb->ccb_h.func_code = XPT_SCAN_LUN;
|
2003-02-27 12:51:24 +00:00
|
|
|
ccb->ccb_h.cbfcnp = sbp_cam_scan_lun;
|
|
|
|
ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
|
2002-09-13 12:31:56 +00:00
|
|
|
ccb->crcn.flags = CAM_FLAG_NONE;
|
|
|
|
ccb->ccb_h.ccb_sdev_ptr = sdev;
|
|
|
|
|
|
|
|
/* The scan is in progress now. */
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(target->sbp);
|
2003-02-17 14:24:06 +00:00
|
|
|
xpt_action(ccb);
|
2003-02-27 12:51:24 +00:00
|
|
|
xpt_release_devq(sdev->path, sdev->freeze, TRUE);
|
|
|
|
sdev->freeze = 1;
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(target->sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
2003-02-27 12:51:24 +00:00
|
|
|
static __inline void
|
|
|
|
sbp_scan_dev(struct sbp_dev *sdev)
|
|
|
|
{
|
2003-02-17 14:24:06 +00:00
|
|
|
sdev->status = SBP_DEV_PROBE;
|
2003-11-10 03:51:23 +00:00
|
|
|
callout_reset(&sdev->target->scan_callout, scan_delay * hz / 1000,
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_cam_scan_target, (void *)sdev->target);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_do_attach(struct fw_xfer *xfer)
|
|
|
|
{
|
|
|
|
struct sbp_dev *sdev;
|
2003-02-27 12:51:24 +00:00
|
|
|
struct sbp_target *target;
|
|
|
|
struct sbp_softc *sbp;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
sdev = (struct sbp_dev *)xfer->sc;
|
2003-02-27 12:51:24 +00:00
|
|
|
target = sdev->target;
|
|
|
|
sbp = target->sbp;
|
2002-09-13 12:31:56 +00:00
|
|
|
SBP_DEBUG(0)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s\n", __func__, sdev->bustgtlun);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2003-04-17 03:38:03 +00:00
|
|
|
sbp_xfer_free(xfer);
|
2003-02-21 02:09:04 +00:00
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
if (sdev->path == NULL)
|
2013-04-14 09:55:48 +00:00
|
|
|
xpt_create_path(&sdev->path, NULL,
|
2003-02-27 12:51:24 +00:00
|
|
|
cam_sim_path(target->sbp->sim),
|
|
|
|
target->target_id, sdev->lun_id);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2003-02-21 02:09:04 +00:00
|
|
|
/*
|
|
|
|
* Let CAM scan the bus if we are in the boot process.
|
|
|
|
* XXX xpt_scan_bus cannot detect LUN larger than 0
|
|
|
|
* if LUN 0 doesn't exists.
|
|
|
|
*/
|
|
|
|
if (sbp_cold > 0) {
|
2003-02-27 12:51:24 +00:00
|
|
|
sdev->status = SBP_DEV_ATTACHED;
|
2003-02-21 02:09:04 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_scan_dev(sdev);
|
2002-09-13 12:31:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_agent_reset_callback(struct fw_xfer *xfer)
|
|
|
|
{
|
|
|
|
struct sbp_dev *sdev;
|
|
|
|
|
|
|
|
sdev = (struct sbp_dev *)xfer->sc;
|
|
|
|
SBP_DEBUG(1)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s\n", __func__, sdev->bustgtlun);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2003-05-05 14:50:24 +00:00
|
|
|
if (xfer->resp != 0) {
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s resp=%d\n", __func__, sdev->bustgtlun, xfer->resp);
|
2003-05-05 14:50:24 +00:00
|
|
|
}
|
|
|
|
|
2003-04-17 03:38:03 +00:00
|
|
|
sbp_xfer_free(xfer);
|
2003-02-27 12:51:24 +00:00
|
|
|
if (sdev->path) {
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sdev->target->sbp);
|
2003-02-27 12:51:24 +00:00
|
|
|
xpt_release_devq(sdev->path, sdev->freeze, TRUE);
|
|
|
|
sdev->freeze = 0;
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sdev->target->sbp);
|
2003-02-27 12:51:24 +00:00
|
|
|
}
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2003-02-04 17:08:45 +00:00
|
|
|
sbp_agent_reset(struct sbp_dev *sdev)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
|
|
|
struct fw_xfer *xfer;
|
|
|
|
struct fw_pkt *fp;
|
|
|
|
|
|
|
|
SBP_DEBUG(0)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s\n", __func__, sdev->bustgtlun);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
|
|
|
xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0x04);
|
|
|
|
if (xfer == NULL)
|
|
|
|
return;
|
2003-06-03 23:01:43 +00:00
|
|
|
if (sdev->status == SBP_DEV_ATTACHED || sdev->status == SBP_DEV_PROBE)
|
2007-03-16 05:39:33 +00:00
|
|
|
xfer->hand = sbp_agent_reset_callback;
|
2003-02-04 17:08:45 +00:00
|
|
|
else
|
2007-03-16 05:39:33 +00:00
|
|
|
xfer->hand = sbp_do_attach;
|
2003-10-02 04:06:56 +00:00
|
|
|
fp = &xfer->send.hdr;
|
2002-09-13 12:31:56 +00:00
|
|
|
fp->mode.wreqq.data = htonl(0xf);
|
|
|
|
fw_asyreq(xfer->fc, -1, xfer);
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_abort_all_ocbs(sdev, CAM_BDR_SENT);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_busy_timeout_callback(struct fw_xfer *xfer)
|
|
|
|
{
|
|
|
|
struct sbp_dev *sdev;
|
|
|
|
|
|
|
|
sdev = (struct sbp_dev *)xfer->sc;
|
|
|
|
SBP_DEBUG(1)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s\n", __func__, sdev->bustgtlun);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2003-04-17 03:38:03 +00:00
|
|
|
sbp_xfer_free(xfer);
|
2003-02-04 17:08:45 +00:00
|
|
|
sbp_agent_reset(sdev);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_busy_timeout(struct sbp_dev *sdev)
|
|
|
|
{
|
|
|
|
struct fw_pkt *fp;
|
|
|
|
struct fw_xfer *xfer;
|
|
|
|
SBP_DEBUG(0)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s\n", __func__, sdev->bustgtlun);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
|
|
|
xfer = sbp_write_cmd(sdev, FWTCODE_WREQQ, 0);
|
|
|
|
|
2007-03-16 05:39:33 +00:00
|
|
|
xfer->hand = sbp_busy_timeout_callback;
|
2003-10-02 04:06:56 +00:00
|
|
|
fp = &xfer->send.hdr;
|
2003-04-17 03:38:03 +00:00
|
|
|
fp->mode.wreqq.dest_hi = 0xffff;
|
|
|
|
fp->mode.wreqq.dest_lo = 0xf0000000 | BUSY_TIMEOUT;
|
2003-01-31 03:09:13 +00:00
|
|
|
fp->mode.wreqq.data = htonl((1 << (13+12)) | 0xf);
|
2002-09-13 12:31:56 +00:00
|
|
|
fw_asyreq(xfer->fc, -1, xfer);
|
|
|
|
}
|
|
|
|
|
2003-10-18 04:59:47 +00:00
|
|
|
static void
|
|
|
|
sbp_orb_pointer_callback(struct fw_xfer *xfer)
|
|
|
|
{
|
|
|
|
struct sbp_dev *sdev;
|
|
|
|
sdev = (struct sbp_dev *)xfer->sc;
|
|
|
|
|
2007-06-16 00:59:41 +00:00
|
|
|
SBP_DEBUG(2)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s\n", __func__, sdev->bustgtlun);
|
2003-10-18 04:59:47 +00:00
|
|
|
END_DEBUG
|
|
|
|
if (xfer->resp != 0) {
|
|
|
|
/* XXX */
|
2004-03-26 23:17:10 +00:00
|
|
|
printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
|
2003-10-18 04:59:47 +00:00
|
|
|
}
|
|
|
|
sbp_xfer_free(xfer);
|
2007-06-16 00:59:41 +00:00
|
|
|
|
|
|
|
SBP_LOCK(sdev->target->sbp);
|
2003-10-18 04:59:47 +00:00
|
|
|
sdev->flags &= ~ORB_POINTER_ACTIVE;
|
|
|
|
|
|
|
|
if ((sdev->flags & ORB_POINTER_NEED) != 0) {
|
|
|
|
struct sbp_ocb *ocb;
|
|
|
|
|
|
|
|
sdev->flags &= ~ORB_POINTER_NEED;
|
|
|
|
ocb = STAILQ_FIRST(&sdev->ocbs);
|
|
|
|
if (ocb != NULL)
|
|
|
|
sbp_orb_pointer(sdev, ocb);
|
|
|
|
}
|
2007-06-16 00:59:41 +00:00
|
|
|
SBP_UNLOCK(sdev->target->sbp);
|
2003-10-18 04:59:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
static void
|
|
|
|
sbp_orb_pointer(struct sbp_dev *sdev, struct sbp_ocb *ocb)
|
|
|
|
{
|
|
|
|
struct fw_xfer *xfer;
|
|
|
|
struct fw_pkt *fp;
|
2003-10-18 04:59:47 +00:00
|
|
|
SBP_DEBUG(1)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s 0x%08x\n",
|
|
|
|
__func__, sdev->bustgtlun,
|
|
|
|
(uint32_t)ocb->bus_addr);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
|
|
|
|
2007-06-16 00:59:41 +00:00
|
|
|
mtx_assert(&sdev->target->sbp->mtx, MA_OWNED);
|
|
|
|
|
2003-10-18 04:59:47 +00:00
|
|
|
if ((sdev->flags & ORB_POINTER_ACTIVE) != 0) {
|
2003-11-10 14:04:37 +00:00
|
|
|
SBP_DEBUG(0)
|
2004-03-26 23:17:10 +00:00
|
|
|
printf("%s: orb pointer active\n", __func__);
|
2003-11-10 14:04:37 +00:00
|
|
|
END_DEBUG
|
2003-10-18 04:59:47 +00:00
|
|
|
sdev->flags |= ORB_POINTER_NEED;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sdev->flags |= ORB_POINTER_ACTIVE;
|
2007-06-16 00:59:41 +00:00
|
|
|
xfer = sbp_write_cmd_locked(sdev, FWTCODE_WREQB, 0x08);
|
2002-09-13 12:31:56 +00:00
|
|
|
if (xfer == NULL)
|
|
|
|
return;
|
2007-03-16 05:39:33 +00:00
|
|
|
xfer->hand = sbp_orb_pointer_callback;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2003-10-02 04:06:56 +00:00
|
|
|
fp = &xfer->send.hdr;
|
2003-04-17 03:38:03 +00:00
|
|
|
fp->mode.wreqb.len = 8;
|
2002-09-13 12:31:56 +00:00
|
|
|
fp->mode.wreqb.extcode = 0;
|
2003-10-02 04:06:56 +00:00
|
|
|
xfer->send.payload[0] =
|
2002-09-13 12:31:56 +00:00
|
|
|
htonl(((sdev->target->sbp->fd.fc->nodeid | FWLOCALBUS )<< 16));
|
2004-05-22 16:14:17 +00:00
|
|
|
xfer->send.payload[1] = htonl((uint32_t)ocb->bus_addr);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2009-02-01 23:28:52 +00:00
|
|
|
/*
|
|
|
|
* sbp_xfer_free() will attempt to acquire
|
|
|
|
* the SBP lock on entrance. Also, this removes
|
|
|
|
* a LOR between the firewire layer and sbp
|
|
|
|
*/
|
|
|
|
SBP_UNLOCK(sdev->target->sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
if(fw_asyreq(xfer->fc, -1, xfer) != 0){
|
2003-04-17 03:38:03 +00:00
|
|
|
sbp_xfer_free(xfer);
|
2002-09-13 12:31:56 +00:00
|
|
|
ocb->ccb->ccb_h.status = CAM_REQ_INVALID;
|
|
|
|
xpt_done(ocb->ccb);
|
|
|
|
}
|
2009-02-01 23:28:52 +00:00
|
|
|
SBP_LOCK(sdev->target->sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
2003-10-18 04:59:47 +00:00
|
|
|
static void
|
2004-03-26 23:17:10 +00:00
|
|
|
sbp_doorbell_callback(struct fw_xfer *xfer)
|
2003-10-18 04:59:47 +00:00
|
|
|
{
|
|
|
|
struct sbp_dev *sdev;
|
|
|
|
sdev = (struct sbp_dev *)xfer->sc;
|
2004-03-26 23:17:10 +00:00
|
|
|
|
|
|
|
SBP_DEBUG(1)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s\n", __func__, sdev->bustgtlun);
|
2003-10-18 04:59:47 +00:00
|
|
|
END_DEBUG
|
|
|
|
if (xfer->resp != 0) {
|
|
|
|
/* XXX */
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s: xfer->resp = %d\n", __func__, xfer->resp);
|
2003-10-18 04:59:47 +00:00
|
|
|
}
|
|
|
|
sbp_xfer_free(xfer);
|
2004-03-26 23:17:10 +00:00
|
|
|
sdev->flags &= ~ORB_DOORBELL_ACTIVE;
|
|
|
|
if ((sdev->flags & ORB_DOORBELL_NEED) != 0) {
|
|
|
|
sdev->flags &= ~ORB_DOORBELL_NEED;
|
2007-06-16 00:59:41 +00:00
|
|
|
SBP_LOCK(sdev->target->sbp);
|
2004-03-26 23:17:10 +00:00
|
|
|
sbp_doorbell(sdev);
|
2007-06-16 00:59:41 +00:00
|
|
|
SBP_UNLOCK(sdev->target->sbp);
|
2004-03-26 23:17:10 +00:00
|
|
|
}
|
2003-10-18 04:59:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
static void
|
|
|
|
sbp_doorbell(struct sbp_dev *sdev)
|
|
|
|
{
|
|
|
|
struct fw_xfer *xfer;
|
|
|
|
struct fw_pkt *fp;
|
|
|
|
SBP_DEBUG(1)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s\n", __func__, sdev->bustgtlun);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
|
|
|
|
2004-03-26 23:17:10 +00:00
|
|
|
if ((sdev->flags & ORB_DOORBELL_ACTIVE) != 0) {
|
|
|
|
sdev->flags |= ORB_DOORBELL_NEED;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sdev->flags |= ORB_DOORBELL_ACTIVE;
|
2007-06-16 00:59:41 +00:00
|
|
|
xfer = sbp_write_cmd_locked(sdev, FWTCODE_WREQQ, 0x10);
|
2002-09-13 12:31:56 +00:00
|
|
|
if (xfer == NULL)
|
|
|
|
return;
|
2007-03-16 05:39:33 +00:00
|
|
|
xfer->hand = sbp_doorbell_callback;
|
2004-03-26 23:17:10 +00:00
|
|
|
fp = &xfer->send.hdr;
|
2002-09-13 12:31:56 +00:00
|
|
|
fp->mode.wreqq.data = htonl(0xf);
|
|
|
|
fw_asyreq(xfer->fc, -1, xfer);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct fw_xfer *
|
2007-06-16 00:59:41 +00:00
|
|
|
sbp_write_cmd_locked(struct sbp_dev *sdev, int tcode, int offset)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
|
|
|
struct fw_xfer *xfer;
|
|
|
|
struct fw_pkt *fp;
|
2003-04-17 03:38:03 +00:00
|
|
|
struct sbp_target *target;
|
|
|
|
int s, new = 0;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2007-06-16 00:59:41 +00:00
|
|
|
mtx_assert(&sdev->target->sbp->mtx, MA_OWNED);
|
|
|
|
|
2003-04-17 03:38:03 +00:00
|
|
|
target = sdev->target;
|
|
|
|
s = splfw();
|
|
|
|
xfer = STAILQ_FIRST(&target->xferlist);
|
|
|
|
if (xfer == NULL) {
|
|
|
|
if (target->n_xfer > 5 /* XXX */) {
|
|
|
|
printf("sbp: no more xfer for this target\n");
|
|
|
|
splx(s);
|
|
|
|
return(NULL);
|
|
|
|
}
|
2003-10-02 04:06:56 +00:00
|
|
|
xfer = fw_xfer_alloc_buf(M_SBP, 8, 0);
|
2003-04-17 03:38:03 +00:00
|
|
|
if(xfer == NULL){
|
|
|
|
printf("sbp: fw_xfer_alloc_buf failed\n");
|
|
|
|
splx(s);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
target->n_xfer ++;
|
|
|
|
if (debug)
|
|
|
|
printf("sbp: alloc %d xfer\n", target->n_xfer);
|
|
|
|
new = 1;
|
|
|
|
} else {
|
|
|
|
STAILQ_REMOVE_HEAD(&target->xferlist, link);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
2003-04-17 03:38:03 +00:00
|
|
|
splx(s);
|
|
|
|
|
|
|
|
if (new) {
|
2003-10-02 04:06:56 +00:00
|
|
|
xfer->recv.pay_len = 0;
|
|
|
|
xfer->send.spd = min(sdev->target->fwdev->speed, max_speed);
|
2003-04-17 03:38:03 +00:00
|
|
|
xfer->fc = sdev->target->sbp->fd.fc;
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
2003-10-02 04:06:56 +00:00
|
|
|
|
|
|
|
if (tcode == FWTCODE_WREQB)
|
|
|
|
xfer->send.pay_len = 8;
|
|
|
|
else
|
|
|
|
xfer->send.pay_len = 0;
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
xfer->sc = (caddr_t)sdev;
|
2003-10-02 04:06:56 +00:00
|
|
|
fp = &xfer->send.hdr;
|
2003-04-17 03:38:03 +00:00
|
|
|
fp->mode.wreqq.dest_hi = sdev->login->cmd_hi;
|
|
|
|
fp->mode.wreqq.dest_lo = sdev->login->cmd_lo + offset;
|
2002-09-13 12:31:56 +00:00
|
|
|
fp->mode.wreqq.tlrt = 0;
|
|
|
|
fp->mode.wreqq.tcode = tcode;
|
|
|
|
fp->mode.wreqq.pri = 0;
|
2003-10-02 04:06:56 +00:00
|
|
|
fp->mode.wreqq.dst = FWLOCALBUS | sdev->target->fwdev->dst;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
return xfer;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-06-16 00:59:41 +00:00
|
|
|
static struct fw_xfer *
|
|
|
|
sbp_write_cmd(struct sbp_dev *sdev, int tcode, int offset)
|
|
|
|
{
|
|
|
|
struct sbp_softc *sbp = sdev->target->sbp;
|
|
|
|
struct fw_xfer *xfer;
|
|
|
|
|
|
|
|
SBP_LOCK(sbp);
|
|
|
|
xfer = sbp_write_cmd_locked(sdev, tcode, offset);
|
|
|
|
SBP_UNLOCK(sbp);
|
|
|
|
|
|
|
|
return (xfer);
|
|
|
|
}
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
static void
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_mgm_orb(struct sbp_dev *sdev, int func, struct sbp_ocb *aocb)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
|
|
|
struct fw_xfer *xfer;
|
|
|
|
struct fw_pkt *fp;
|
|
|
|
struct sbp_ocb *ocb;
|
2003-02-27 12:51:24 +00:00
|
|
|
struct sbp_target *target;
|
2002-09-13 12:31:56 +00:00
|
|
|
int s, nid;
|
|
|
|
|
2003-02-27 12:51:24 +00:00
|
|
|
target = sdev->target;
|
|
|
|
nid = target->sbp->fd.fc->nodeid | FWLOCALBUS;
|
|
|
|
|
|
|
|
s = splfw();
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(target->sbp);
|
2003-02-27 12:51:24 +00:00
|
|
|
if (func == ORB_FUN_RUNQUEUE) {
|
|
|
|
ocb = STAILQ_FIRST(&target->mgm_ocb_queue);
|
|
|
|
if (target->mgm_ocb_cur != NULL || ocb == NULL) {
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(target->sbp);
|
2003-02-27 12:51:24 +00:00
|
|
|
splx(s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
STAILQ_REMOVE_HEAD(&target->mgm_ocb_queue, ocb);
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(target->sbp);
|
2003-02-27 12:51:24 +00:00
|
|
|
goto start;
|
|
|
|
}
|
2003-04-17 03:38:03 +00:00
|
|
|
if ((ocb = sbp_get_ocb(sdev)) == NULL) {
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(target->sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
splx(s);
|
2003-11-12 03:45:10 +00:00
|
|
|
/* XXX */
|
2002-09-13 12:31:56 +00:00
|
|
|
return;
|
|
|
|
}
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(target->sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
ocb->flags = OCB_ACT_MGM;
|
|
|
|
ocb->sdev = sdev;
|
|
|
|
|
2003-10-02 04:06:56 +00:00
|
|
|
bzero((void *)ocb->orb, sizeof(ocb->orb));
|
2002-09-13 12:31:56 +00:00
|
|
|
ocb->orb[6] = htonl((nid << 16) | SBP_BIND_HI);
|
2003-10-02 04:06:56 +00:00
|
|
|
ocb->orb[7] = htonl(SBP_DEV2ADDR(target->target_id, sdev->lun_id));
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2002-12-06 02:17:30 +00:00
|
|
|
SBP_DEBUG(0)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s %s\n",
|
|
|
|
__func__,sdev->bustgtlun,
|
|
|
|
orb_fun_name[(func>>16)&0xf]);
|
2002-12-06 02:17:30 +00:00
|
|
|
END_DEBUG
|
2002-09-13 12:31:56 +00:00
|
|
|
switch (func) {
|
|
|
|
case ORB_FUN_LGI:
|
2003-10-02 04:06:56 +00:00
|
|
|
ocb->orb[0] = ocb->orb[1] = 0; /* password */
|
2002-09-13 12:31:56 +00:00
|
|
|
ocb->orb[2] = htonl(nid << 16);
|
2003-04-17 03:38:03 +00:00
|
|
|
ocb->orb[3] = htonl(sdev->dma.bus_addr);
|
2003-10-31 12:05:55 +00:00
|
|
|
ocb->orb[4] = htonl(ORB_NOTIFY | sdev->lun_id);
|
2003-11-10 03:51:23 +00:00
|
|
|
if (ex_login)
|
2003-10-31 12:05:55 +00:00
|
|
|
ocb->orb[4] |= htonl(ORB_EXV);
|
2003-04-17 03:38:03 +00:00
|
|
|
ocb->orb[5] = htonl(SBP_LOGIN_SIZE);
|
|
|
|
fwdma_sync(&sdev->dma, BUS_DMASYNC_PREREAD);
|
2002-09-13 12:31:56 +00:00
|
|
|
break;
|
2003-02-04 17:08:45 +00:00
|
|
|
case ORB_FUN_ATA:
|
2003-02-27 12:51:24 +00:00
|
|
|
ocb->orb[0] = htonl((0 << 16) | 0);
|
2003-04-17 03:38:03 +00:00
|
|
|
ocb->orb[1] = htonl(aocb->bus_addr & 0xffffffff);
|
2003-02-04 17:08:45 +00:00
|
|
|
/* fall through */
|
2002-09-13 12:31:56 +00:00
|
|
|
case ORB_FUN_RCN:
|
|
|
|
case ORB_FUN_LGO:
|
|
|
|
case ORB_FUN_LUR:
|
|
|
|
case ORB_FUN_RST:
|
|
|
|
case ORB_FUN_ATS:
|
2003-04-17 03:38:03 +00:00
|
|
|
ocb->orb[4] = htonl(ORB_NOTIFY | func | sdev->login->id);
|
2002-09-13 12:31:56 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2003-02-27 12:51:24 +00:00
|
|
|
if (target->mgm_ocb_cur != NULL) {
|
|
|
|
/* there is a standing ORB */
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(target->sbp);
|
2003-02-27 12:51:24 +00:00
|
|
|
STAILQ_INSERT_TAIL(&sdev->target->mgm_ocb_queue, ocb, ocb);
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(target->sbp);
|
2003-02-27 12:51:24 +00:00
|
|
|
splx(s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
start:
|
|
|
|
target->mgm_ocb_cur = ocb;
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
callout_reset(&target->mgm_ocb_timeout, 5*hz,
|
2003-05-05 14:50:24 +00:00
|
|
|
sbp_mgm_timeout, (caddr_t)ocb);
|
2002-09-13 12:31:56 +00:00
|
|
|
xfer = sbp_write_cmd(sdev, FWTCODE_WREQB, 0);
|
|
|
|
if(xfer == NULL){
|
|
|
|
return;
|
|
|
|
}
|
2007-03-16 05:39:33 +00:00
|
|
|
xfer->hand = sbp_mgm_callback;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2003-10-02 04:06:56 +00:00
|
|
|
fp = &xfer->send.hdr;
|
2003-04-17 03:38:03 +00:00
|
|
|
fp->mode.wreqb.dest_hi = sdev->target->mgm_hi;
|
|
|
|
fp->mode.wreqb.dest_lo = sdev->target->mgm_lo;
|
|
|
|
fp->mode.wreqb.len = 8;
|
2002-09-13 12:31:56 +00:00
|
|
|
fp->mode.wreqb.extcode = 0;
|
2003-10-02 04:06:56 +00:00
|
|
|
xfer->send.payload[0] = htonl(nid << 16);
|
|
|
|
xfer->send.payload[1] = htonl(ocb->bus_addr & 0xffffffff);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
fw_asyreq(xfer->fc, -1, xfer);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-10-23 13:04:02 +00:00
|
|
|
sbp_print_scsi_cmd(struct sbp_ocb *ocb)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
|
|
|
struct ccb_scsiio *csio;
|
|
|
|
|
|
|
|
csio = &ocb->ccb->csio;
|
|
|
|
printf("%s:%d:%d XPT_SCSI_IO: "
|
|
|
|
"cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x"
|
|
|
|
", flags: 0x%02x, "
|
|
|
|
"%db cmd/%db data/%db sense\n",
|
|
|
|
device_get_nameunit(ocb->sdev->target->sbp->fd.dev),
|
|
|
|
ocb->ccb->ccb_h.target_id, ocb->ccb->ccb_h.target_lun,
|
|
|
|
csio->cdb_io.cdb_bytes[0],
|
|
|
|
csio->cdb_io.cdb_bytes[1],
|
|
|
|
csio->cdb_io.cdb_bytes[2],
|
|
|
|
csio->cdb_io.cdb_bytes[3],
|
|
|
|
csio->cdb_io.cdb_bytes[4],
|
|
|
|
csio->cdb_io.cdb_bytes[5],
|
|
|
|
csio->cdb_io.cdb_bytes[6],
|
|
|
|
csio->cdb_io.cdb_bytes[7],
|
|
|
|
csio->cdb_io.cdb_bytes[8],
|
|
|
|
csio->cdb_io.cdb_bytes[9],
|
|
|
|
ocb->ccb->ccb_h.flags & CAM_DIR_MASK,
|
|
|
|
csio->cdb_len, csio->dxfer_len,
|
|
|
|
csio->sense_len);
|
2002-10-23 13:04:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_scsi_status(struct sbp_status *sbp_status, struct sbp_ocb *ocb)
|
|
|
|
{
|
|
|
|
struct sbp_cmd_status *sbp_cmd_status;
|
Add descriptor sense support to CAM, and honor sense residuals properly in
CAM.
Desriptor sense is a new sense data format that originated in SPC-3. Among
other things, it allows for an 8-byte info field, which is necessary to
pass back block numbers larger than 4 bytes.
This change adds a number of new functions to scsi_all.c (and therefore
libcam) that abstract out most access to sense data.
This includes a bump of CAM_VERSION, because the CCB ABI has changed.
Userland programs that use the CAM pass(4) driver will need to be
recompiled.
camcontrol.c: Change uses of scsi_extract_sense() to use
scsi_extract_sense_len().
Use scsi_get_sks() instead of accessing sense key specific
data directly.
scsi_modes: Update the control mode page to the latest version (SPC-4).
scsi_cmds.c,
scsi_target.c: Change references to struct scsi_sense_data to struct
scsi_sense_data_fixed. This should be changed to allow the
user to specify fixed or descriptor sense, and then use
scsi_set_sense_data() to build the sense data.
ps3cdrom.c: Use scsi_set_sense_data() instead of setting sense data
manually.
cam_periph.c: Use scsi_extract_sense_len() instead of using
scsi_extract_sense() or accessing sense data directly.
cam_ccb.h: Bump the CAM_VERSION from 0x15 to 0x16. The change of
struct scsi_sense_data from 32 to 252 bytes changes the
size of struct ccb_scsiio, but not the size of union ccb.
So the version must be bumped to prevent structure
mis-matches.
scsi_all.h: Lots of updated SCSI sense data and other structures.
Add function prototypes for the new sense data functions.
Take out the inline implementation of scsi_extract_sense().
It is now too large to put in a header file.
Add macros to calculate whether fields are present and
filled in fixed and descriptor sense data
scsi_all.c: In scsi_op_desc(), allow the user to pass in NULL inquiry
data, and we'll assume a direct access device in that case.
Changed the SCSI RESERVED sense key name and description
to COMPLETED, as it is now defined in the spec.
Change the error recovery action for a number of read errors
to prevent lots of retries when the drive has said that the
block isn't accessible. This speeds up reconstruction of
the block by any RAID software running on top of the drive
(e.g. ZFS).
In scsi_sense_desc(), allow for invalid sense key numbers.
This allows calling this routine without checking the input
values first.
Change scsi_error_action() to use scsi_extract_sense_len(),
and handle things when invalid asc/ascq values are
encountered.
Add a new routine, scsi_desc_iterate(), that will call the
supplied function for every descriptor in descriptor format
sense data.
Add scsi_set_sense_data(), and scsi_set_sense_data_va(),
which build descriptor and fixed format sense data. They
currently default to fixed format sense data.
Add a number of scsi_get_*() functions, which get different
types of sense data fields from either fixed or descriptor
format sense data, if the data is present.
Add a number of scsi_*_sbuf() functions, which print
formatted versions of various sense data fields. These
functions work for either fixed or descriptor sense.
Add a number of scsi_sense_*_sbuf() functions, which have a
standard calling interface and print the indicated field.
These functions take descriptors only.
Add scsi_sense_desc_sbuf(), which will print a formatted
version of the given sense descriptor.
Pull out a majority of the scsi_sense_sbuf() function and
put it into scsi_sense_only_sbuf(). This allows callers
that don't use struct ccb_scsiio to easily utilize the
printing routines. Revamp that function to handle
descriptor sense and use the new sense fetching and
printing routines.
Move scsi_extract_sense() into scsi_all.c, and implement it
in terms of the new function, scsi_extract_sense_len().
The _len() version takes a length (which should be the
sense length - residual) and can indicate which fields are
present and valid in the sense data.
Add a couple of new scsi_get_*() routines to get the sense
key, asc, and ascq only.
mly.c: Rename struct scsi_sense_data to struct
scsi_sense_data_fixed.
sbp_targ.c: Use the new sense fetching routines to get sense data
instead of accessing it directly.
sbp.c: Change the firewire/SCSI sense data transformation code to
use struct scsi_sense_data_fixed instead of struct
scsi_sense_data. This should be changed later to use
scsi_set_sense_data().
ciss.c: Calculate the sense residual properly. Use
scsi_get_sense_key() to fetch the sense key.
mps_sas.c,
mpt_cam.c: Set the sense residual properly.
iir.c: Use scsi_set_sense_data() instead of building sense data by
hand.
iscsi_subr.c: Use scsi_extract_sense_len() instead of grabbing sense data
directly.
umass.c: Use scsi_set_sense_data() to build sense data.
Grab the sense key using scsi_get_sense_key().
Calculate the sense residual properly.
isp_freebsd.h: Use scsi_get_*() routines to grab asc, ascq, and sense key
values.
Calculate and set the sense residual.
MFC after: 3 days
Sponsored by: Spectra Logic Corporation
2011-10-03 20:32:55 +00:00
|
|
|
struct scsi_sense_data_fixed *sense;
|
2002-10-23 13:04:02 +00:00
|
|
|
|
|
|
|
sbp_cmd_status = (struct sbp_cmd_status *)sbp_status->data;
|
Add descriptor sense support to CAM, and honor sense residuals properly in
CAM.
Desriptor sense is a new sense data format that originated in SPC-3. Among
other things, it allows for an 8-byte info field, which is necessary to
pass back block numbers larger than 4 bytes.
This change adds a number of new functions to scsi_all.c (and therefore
libcam) that abstract out most access to sense data.
This includes a bump of CAM_VERSION, because the CCB ABI has changed.
Userland programs that use the CAM pass(4) driver will need to be
recompiled.
camcontrol.c: Change uses of scsi_extract_sense() to use
scsi_extract_sense_len().
Use scsi_get_sks() instead of accessing sense key specific
data directly.
scsi_modes: Update the control mode page to the latest version (SPC-4).
scsi_cmds.c,
scsi_target.c: Change references to struct scsi_sense_data to struct
scsi_sense_data_fixed. This should be changed to allow the
user to specify fixed or descriptor sense, and then use
scsi_set_sense_data() to build the sense data.
ps3cdrom.c: Use scsi_set_sense_data() instead of setting sense data
manually.
cam_periph.c: Use scsi_extract_sense_len() instead of using
scsi_extract_sense() or accessing sense data directly.
cam_ccb.h: Bump the CAM_VERSION from 0x15 to 0x16. The change of
struct scsi_sense_data from 32 to 252 bytes changes the
size of struct ccb_scsiio, but not the size of union ccb.
So the version must be bumped to prevent structure
mis-matches.
scsi_all.h: Lots of updated SCSI sense data and other structures.
Add function prototypes for the new sense data functions.
Take out the inline implementation of scsi_extract_sense().
It is now too large to put in a header file.
Add macros to calculate whether fields are present and
filled in fixed and descriptor sense data
scsi_all.c: In scsi_op_desc(), allow the user to pass in NULL inquiry
data, and we'll assume a direct access device in that case.
Changed the SCSI RESERVED sense key name and description
to COMPLETED, as it is now defined in the spec.
Change the error recovery action for a number of read errors
to prevent lots of retries when the drive has said that the
block isn't accessible. This speeds up reconstruction of
the block by any RAID software running on top of the drive
(e.g. ZFS).
In scsi_sense_desc(), allow for invalid sense key numbers.
This allows calling this routine without checking the input
values first.
Change scsi_error_action() to use scsi_extract_sense_len(),
and handle things when invalid asc/ascq values are
encountered.
Add a new routine, scsi_desc_iterate(), that will call the
supplied function for every descriptor in descriptor format
sense data.
Add scsi_set_sense_data(), and scsi_set_sense_data_va(),
which build descriptor and fixed format sense data. They
currently default to fixed format sense data.
Add a number of scsi_get_*() functions, which get different
types of sense data fields from either fixed or descriptor
format sense data, if the data is present.
Add a number of scsi_*_sbuf() functions, which print
formatted versions of various sense data fields. These
functions work for either fixed or descriptor sense.
Add a number of scsi_sense_*_sbuf() functions, which have a
standard calling interface and print the indicated field.
These functions take descriptors only.
Add scsi_sense_desc_sbuf(), which will print a formatted
version of the given sense descriptor.
Pull out a majority of the scsi_sense_sbuf() function and
put it into scsi_sense_only_sbuf(). This allows callers
that don't use struct ccb_scsiio to easily utilize the
printing routines. Revamp that function to handle
descriptor sense and use the new sense fetching and
printing routines.
Move scsi_extract_sense() into scsi_all.c, and implement it
in terms of the new function, scsi_extract_sense_len().
The _len() version takes a length (which should be the
sense length - residual) and can indicate which fields are
present and valid in the sense data.
Add a couple of new scsi_get_*() routines to get the sense
key, asc, and ascq only.
mly.c: Rename struct scsi_sense_data to struct
scsi_sense_data_fixed.
sbp_targ.c: Use the new sense fetching routines to get sense data
instead of accessing it directly.
sbp.c: Change the firewire/SCSI sense data transformation code to
use struct scsi_sense_data_fixed instead of struct
scsi_sense_data. This should be changed later to use
scsi_set_sense_data().
ciss.c: Calculate the sense residual properly. Use
scsi_get_sense_key() to fetch the sense key.
mps_sas.c,
mpt_cam.c: Set the sense residual properly.
iir.c: Use scsi_set_sense_data() instead of building sense data by
hand.
iscsi_subr.c: Use scsi_extract_sense_len() instead of grabbing sense data
directly.
umass.c: Use scsi_set_sense_data() to build sense data.
Grab the sense key using scsi_get_sense_key().
Calculate the sense residual properly.
isp_freebsd.h: Use scsi_get_*() routines to grab asc, ascq, and sense key
values.
Calculate and set the sense residual.
MFC after: 3 days
Sponsored by: Spectra Logic Corporation
2011-10-03 20:32:55 +00:00
|
|
|
sense = (struct scsi_sense_data_fixed *)&ocb->ccb->csio.sense_data;
|
2002-10-23 13:04:02 +00:00
|
|
|
|
|
|
|
SBP_DEBUG(0)
|
|
|
|
sbp_print_scsi_cmd(ocb);
|
2002-09-13 12:31:56 +00:00
|
|
|
/* XXX need decode status */
|
2009-02-18 18:41:34 +00:00
|
|
|
printf("%s: SCSI status %x sfmt %x valid %x key %x code %x qlfr %x len %d\n",
|
|
|
|
ocb->sdev->bustgtlun,
|
2002-09-13 12:31:56 +00:00
|
|
|
sbp_cmd_status->status,
|
|
|
|
sbp_cmd_status->sfmt,
|
|
|
|
sbp_cmd_status->valid,
|
|
|
|
sbp_cmd_status->s_key,
|
|
|
|
sbp_cmd_status->s_code,
|
|
|
|
sbp_cmd_status->s_qlfr,
|
2009-02-18 18:41:34 +00:00
|
|
|
sbp_status->len);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
|
|
|
|
2003-01-30 05:12:56 +00:00
|
|
|
switch (sbp_cmd_status->status) {
|
|
|
|
case SCSI_STATUS_CHECK_COND:
|
|
|
|
case SCSI_STATUS_BUSY:
|
|
|
|
case SCSI_STATUS_CMD_TERMINATED:
|
2002-09-13 12:31:56 +00:00
|
|
|
if(sbp_cmd_status->sfmt == SBP_SFMT_CURR){
|
|
|
|
sense->error_code = SSD_CURRENT_ERROR;
|
|
|
|
}else{
|
|
|
|
sense->error_code = SSD_DEFERRED_ERROR;
|
|
|
|
}
|
|
|
|
if(sbp_cmd_status->valid)
|
|
|
|
sense->error_code |= SSD_ERRCODE_VALID;
|
|
|
|
sense->flags = sbp_cmd_status->s_key;
|
|
|
|
if(sbp_cmd_status->mark)
|
|
|
|
sense->flags |= SSD_FILEMARK;
|
|
|
|
if(sbp_cmd_status->eom)
|
|
|
|
sense->flags |= SSD_EOM;
|
|
|
|
if(sbp_cmd_status->ill_len)
|
|
|
|
sense->flags |= SSD_ILI;
|
2003-08-29 13:36:17 +00:00
|
|
|
|
|
|
|
bcopy(&sbp_cmd_status->info, &sense->info[0], 4);
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
if (sbp_status->len <= 1)
|
|
|
|
/* XXX not scsi status. shouldn't be happened */
|
|
|
|
sense->extra_len = 0;
|
|
|
|
else if (sbp_status->len <= 4)
|
|
|
|
/* add_sense_code(_qual), info, cmd_spec_info */
|
|
|
|
sense->extra_len = 6;
|
|
|
|
else
|
|
|
|
/* fru, sense_key_spec */
|
|
|
|
sense->extra_len = 10;
|
2003-08-29 13:36:17 +00:00
|
|
|
|
|
|
|
bcopy(&sbp_cmd_status->cdb, &sense->cmd_spec_info[0], 4);
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
sense->add_sense_code = sbp_cmd_status->s_code;
|
|
|
|
sense->add_sense_code_qual = sbp_cmd_status->s_qlfr;
|
|
|
|
sense->fru = sbp_cmd_status->fru;
|
2003-08-29 13:36:17 +00:00
|
|
|
|
|
|
|
bcopy(&sbp_cmd_status->s_keydep[0],
|
|
|
|
&sense->sense_key_spec[0], 3);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2010-01-07 21:01:37 +00:00
|
|
|
ocb->ccb->csio.scsi_status = sbp_cmd_status->status;
|
2002-09-13 12:31:56 +00:00
|
|
|
ocb->ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
|
|
|
|
| CAM_AUTOSNS_VALID;
|
|
|
|
/*
|
|
|
|
{
|
2004-05-22 16:14:17 +00:00
|
|
|
uint8_t j, *tmp;
|
2002-09-13 12:31:56 +00:00
|
|
|
tmp = sense;
|
|
|
|
for( j = 0 ; j < 32 ; j+=8){
|
|
|
|
printf("sense %02x%02x %02x%02x %02x%02x %02x%02x\n",
|
|
|
|
tmp[j], tmp[j+1], tmp[j+2], tmp[j+3],
|
|
|
|
tmp[j+4], tmp[j+5], tmp[j+6], tmp[j+7]);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
*/
|
2003-01-30 05:12:56 +00:00
|
|
|
break;
|
|
|
|
default:
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(ocb->sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s unknown scsi status 0x%x\n",
|
|
|
|
__func__, ocb->sdev->bustgtlun,
|
|
|
|
sbp_cmd_status->status);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_fix_inq_data(struct sbp_ocb *ocb)
|
|
|
|
{
|
|
|
|
union ccb *ccb;
|
|
|
|
struct sbp_dev *sdev;
|
|
|
|
struct scsi_inquiry_data *inq;
|
|
|
|
|
|
|
|
ccb = ocb->ccb;
|
|
|
|
sdev = ocb->sdev;
|
|
|
|
|
|
|
|
if (ccb->csio.cdb_io.cdb_bytes[1] & SI_EVPD)
|
|
|
|
return;
|
|
|
|
SBP_DEBUG(1)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s\n", __func__, sdev->bustgtlun);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
|
|
|
inq = (struct scsi_inquiry_data *) ccb->csio.data_ptr;
|
|
|
|
switch (SID_TYPE(inq)) {
|
|
|
|
case T_DIRECT:
|
2003-08-01 02:24:39 +00:00
|
|
|
#if 0
|
2002-09-13 12:31:56 +00:00
|
|
|
/*
|
|
|
|
* XXX Convert Direct Access device to RBC.
|
2002-12-26 06:50:09 +00:00
|
|
|
* I've never seen FireWire DA devices which support READ_6.
|
2002-09-13 12:31:56 +00:00
|
|
|
*/
|
|
|
|
if (SID_TYPE(inq) == T_DIRECT)
|
|
|
|
inq->device |= T_RBC; /* T_DIRECT == 0 */
|
|
|
|
#endif
|
|
|
|
/* fall through */
|
|
|
|
case T_RBC:
|
|
|
|
/*
|
|
|
|
* Override vendor/product/revision information.
|
|
|
|
* Some devices sometimes return strange strings.
|
|
|
|
*/
|
2003-02-27 12:51:24 +00:00
|
|
|
#if 1
|
2002-09-13 12:31:56 +00:00
|
|
|
bcopy(sdev->vendor, inq->vendor, sizeof(inq->vendor));
|
|
|
|
bcopy(sdev->product, inq->product, sizeof(inq->product));
|
|
|
|
bcopy(sdev->revision+2, inq->revision, sizeof(inq->revision));
|
2003-02-27 12:51:24 +00:00
|
|
|
#endif
|
2002-09-13 12:31:56 +00:00
|
|
|
break;
|
|
|
|
}
|
2004-03-26 23:17:10 +00:00
|
|
|
/*
|
|
|
|
* Force to enable/disable tagged queuing.
|
|
|
|
* XXX CAM also checks SCP_QUEUE_DQUE flag in the control mode page.
|
|
|
|
*/
|
|
|
|
if (sbp_tags > 0)
|
|
|
|
inq->flags |= SID_CmdQue;
|
|
|
|
else if (sbp_tags < 0)
|
|
|
|
inq->flags &= ~SID_CmdQue;
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2003-04-17 03:38:03 +00:00
|
|
|
sbp_recv1(struct fw_xfer *xfer)
|
|
|
|
{
|
2002-09-13 12:31:56 +00:00
|
|
|
struct fw_pkt *rfp;
|
|
|
|
#if NEED_RESPONSE
|
|
|
|
struct fw_pkt *sfp;
|
|
|
|
#endif
|
|
|
|
struct sbp_softc *sbp;
|
|
|
|
struct sbp_dev *sdev;
|
|
|
|
struct sbp_ocb *ocb;
|
|
|
|
struct sbp_login_res *login_res = NULL;
|
|
|
|
struct sbp_status *sbp_status;
|
|
|
|
struct sbp_target *target;
|
2003-03-01 16:50:40 +00:00
|
|
|
int orb_fun, status_valid0, status_valid, t, l, reset_agent = 0;
|
2004-05-22 16:14:17 +00:00
|
|
|
uint32_t addr;
|
2002-09-13 12:31:56 +00:00
|
|
|
/*
|
2004-05-22 16:14:17 +00:00
|
|
|
uint32_t *ld;
|
2002-09-13 12:31:56 +00:00
|
|
|
ld = xfer->recv.buf;
|
|
|
|
printf("sbp %x %d %d %08x %08x %08x %08x\n",
|
|
|
|
xfer->resp, xfer->recv.len, xfer->recv.off, ntohl(ld[0]), ntohl(ld[1]), ntohl(ld[2]), ntohl(ld[3]));
|
|
|
|
printf("sbp %08x %08x %08x %08x\n", ntohl(ld[4]), ntohl(ld[5]), ntohl(ld[6]), ntohl(ld[7]));
|
|
|
|
printf("sbp %08x %08x %08x %08x\n", ntohl(ld[8]), ntohl(ld[9]), ntohl(ld[10]), ntohl(ld[11]));
|
|
|
|
*/
|
2003-04-17 03:38:03 +00:00
|
|
|
sbp = (struct sbp_softc *)xfer->sc;
|
2003-10-02 04:06:56 +00:00
|
|
|
if (xfer->resp != 0){
|
2003-11-12 04:06:21 +00:00
|
|
|
printf("sbp_recv: xfer->resp = %d\n", xfer->resp);
|
2003-04-17 03:38:03 +00:00
|
|
|
goto done0;
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
2003-10-02 04:06:56 +00:00
|
|
|
if (xfer->recv.payload == NULL){
|
|
|
|
printf("sbp_recv: xfer->recv.payload == NULL\n");
|
2003-04-17 03:38:03 +00:00
|
|
|
goto done0;
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
2003-10-02 04:06:56 +00:00
|
|
|
rfp = &xfer->recv.hdr;
|
2002-09-13 12:31:56 +00:00
|
|
|
if(rfp->mode.wreqb.tcode != FWTCODE_WREQB){
|
|
|
|
printf("sbp_recv: tcode = %d\n", rfp->mode.wreqb.tcode);
|
2003-04-17 03:38:03 +00:00
|
|
|
goto done0;
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
2003-10-02 04:06:56 +00:00
|
|
|
sbp_status = (struct sbp_status *)xfer->recv.payload;
|
2003-04-17 03:38:03 +00:00
|
|
|
addr = rfp->mode.wreqb.dest_lo;
|
2002-09-13 12:31:56 +00:00
|
|
|
SBP_DEBUG(2)
|
|
|
|
printf("received address 0x%x\n", addr);
|
|
|
|
END_DEBUG
|
2003-02-01 12:06:57 +00:00
|
|
|
t = SBP_ADDR2TRG(addr);
|
|
|
|
if (t >= SBP_NUM_TARGETS) {
|
|
|
|
device_printf(sbp->fd.dev,
|
|
|
|
"sbp_recv1: invalid target %d\n", t);
|
2003-04-17 03:38:03 +00:00
|
|
|
goto done0;
|
2003-02-01 12:06:57 +00:00
|
|
|
}
|
|
|
|
target = &sbp->targets[t];
|
|
|
|
l = SBP_ADDR2LUN(addr);
|
2003-10-18 04:59:47 +00:00
|
|
|
if (l >= target->num_lun || target->luns[l] == NULL) {
|
2003-02-01 12:06:57 +00:00
|
|
|
device_printf(sbp->fd.dev,
|
|
|
|
"sbp_recv1: invalid lun %d (target=%d)\n", l, t);
|
2003-04-17 03:38:03 +00:00
|
|
|
goto done0;
|
2003-02-01 12:06:57 +00:00
|
|
|
}
|
2003-10-18 04:59:47 +00:00
|
|
|
sdev = target->luns[l];
|
2003-02-01 12:06:57 +00:00
|
|
|
|
|
|
|
ocb = NULL;
|
|
|
|
switch (sbp_status->src) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
2003-02-27 12:51:24 +00:00
|
|
|
/* check mgm_ocb_cur first */
|
|
|
|
ocb = target->mgm_ocb_cur;
|
|
|
|
if (ocb != NULL) {
|
|
|
|
if (OCB_MATCH(ocb, sbp_status)) {
|
|
|
|
callout_stop(&target->mgm_ocb_timeout);
|
|
|
|
target->mgm_ocb_cur = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ocb = sbp_dequeue_ocb(sdev, sbp_status);
|
2003-02-01 12:06:57 +00:00
|
|
|
if (ocb == NULL) {
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__DragonFly__) || __FreeBSD_version < 500000
|
2009-02-18 18:41:34 +00:00
|
|
|
"%s:%s No ocb(%lx) on the queue\n",
|
2004-03-26 23:17:10 +00:00
|
|
|
#else
|
2009-02-18 18:41:34 +00:00
|
|
|
"%s:%s No ocb(%x) on the queue\n",
|
2003-03-04 06:47:17 +00:00
|
|
|
#endif
|
2009-02-18 18:41:34 +00:00
|
|
|
__func__,sdev->bustgtlun,
|
|
|
|
ntohl(sbp_status->orb_lo));
|
2003-02-01 12:06:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
/* unsolicit */
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s unsolicit status received\n",
|
|
|
|
__func__, sdev->bustgtlun);
|
2003-02-01 12:06:57 +00:00
|
|
|
break;
|
|
|
|
default:
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s unknown sbp_status->src\n",
|
|
|
|
__func__, sdev->bustgtlun);
|
2003-02-01 12:06:57 +00:00
|
|
|
}
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2003-02-27 12:51:24 +00:00
|
|
|
status_valid0 = (sbp_status->src < 2
|
2003-02-01 12:06:57 +00:00
|
|
|
&& sbp_status->resp == ORB_RES_CMPL
|
2003-02-27 12:51:24 +00:00
|
|
|
&& sbp_status->dead == 0);
|
|
|
|
status_valid = (status_valid0 && sbp_status->status == 0);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2003-10-18 04:59:47 +00:00
|
|
|
if (!status_valid0 || debug > 2){
|
2002-09-13 12:31:56 +00:00
|
|
|
int status;
|
2003-01-31 03:09:13 +00:00
|
|
|
SBP_DEBUG(0)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s ORB status src:%x resp:%x dead:%x"
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__DragonFly__) || __FreeBSD_version < 500000
|
2003-01-05 14:58:45 +00:00
|
|
|
" len:%x stat:%x orb:%x%08lx\n",
|
2004-03-26 23:17:10 +00:00
|
|
|
#else
|
|
|
|
" len:%x stat:%x orb:%x%08x\n",
|
2003-01-05 14:58:45 +00:00
|
|
|
#endif
|
2009-02-18 18:41:34 +00:00
|
|
|
__func__, sdev->bustgtlun,
|
2002-09-13 12:31:56 +00:00
|
|
|
sbp_status->src, sbp_status->resp, sbp_status->dead,
|
|
|
|
sbp_status->len, sbp_status->status,
|
2002-12-26 06:41:37 +00:00
|
|
|
ntohs(sbp_status->orb_hi), ntohl(sbp_status->orb_lo));
|
2003-01-31 03:09:13 +00:00
|
|
|
END_DEBUG
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s\n", sdev->bustgtlun);
|
2002-09-13 12:31:56 +00:00
|
|
|
status = sbp_status->status;
|
|
|
|
switch(sbp_status->resp) {
|
|
|
|
case 0:
|
|
|
|
if (status > MAX_ORB_STATUS0)
|
|
|
|
printf("%s\n", orb_status0[MAX_ORB_STATUS0]);
|
2003-01-31 03:09:13 +00:00
|
|
|
else
|
2003-02-01 12:06:57 +00:00
|
|
|
printf("%s\n", orb_status0[status]);
|
2002-09-13 12:31:56 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
2003-02-04 17:08:45 +00:00
|
|
|
printf("Obj: %s, Error: %s\n",
|
2002-09-13 12:31:56 +00:00
|
|
|
orb_status1_object[(status>>6) & 3],
|
|
|
|
orb_status1_serial_bus_error[status & 0xf]);
|
|
|
|
break;
|
2003-01-31 03:09:13 +00:00
|
|
|
case 2:
|
|
|
|
printf("Illegal request\n");
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
printf("Vendor dependent\n");
|
|
|
|
break;
|
2002-09-13 12:31:56 +00:00
|
|
|
default:
|
2003-01-31 03:09:13 +00:00
|
|
|
printf("unknown respose code %d\n", sbp_status->resp);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we have to reset the fetch agent if it's dead */
|
|
|
|
if (sbp_status->dead) {
|
2003-02-27 12:51:24 +00:00
|
|
|
if (sdev->path) {
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
xpt_freeze_devq(sdev->path, 1);
|
2003-02-27 12:51:24 +00:00
|
|
|
sdev->freeze ++;
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sbp);
|
2003-02-27 12:51:24 +00:00
|
|
|
}
|
2003-03-01 16:50:40 +00:00
|
|
|
reset_agent = 1;
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
2003-03-01 16:50:40 +00:00
|
|
|
if (ocb == NULL)
|
|
|
|
goto done;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
switch(ntohl(ocb->orb[4]) & ORB_FMT_MSK){
|
|
|
|
case ORB_FMT_NOP:
|
|
|
|
break;
|
|
|
|
case ORB_FMT_VED:
|
|
|
|
break;
|
|
|
|
case ORB_FMT_STD:
|
2003-03-03 15:27:29 +00:00
|
|
|
switch(ocb->flags) {
|
2002-09-13 12:31:56 +00:00
|
|
|
case OCB_ACT_MGM:
|
|
|
|
orb_fun = ntohl(ocb->orb[4]) & ORB_FUN_MSK;
|
2003-10-06 03:44:37 +00:00
|
|
|
reset_agent = 0;
|
2002-09-13 12:31:56 +00:00
|
|
|
switch(orb_fun) {
|
|
|
|
case ORB_FUN_LGI:
|
2003-04-17 03:38:03 +00:00
|
|
|
fwdma_sync(&sdev->dma, BUS_DMASYNC_POSTREAD);
|
|
|
|
login_res = sdev->login;
|
2002-09-13 12:31:56 +00:00
|
|
|
login_res->len = ntohs(login_res->len);
|
|
|
|
login_res->id = ntohs(login_res->id);
|
|
|
|
login_res->cmd_hi = ntohs(login_res->cmd_hi);
|
|
|
|
login_res->cmd_lo = ntohl(login_res->cmd_lo);
|
|
|
|
if (status_valid) {
|
|
|
|
SBP_DEBUG(0)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s login: len %d, ID %d, cmd %08x%08x, recon_hold %d\n",
|
|
|
|
__func__, sdev->bustgtlun,
|
|
|
|
login_res->len, login_res->id,
|
|
|
|
login_res->cmd_hi, login_res->cmd_lo,
|
|
|
|
ntohs(login_res->recon_hold));
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
|
|
|
sbp_busy_timeout(sdev);
|
|
|
|
} else {
|
2003-02-04 17:08:45 +00:00
|
|
|
/* forgot logout? */
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s login failed\n",
|
|
|
|
__func__, sdev->bustgtlun);
|
2002-09-13 12:31:56 +00:00
|
|
|
sdev->status = SBP_DEV_RESET;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ORB_FUN_RCN:
|
2003-04-17 03:38:03 +00:00
|
|
|
login_res = sdev->login;
|
2002-09-13 12:31:56 +00:00
|
|
|
if (status_valid) {
|
|
|
|
SBP_DEBUG(0)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s reconnect: len %d, ID %d, cmd %08x%08x\n",
|
|
|
|
__func__, sdev->bustgtlun,
|
|
|
|
login_res->len, login_res->id,
|
|
|
|
login_res->cmd_hi, login_res->cmd_lo);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2003-02-27 12:51:24 +00:00
|
|
|
if (sdev->status == SBP_DEV_ATTACHED)
|
|
|
|
sbp_scan_dev(sdev);
|
|
|
|
else
|
|
|
|
sbp_agent_reset(sdev);
|
2002-09-13 12:31:56 +00:00
|
|
|
} else {
|
|
|
|
/* reconnection hold time exceed? */
|
2003-02-04 17:08:45 +00:00
|
|
|
SBP_DEBUG(0)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s reconnect failed\n",
|
|
|
|
__func__, sdev->bustgtlun);
|
2003-02-04 17:08:45 +00:00
|
|
|
END_DEBUG
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_login(sdev);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ORB_FUN_LGO:
|
|
|
|
sdev->status = SBP_DEV_RESET;
|
|
|
|
break;
|
|
|
|
case ORB_FUN_RST:
|
2003-02-04 17:08:45 +00:00
|
|
|
sbp_busy_timeout(sdev);
|
|
|
|
break;
|
|
|
|
case ORB_FUN_LUR:
|
2002-09-13 12:31:56 +00:00
|
|
|
case ORB_FUN_ATA:
|
|
|
|
case ORB_FUN_ATS:
|
2003-02-04 17:08:45 +00:00
|
|
|
sbp_agent_reset(sdev);
|
2002-09-13 12:31:56 +00:00
|
|
|
break;
|
|
|
|
default:
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s unknown function %d\n",
|
|
|
|
__func__, sdev->bustgtlun, orb_fun);
|
2002-09-13 12:31:56 +00:00
|
|
|
break;
|
|
|
|
}
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_mgm_orb(sdev, ORB_FUN_RUNQUEUE, NULL);
|
2002-09-13 12:31:56 +00:00
|
|
|
break;
|
|
|
|
case OCB_ACT_CMD:
|
2003-05-05 14:50:24 +00:00
|
|
|
sdev->timeout = 0;
|
2002-09-13 12:31:56 +00:00
|
|
|
if(ocb->ccb != NULL){
|
|
|
|
union ccb *ccb;
|
2009-02-18 18:41:34 +00:00
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
ccb = ocb->ccb;
|
|
|
|
if(sbp_status->len > 1){
|
|
|
|
sbp_scsi_status(sbp_status, ocb);
|
|
|
|
}else{
|
|
|
|
if(sbp_status->resp != ORB_RES_CMPL){
|
|
|
|
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
|
|
|
|
}else{
|
|
|
|
ccb->ccb_h.status = CAM_REQ_CMP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* fix up inq data */
|
|
|
|
if (ccb->csio.cdb_io.cdb_bytes[0] == INQUIRY)
|
|
|
|
sbp_fix_inq_data(ocb);
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
xpt_done(ccb);
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-03-26 23:17:10 +00:00
|
|
|
if (!use_doorbell)
|
|
|
|
sbp_free_ocb(sdev, ocb);
|
2003-03-01 16:50:40 +00:00
|
|
|
done:
|
|
|
|
if (reset_agent)
|
|
|
|
sbp_agent_reset(sdev);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2003-04-17 03:38:03 +00:00
|
|
|
done0:
|
2003-10-02 04:06:56 +00:00
|
|
|
xfer->recv.pay_len = SBP_RECV_LEN;
|
2002-09-13 12:31:56 +00:00
|
|
|
/* The received packet is usually small enough to be stored within
|
|
|
|
* the buffer. In that case, the controller return ack_complete and
|
|
|
|
* no respose is necessary.
|
|
|
|
*
|
|
|
|
* XXX fwohci.c and firewire.c should inform event_code such as
|
|
|
|
* ack_complete or ack_pending to upper driver.
|
|
|
|
*/
|
|
|
|
#if NEED_RESPONSE
|
|
|
|
xfer->send.off = 0;
|
|
|
|
sfp = (struct fw_pkt *)xfer->send.buf;
|
|
|
|
sfp->mode.wres.dst = rfp->mode.wreqb.src;
|
2003-04-17 03:38:03 +00:00
|
|
|
xfer->dst = sfp->mode.wres.dst;
|
2002-09-13 12:31:56 +00:00
|
|
|
xfer->spd = min(sdev->target->fwdev->speed, max_speed);
|
2007-03-16 05:39:33 +00:00
|
|
|
xfer->hand = sbp_loginres_callback;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
sfp->mode.wres.tlrt = rfp->mode.wreqb.tlrt;
|
|
|
|
sfp->mode.wres.tcode = FWTCODE_WRES;
|
|
|
|
sfp->mode.wres.rtcode = 0;
|
|
|
|
sfp->mode.wres.pri = 0;
|
|
|
|
|
|
|
|
fw_asyreq(xfer->fc, -1, xfer);
|
|
|
|
#else
|
2003-04-17 03:38:03 +00:00
|
|
|
/* recycle */
|
2007-06-16 00:59:41 +00:00
|
|
|
/* we don't need a lock here because bottom half is serialized */
|
2003-04-17 03:38:03 +00:00
|
|
|
STAILQ_INSERT_TAIL(&sbp->fwb.xferlist, xfer, link);
|
2002-09-13 12:31:56 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_recv(struct fw_xfer *xfer)
|
|
|
|
{
|
|
|
|
int s;
|
|
|
|
|
|
|
|
s = splcam();
|
|
|
|
sbp_recv1(xfer);
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* sbp_attach()
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
sbp_attach(device_t dev)
|
|
|
|
{
|
|
|
|
struct sbp_softc *sbp;
|
|
|
|
struct cam_devq *devq;
|
2007-06-06 14:31:36 +00:00
|
|
|
struct firewire_comm *fc;
|
2002-09-13 12:31:56 +00:00
|
|
|
int i, s, error;
|
|
|
|
|
2007-03-16 02:29:36 +00:00
|
|
|
if (DFLTPHYS > SBP_MAXPHYS)
|
|
|
|
device_printf(dev, "Warning, DFLTPHYS(%dKB) is larger than "
|
|
|
|
"SBP_MAXPHYS(%dKB).\n", DFLTPHYS / 1024,
|
|
|
|
SBP_MAXPHYS / 1024);
|
|
|
|
|
2007-06-07 13:20:48 +00:00
|
|
|
if (!firewire_phydma_enable)
|
|
|
|
device_printf(dev, "Warning, hw.firewire.phydma_enable must be 1 "
|
|
|
|
"for SBP over FireWire.\n");
|
2002-09-13 12:31:56 +00:00
|
|
|
SBP_DEBUG(0)
|
2003-02-21 02:09:04 +00:00
|
|
|
printf("sbp_attach (cold=%d)\n", cold);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
|
|
|
|
2003-02-21 02:09:04 +00:00
|
|
|
if (cold)
|
|
|
|
sbp_cold ++;
|
2002-09-13 12:31:56 +00:00
|
|
|
sbp = ((struct sbp_softc *)device_get_softc(dev));
|
|
|
|
bzero(sbp, sizeof(struct sbp_softc));
|
|
|
|
sbp->fd.dev = dev;
|
2007-06-06 14:31:36 +00:00
|
|
|
sbp->fd.fc = fc = device_get_ivars(dev);
|
|
|
|
mtx_init(&sbp->mtx, "sbp", NULL, MTX_DEF);
|
2004-01-08 14:58:09 +00:00
|
|
|
|
|
|
|
if (max_speed < 0)
|
2007-06-06 14:31:36 +00:00
|
|
|
max_speed = fc->speed;
|
2004-01-08 14:58:09 +00:00
|
|
|
|
2007-06-06 14:31:36 +00:00
|
|
|
error = bus_dma_tag_create(/*parent*/fc->dmat,
|
2003-04-17 03:38:03 +00:00
|
|
|
/* XXX shoud be 4 for sane backend? */
|
|
|
|
/*alignment*/1,
|
2002-09-13 12:31:56 +00:00
|
|
|
/*boundary*/0,
|
|
|
|
/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
|
|
|
|
/*highaddr*/BUS_SPACE_MAXADDR,
|
|
|
|
/*filter*/NULL, /*filterarg*/NULL,
|
|
|
|
/*maxsize*/0x100000, /*nsegments*/SBP_IND_MAX,
|
2003-04-14 14:17:49 +00:00
|
|
|
/*maxsegsz*/SBP_SEG_MAX,
|
2002-09-13 12:31:56 +00:00
|
|
|
/*flags*/BUS_DMA_ALLOCNOW,
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__FreeBSD__) && __FreeBSD_version >= 501102
|
2003-07-01 15:52:06 +00:00
|
|
|
/*lockfunc*/busdma_lock_mutex,
|
2007-06-06 14:31:36 +00:00
|
|
|
/*lockarg*/&sbp->mtx,
|
2003-07-04 14:04:41 +00:00
|
|
|
#endif
|
|
|
|
&sbp->dmat);
|
2002-09-13 12:31:56 +00:00
|
|
|
if (error != 0) {
|
|
|
|
printf("sbp_attach: Could not allocate DMA tag "
|
|
|
|
"- error %d\n", error);
|
|
|
|
return (ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
devq = cam_simq_alloc(/*maxopenings*/SBP_NUM_OCB);
|
|
|
|
if (devq == NULL)
|
|
|
|
return (ENXIO);
|
|
|
|
|
|
|
|
for( i = 0 ; i < SBP_NUM_TARGETS ; i++){
|
|
|
|
sbp->targets[i].fwdev = NULL;
|
|
|
|
sbp->targets[i].luns = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sbp->sim = cam_sim_alloc(sbp_action, sbp_poll, "sbp", sbp,
|
|
|
|
device_get_unit(dev),
|
2007-06-06 14:31:36 +00:00
|
|
|
&sbp->mtx,
|
2003-02-27 12:51:24 +00:00
|
|
|
/*untagged*/ 1,
|
2003-11-12 03:45:10 +00:00
|
|
|
/*tagged*/ SBP_QUEUE_LEN - 1,
|
2003-02-27 12:51:24 +00:00
|
|
|
devq);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
if (sbp->sim == NULL) {
|
|
|
|
cam_simq_free(devq);
|
|
|
|
return (ENXIO);
|
|
|
|
}
|
|
|
|
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sbp);
|
2007-06-17 05:55:54 +00:00
|
|
|
if (xpt_bus_register(sbp->sim, dev, /*bus*/0) != CAM_SUCCESS)
|
2003-02-27 12:51:24 +00:00
|
|
|
goto fail;
|
|
|
|
|
2013-04-14 09:55:48 +00:00
|
|
|
if (xpt_create_path(&sbp->path, NULL, cam_sim_path(sbp->sim),
|
2003-10-02 04:06:56 +00:00
|
|
|
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
|
|
|
|
xpt_bus_deregister(cam_sim_path(sbp->sim));
|
2003-02-27 12:51:24 +00:00
|
|
|
goto fail;
|
2003-10-02 04:06:56 +00:00
|
|
|
}
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
/* We reserve 16 bit space (4 bytes X 64 targets X 256 luns) */
|
2003-10-02 04:06:56 +00:00
|
|
|
sbp->fwb.start = ((u_int64_t)SBP_BIND_HI << 32) | SBP_DEV2ADDR(0, 0);
|
|
|
|
sbp->fwb.end = sbp->fwb.start + 0xffff;
|
2003-04-17 03:38:03 +00:00
|
|
|
/* pre-allocate xfer */
|
|
|
|
STAILQ_INIT(&sbp->fwb.xferlist);
|
2007-04-30 13:41:40 +00:00
|
|
|
fw_xferlist_add(&sbp->fwb.xferlist, M_SBP,
|
|
|
|
/*send*/ 0, /*recv*/ SBP_RECV_LEN, SBP_NUM_OCB/2,
|
2007-06-06 14:31:36 +00:00
|
|
|
fc, (void *)sbp, sbp_recv);
|
|
|
|
|
|
|
|
fw_bindadd(fc, &sbp->fwb);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2003-04-17 03:38:03 +00:00
|
|
|
sbp->fd.post_busreset = sbp_post_busreset;
|
2002-09-13 12:31:56 +00:00
|
|
|
sbp->fd.post_explore = sbp_post_explore;
|
2003-02-21 02:09:04 +00:00
|
|
|
|
2007-06-06 14:31:36 +00:00
|
|
|
if (fc->status != -1) {
|
2003-02-21 02:09:04 +00:00
|
|
|
s = splfw();
|
2003-11-10 03:51:23 +00:00
|
|
|
sbp_post_busreset((void *)sbp);
|
2003-02-21 02:09:04 +00:00
|
|
|
sbp_post_explore((void *)sbp);
|
|
|
|
splx(s);
|
|
|
|
}
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sbp);
|
2003-11-10 03:51:23 +00:00
|
|
|
xpt_async(AC_BUS_RESET, sbp->path, /*arg*/ NULL);
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
return (0);
|
2003-02-27 12:51:24 +00:00
|
|
|
fail:
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sbp);
|
2003-02-27 12:51:24 +00:00
|
|
|
cam_sim_free(sbp->sim, /*free_devq*/TRUE);
|
|
|
|
return (ENXIO);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
2003-01-31 14:11:22 +00:00
|
|
|
static int
|
|
|
|
sbp_logout_all(struct sbp_softc *sbp)
|
|
|
|
{
|
|
|
|
struct sbp_target *target;
|
|
|
|
struct sbp_dev *sdev;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
SBP_DEBUG(0)
|
|
|
|
printf("sbp_logout_all\n");
|
|
|
|
END_DEBUG
|
|
|
|
for (i = 0 ; i < SBP_NUM_TARGETS ; i ++) {
|
|
|
|
target = &sbp->targets[i];
|
|
|
|
if (target->luns == NULL)
|
|
|
|
continue;
|
|
|
|
for (j = 0; j < target->num_lun; j++) {
|
2003-10-18 04:59:47 +00:00
|
|
|
sdev = target->luns[j];
|
|
|
|
if (sdev == NULL)
|
|
|
|
continue;
|
2003-04-17 03:38:03 +00:00
|
|
|
callout_stop(&sdev->login_callout);
|
2003-02-04 17:08:45 +00:00
|
|
|
if (sdev->status >= SBP_DEV_TOATTACH &&
|
|
|
|
sdev->status <= SBP_DEV_ATTACHED)
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_mgm_orb(sdev, ORB_FUN_LGO, NULL);
|
2003-01-31 14:11:22 +00:00
|
|
|
}
|
|
|
|
}
|
2003-04-17 03:38:03 +00:00
|
|
|
|
2003-01-31 14:11:22 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
sbp_shutdown(device_t dev)
|
|
|
|
{
|
|
|
|
struct sbp_softc *sbp = ((struct sbp_softc *)device_get_softc(dev));
|
|
|
|
|
|
|
|
sbp_logout_all(sbp);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2003-10-18 04:59:47 +00:00
|
|
|
static void
|
|
|
|
sbp_free_sdev(struct sbp_dev *sdev)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (sdev == NULL)
|
|
|
|
return;
|
|
|
|
for (i = 0; i < SBP_QUEUE_LEN; i++)
|
|
|
|
bus_dmamap_destroy(sdev->target->sbp->dmat,
|
|
|
|
sdev->ocb[i].dmamap);
|
|
|
|
fwdma_free(sdev->target->sbp->fd.fc, &sdev->dma);
|
|
|
|
free(sdev, M_SBP);
|
2009-02-01 23:28:52 +00:00
|
|
|
sdev = NULL;
|
2003-10-18 04:59:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_free_target(struct sbp_target *target)
|
|
|
|
{
|
|
|
|
struct sbp_softc *sbp;
|
|
|
|
struct fw_xfer *xfer, *next;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (target->luns == NULL)
|
|
|
|
return;
|
|
|
|
callout_stop(&target->mgm_ocb_timeout);
|
|
|
|
sbp = target->sbp;
|
|
|
|
for (i = 0; i < target->num_lun; i++)
|
|
|
|
sbp_free_sdev(target->luns[i]);
|
|
|
|
|
|
|
|
for (xfer = STAILQ_FIRST(&target->xferlist);
|
|
|
|
xfer != NULL; xfer = next) {
|
|
|
|
next = STAILQ_NEXT(xfer, link);
|
|
|
|
fw_xfer_free_buf(xfer);
|
|
|
|
}
|
|
|
|
STAILQ_INIT(&target->xferlist);
|
|
|
|
free(target->luns, M_SBP);
|
2010-01-07 21:01:37 +00:00
|
|
|
target->num_lun = 0;
|
2003-10-18 04:59:47 +00:00
|
|
|
target->luns = NULL;
|
|
|
|
target->fwdev = NULL;
|
|
|
|
}
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
static int
|
|
|
|
sbp_detach(device_t dev)
|
|
|
|
{
|
|
|
|
struct sbp_softc *sbp = ((struct sbp_softc *)device_get_softc(dev));
|
|
|
|
struct firewire_comm *fc = sbp->fd.fc;
|
2003-10-18 04:59:47 +00:00
|
|
|
int i;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
SBP_DEBUG(0)
|
|
|
|
printf("sbp_detach\n");
|
|
|
|
END_DEBUG
|
2003-04-17 03:38:03 +00:00
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
for (i = 0; i < SBP_NUM_TARGETS; i ++)
|
2003-01-31 14:11:22 +00:00
|
|
|
sbp_cam_detach_target(&sbp->targets[i]);
|
2007-06-06 14:31:36 +00:00
|
|
|
|
|
|
|
SBP_LOCK(sbp);
|
2003-10-02 04:06:56 +00:00
|
|
|
xpt_async(AC_LOST_DEVICE, sbp->path, NULL);
|
2003-02-27 12:51:24 +00:00
|
|
|
xpt_free_path(sbp->path);
|
2002-09-13 12:31:56 +00:00
|
|
|
xpt_bus_deregister(cam_sim_path(sbp->sim));
|
2007-06-06 18:33:38 +00:00
|
|
|
cam_sim_free(sbp->sim, /*free_devq*/ TRUE);
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sbp);
|
2003-01-31 14:11:22 +00:00
|
|
|
|
|
|
|
sbp_logout_all(sbp);
|
2003-04-17 03:38:03 +00:00
|
|
|
|
2003-01-31 14:11:22 +00:00
|
|
|
/* XXX wait for logout completion */
|
2007-02-27 17:23:29 +00:00
|
|
|
pause("sbpdtc", hz/2);
|
2003-01-31 14:11:22 +00:00
|
|
|
|
2003-10-18 04:59:47 +00:00
|
|
|
for (i = 0 ; i < SBP_NUM_TARGETS ; i ++)
|
|
|
|
sbp_free_target(&sbp->targets[i]);
|
2003-04-17 03:38:03 +00:00
|
|
|
|
2003-01-31 14:11:22 +00:00
|
|
|
fw_bindremove(fc, &sbp->fwb);
|
2007-04-30 13:41:40 +00:00
|
|
|
fw_xferlist_remove(&sbp->fwb.xferlist);
|
2003-01-31 14:11:22 +00:00
|
|
|
|
2003-04-17 03:38:03 +00:00
|
|
|
bus_dma_tag_destroy(sbp->dmat);
|
2007-06-06 14:31:36 +00:00
|
|
|
mtx_destroy(&sbp->mtx);
|
2003-01-31 14:11:22 +00:00
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2003-10-18 04:59:47 +00:00
|
|
|
static void
|
|
|
|
sbp_cam_detach_sdev(struct sbp_dev *sdev)
|
|
|
|
{
|
|
|
|
if (sdev == NULL)
|
|
|
|
return;
|
|
|
|
if (sdev->status == SBP_DEV_DEAD)
|
|
|
|
return;
|
|
|
|
if (sdev->status == SBP_DEV_RESET)
|
|
|
|
return;
|
2007-06-06 14:31:36 +00:00
|
|
|
sbp_abort_all_ocbs(sdev, CAM_DEV_NOT_THERE);
|
2003-10-18 04:59:47 +00:00
|
|
|
if (sdev->path) {
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sdev->target->sbp);
|
2003-10-18 04:59:47 +00:00
|
|
|
xpt_release_devq(sdev->path,
|
|
|
|
sdev->freeze, TRUE);
|
|
|
|
sdev->freeze = 0;
|
|
|
|
xpt_async(AC_LOST_DEVICE, sdev->path, NULL);
|
|
|
|
xpt_free_path(sdev->path);
|
|
|
|
sdev->path = NULL;
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sdev->target->sbp);
|
2003-10-18 04:59:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
static void
|
2003-01-31 14:11:22 +00:00
|
|
|
sbp_cam_detach_target(struct sbp_target *target)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
2003-04-17 03:38:03 +00:00
|
|
|
int i;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
if (target->luns != NULL) {
|
2003-01-01 08:22:29 +00:00
|
|
|
SBP_DEBUG(0)
|
2002-09-13 12:31:56 +00:00
|
|
|
printf("sbp_detach_target %d\n", target->target_id);
|
2003-01-01 08:22:29 +00:00
|
|
|
END_DEBUG
|
2003-02-27 12:51:24 +00:00
|
|
|
callout_stop(&target->scan_callout);
|
2003-10-18 04:59:47 +00:00
|
|
|
for (i = 0; i < target->num_lun; i++)
|
|
|
|
sbp_cam_detach_sdev(target->luns[i]);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-05 14:50:24 +00:00
|
|
|
static void
|
|
|
|
sbp_target_reset(struct sbp_dev *sdev, int method)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct sbp_target *target = sdev->target;
|
|
|
|
struct sbp_dev *tsdev;
|
|
|
|
|
|
|
|
for (i = 0; i < target->num_lun; i++) {
|
2003-10-18 04:59:47 +00:00
|
|
|
tsdev = target->luns[i];
|
|
|
|
if (tsdev == NULL)
|
|
|
|
continue;
|
2003-05-05 14:50:24 +00:00
|
|
|
if (tsdev->status == SBP_DEV_DEAD)
|
|
|
|
continue;
|
|
|
|
if (tsdev->status == SBP_DEV_RESET)
|
|
|
|
continue;
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(target->sbp);
|
2003-05-05 14:50:24 +00:00
|
|
|
xpt_freeze_devq(tsdev->path, 1);
|
|
|
|
tsdev->freeze ++;
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(target->sbp);
|
2003-05-05 14:50:24 +00:00
|
|
|
sbp_abort_all_ocbs(tsdev, CAM_CMD_TIMEOUT);
|
|
|
|
if (method == 2)
|
|
|
|
tsdev->status = SBP_DEV_LOGIN;
|
|
|
|
}
|
|
|
|
switch(method) {
|
|
|
|
case 1:
|
|
|
|
printf("target reset\n");
|
|
|
|
sbp_mgm_orb(sdev, ORB_FUN_RST, NULL);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
printf("reset start\n");
|
|
|
|
sbp_reset_start(sdev);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_mgm_timeout(void *arg)
|
|
|
|
{
|
|
|
|
struct sbp_ocb *ocb = (struct sbp_ocb *)arg;
|
|
|
|
struct sbp_dev *sdev = ocb->sdev;
|
|
|
|
struct sbp_target *target = sdev->target;
|
|
|
|
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s request timeout(mgm orb:0x%08x)\n",
|
|
|
|
__func__, sdev->bustgtlun, (uint32_t)ocb->bus_addr);
|
2003-05-05 14:50:24 +00:00
|
|
|
target->mgm_ocb_cur = NULL;
|
|
|
|
sbp_free_ocb(sdev, ocb);
|
|
|
|
#if 0
|
|
|
|
/* XXX */
|
2003-10-18 04:59:47 +00:00
|
|
|
printf("run next request\n");
|
2003-05-05 14:50:24 +00:00
|
|
|
sbp_mgm_orb(sdev, ORB_FUN_RUNQUEUE, NULL);
|
|
|
|
#endif
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s reset start\n",
|
|
|
|
__func__, sdev->bustgtlun);
|
2003-05-05 14:50:24 +00:00
|
|
|
sbp_reset_start(sdev);
|
|
|
|
}
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
static void
|
|
|
|
sbp_timeout(void *arg)
|
|
|
|
{
|
|
|
|
struct sbp_ocb *ocb = (struct sbp_ocb *)arg;
|
|
|
|
struct sbp_dev *sdev = ocb->sdev;
|
|
|
|
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s request timeout(cmd orb:0x%08x) ... ",
|
|
|
|
__func__, sdev->bustgtlun, (uint32_t)ocb->bus_addr);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2003-05-05 14:50:24 +00:00
|
|
|
sdev->timeout ++;
|
|
|
|
switch(sdev->timeout) {
|
|
|
|
case 1:
|
2003-02-04 17:08:45 +00:00
|
|
|
printf("agent reset\n");
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sdev->target->sbp);
|
2003-05-05 14:50:24 +00:00
|
|
|
xpt_freeze_devq(sdev->path, 1);
|
|
|
|
sdev->freeze ++;
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sdev->target->sbp);
|
2003-05-05 14:50:24 +00:00
|
|
|
sbp_abort_all_ocbs(sdev, CAM_CMD_TIMEOUT);
|
2003-02-04 17:08:45 +00:00
|
|
|
sbp_agent_reset(sdev);
|
2003-05-05 14:50:24 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
case 3:
|
|
|
|
sbp_target_reset(sdev, sdev->timeout - 1);
|
|
|
|
break;
|
|
|
|
#if 0
|
|
|
|
default:
|
|
|
|
/* XXX give up */
|
|
|
|
sbp_cam_detach_target(target);
|
|
|
|
if (target->luns != NULL)
|
|
|
|
free(target->luns, M_SBP);
|
2010-01-07 21:01:37 +00:00
|
|
|
target->num_lun = 0;
|
2003-05-05 14:50:24 +00:00
|
|
|
target->luns = NULL;
|
|
|
|
target->fwdev = NULL;
|
|
|
|
#endif
|
2003-02-04 17:08:45 +00:00
|
|
|
}
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_action1(struct cam_sim *sim, union ccb *ccb)
|
|
|
|
{
|
|
|
|
|
|
|
|
struct sbp_softc *sbp = (struct sbp_softc *)sim->softc;
|
|
|
|
struct sbp_target *target = NULL;
|
|
|
|
struct sbp_dev *sdev = NULL;
|
|
|
|
|
|
|
|
/* target:lun -> sdev mapping */
|
|
|
|
if (sbp != NULL
|
|
|
|
&& ccb->ccb_h.target_id != CAM_TARGET_WILDCARD
|
|
|
|
&& ccb->ccb_h.target_id < SBP_NUM_TARGETS) {
|
|
|
|
target = &sbp->targets[ccb->ccb_h.target_id];
|
|
|
|
if (target->fwdev != NULL
|
|
|
|
&& ccb->ccb_h.target_lun != CAM_LUN_WILDCARD
|
|
|
|
&& ccb->ccb_h.target_lun < target->num_lun) {
|
2003-10-18 04:59:47 +00:00
|
|
|
sdev = target->luns[ccb->ccb_h.target_lun];
|
|
|
|
if (sdev != NULL && sdev->status != SBP_DEV_ATTACHED &&
|
2002-09-13 12:31:56 +00:00
|
|
|
sdev->status != SBP_DEV_PROBE)
|
|
|
|
sdev = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SBP_DEBUG(1)
|
|
|
|
if (sdev == NULL)
|
|
|
|
printf("invalid target %d lun %d\n",
|
|
|
|
ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
|
|
|
|
END_DEBUG
|
|
|
|
|
|
|
|
switch (ccb->ccb_h.func_code) {
|
|
|
|
case XPT_SCSI_IO:
|
|
|
|
case XPT_RESET_DEV:
|
|
|
|
case XPT_GET_TRAN_SETTINGS:
|
|
|
|
case XPT_SET_TRAN_SETTINGS:
|
|
|
|
case XPT_CALC_GEOMETRY:
|
|
|
|
if (sdev == NULL) {
|
|
|
|
SBP_DEBUG(1)
|
|
|
|
printf("%s:%d:%d:func_code 0x%04x: "
|
|
|
|
"Invalid target (target needed)\n",
|
|
|
|
device_get_nameunit(sbp->fd.dev),
|
|
|
|
ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
|
|
|
|
ccb->ccb_h.func_code);
|
|
|
|
END_DEBUG
|
|
|
|
|
2002-12-26 03:17:59 +00:00
|
|
|
ccb->ccb_h.status = CAM_DEV_NOT_THERE;
|
2002-09-13 12:31:56 +00:00
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case XPT_PATH_INQ:
|
|
|
|
case XPT_NOOP:
|
|
|
|
/* The opcodes sometimes aimed at a target (sc is valid),
|
|
|
|
* sometimes aimed at the SIM (sc is invalid and target is
|
|
|
|
* CAM_TARGET_WILDCARD)
|
|
|
|
*/
|
|
|
|
if (sbp == NULL &&
|
|
|
|
ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
|
|
|
|
SBP_DEBUG(0)
|
|
|
|
printf("%s:%d:%d func_code 0x%04x: "
|
|
|
|
"Invalid target (no wildcard)\n",
|
|
|
|
device_get_nameunit(sbp->fd.dev),
|
|
|
|
ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
|
|
|
|
ccb->ccb_h.func_code);
|
|
|
|
END_DEBUG
|
2002-12-26 03:17:59 +00:00
|
|
|
ccb->ccb_h.status = CAM_DEV_NOT_THERE;
|
2002-09-13 12:31:56 +00:00
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* XXX Hm, we should check the input parameters */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (ccb->ccb_h.func_code) {
|
|
|
|
case XPT_SCSI_IO:
|
|
|
|
{
|
|
|
|
struct ccb_scsiio *csio;
|
|
|
|
struct sbp_ocb *ocb;
|
2003-04-17 03:38:03 +00:00
|
|
|
int speed;
|
2002-11-06 15:34:52 +00:00
|
|
|
void *cdb;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
csio = &ccb->csio;
|
2007-06-06 14:31:36 +00:00
|
|
|
mtx_assert(sim->mtx, MA_OWNED);
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2003-10-18 04:59:47 +00:00
|
|
|
SBP_DEBUG(2)
|
2002-09-13 12:31:56 +00:00
|
|
|
printf("%s:%d:%d XPT_SCSI_IO: "
|
|
|
|
"cmd: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x"
|
|
|
|
", flags: 0x%02x, "
|
|
|
|
"%db cmd/%db data/%db sense\n",
|
|
|
|
device_get_nameunit(sbp->fd.dev),
|
|
|
|
ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
|
|
|
|
csio->cdb_io.cdb_bytes[0],
|
|
|
|
csio->cdb_io.cdb_bytes[1],
|
|
|
|
csio->cdb_io.cdb_bytes[2],
|
|
|
|
csio->cdb_io.cdb_bytes[3],
|
|
|
|
csio->cdb_io.cdb_bytes[4],
|
|
|
|
csio->cdb_io.cdb_bytes[5],
|
|
|
|
csio->cdb_io.cdb_bytes[6],
|
|
|
|
csio->cdb_io.cdb_bytes[7],
|
|
|
|
csio->cdb_io.cdb_bytes[8],
|
|
|
|
csio->cdb_io.cdb_bytes[9],
|
|
|
|
ccb->ccb_h.flags & CAM_DIR_MASK,
|
|
|
|
csio->cdb_len, csio->dxfer_len,
|
|
|
|
csio->sense_len);
|
|
|
|
END_DEBUG
|
|
|
|
if(sdev == NULL){
|
|
|
|
ccb->ccb_h.status = CAM_DEV_NOT_THERE;
|
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
/* if we are in probe stage, pass only probe commands */
|
|
|
|
if (sdev->status == SBP_DEV_PROBE) {
|
|
|
|
char *name;
|
|
|
|
name = xpt_path_periph(ccb->ccb_h.path)->periph_name;
|
|
|
|
printf("probe stage, periph name: %s\n", name);
|
|
|
|
if (strcmp(name, "probe") != 0) {
|
|
|
|
ccb->ccb_h.status = CAM_REQUEUE_REQ;
|
|
|
|
xpt_done(ccb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2003-11-12 03:45:10 +00:00
|
|
|
if ((ocb = sbp_get_ocb(sdev)) == NULL) {
|
2007-06-16 00:59:41 +00:00
|
|
|
ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
|
2004-03-26 23:17:10 +00:00
|
|
|
if (sdev->freeze == 0) {
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sdev->target->sbp);
|
2004-03-26 23:17:10 +00:00
|
|
|
xpt_freeze_devq(sdev->path, 1);
|
|
|
|
sdev->freeze ++;
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sdev->target->sbp);
|
2004-03-26 23:17:10 +00:00
|
|
|
}
|
2003-11-12 03:45:10 +00:00
|
|
|
xpt_done(ccb);
|
2002-09-13 12:31:56 +00:00
|
|
|
return;
|
2003-11-12 03:45:10 +00:00
|
|
|
}
|
2003-04-17 03:38:03 +00:00
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
ocb->flags = OCB_ACT_CMD;
|
|
|
|
ocb->sdev = sdev;
|
|
|
|
ocb->ccb = ccb;
|
|
|
|
ccb->ccb_h.ccb_sdev_ptr = sdev;
|
|
|
|
ocb->orb[0] = htonl(1 << 31);
|
|
|
|
ocb->orb[1] = 0;
|
|
|
|
ocb->orb[2] = htonl(((sbp->fd.fc->nodeid | FWLOCALBUS )<< 16) );
|
2003-04-17 03:38:03 +00:00
|
|
|
ocb->orb[3] = htonl(ocb->bus_addr + IND_PTR_OFFSET);
|
2002-09-13 12:31:56 +00:00
|
|
|
speed = min(target->fwdev->speed, max_speed);
|
|
|
|
ocb->orb[4] = htonl(ORB_NOTIFY | ORB_CMD_SPD(speed)
|
|
|
|
| ORB_CMD_MAXP(speed + 7));
|
|
|
|
if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN){
|
|
|
|
ocb->orb[4] |= htonl(ORB_CMD_IN);
|
|
|
|
}
|
|
|
|
|
2002-11-06 15:34:52 +00:00
|
|
|
if (csio->ccb_h.flags & CAM_CDB_POINTER)
|
|
|
|
cdb = (void *)csio->cdb_io.cdb_ptr;
|
|
|
|
else
|
|
|
|
cdb = (void *)&csio->cdb_io.cdb_bytes;
|
2003-10-02 04:06:56 +00:00
|
|
|
bcopy(cdb, (void *)&ocb->orb[5], csio->cdb_len);
|
2002-09-13 12:31:56 +00:00
|
|
|
/*
|
|
|
|
printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[0]), ntohl(ocb->orb[1]), ntohl(ocb->orb[2]), ntohl(ocb->orb[3]));
|
|
|
|
printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[4]), ntohl(ocb->orb[5]), ntohl(ocb->orb[6]), ntohl(ocb->orb[7]));
|
|
|
|
*/
|
|
|
|
if (ccb->csio.dxfer_len > 0) {
|
2013-02-21 17:50:21 +00:00
|
|
|
int error;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2013-02-12 16:57:20 +00:00
|
|
|
error = bus_dmamap_load_ccb(/*dma tag*/sbp->dmat,
|
2002-09-13 12:31:56 +00:00
|
|
|
/*dma map*/ocb->dmamap,
|
2013-02-12 16:57:20 +00:00
|
|
|
ccb,
|
2002-09-13 12:31:56 +00:00
|
|
|
sbp_execute_ocb,
|
|
|
|
ocb,
|
|
|
|
/*flags*/0);
|
2003-04-17 03:38:03 +00:00
|
|
|
if (error)
|
|
|
|
printf("sbp: bus_dmamap_load error %d\n", error);
|
2002-09-13 12:31:56 +00:00
|
|
|
} else
|
|
|
|
sbp_execute_ocb(ocb, NULL, 0, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XPT_CALC_GEOMETRY:
|
|
|
|
{
|
|
|
|
struct ccb_calc_geometry *ccg;
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__DragonFly__) || __FreeBSD_version < 501100
|
2004-05-22 16:14:17 +00:00
|
|
|
uint32_t size_mb;
|
|
|
|
uint32_t secs_per_cylinder;
|
2003-06-16 03:44:36 +00:00
|
|
|
int extended = 1;
|
|
|
|
#endif
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2003-06-14 22:17:41 +00:00
|
|
|
ccg = &ccb->ccg;
|
2002-09-13 12:31:56 +00:00
|
|
|
if (ccg->block_size == 0) {
|
|
|
|
printf("sbp_action1: block_size is 0.\n");
|
|
|
|
ccb->ccb_h.status = CAM_REQ_INVALID;
|
|
|
|
xpt_done(ccb);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SBP_DEBUG(1)
|
|
|
|
printf("%s:%d:%d:%d:XPT_CALC_GEOMETRY: "
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__DragonFly__) || __FreeBSD_version < 500000
|
2003-05-12 00:42:28 +00:00
|
|
|
"Volume size = %d\n",
|
2004-03-26 23:17:10 +00:00
|
|
|
#else
|
|
|
|
"Volume size = %jd\n",
|
2003-05-12 00:42:28 +00:00
|
|
|
#endif
|
|
|
|
device_get_nameunit(sbp->fd.dev),
|
|
|
|
cam_sim_path(sbp->sim),
|
2002-09-13 12:31:56 +00:00
|
|
|
ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
|
2003-05-12 00:42:28 +00:00
|
|
|
(uintmax_t)
|
|
|
|
#endif
|
|
|
|
ccg->volume_size);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
|
|
|
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__DragonFly__) || __FreeBSD_version < 501100
|
2003-06-16 03:44:36 +00:00
|
|
|
size_mb = ccg->volume_size
|
|
|
|
/ ((1024L * 1024L) / ccg->block_size);
|
|
|
|
|
|
|
|
if (size_mb > 1024 && extended) {
|
|
|
|
ccg->heads = 255;
|
|
|
|
ccg->secs_per_track = 63;
|
|
|
|
} else {
|
|
|
|
ccg->heads = 64;
|
|
|
|
ccg->secs_per_track = 32;
|
|
|
|
}
|
|
|
|
secs_per_cylinder = ccg->heads * ccg->secs_per_track;
|
|
|
|
ccg->cylinders = ccg->volume_size / secs_per_cylinder;
|
|
|
|
ccb->ccb_h.status = CAM_REQ_CMP;
|
|
|
|
#else
|
2003-06-14 22:17:41 +00:00
|
|
|
cam_calc_geometry(ccg, /*extended*/1);
|
2003-06-16 03:44:36 +00:00
|
|
|
#endif
|
2002-09-13 12:31:56 +00:00
|
|
|
xpt_done(ccb);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XPT_RESET_BUS: /* Reset the specified SCSI bus */
|
|
|
|
{
|
|
|
|
|
|
|
|
SBP_DEBUG(1)
|
|
|
|
printf("%s:%d:XPT_RESET_BUS: \n",
|
|
|
|
device_get_nameunit(sbp->fd.dev), cam_sim_path(sbp->sim));
|
|
|
|
END_DEBUG
|
|
|
|
|
|
|
|
ccb->ccb_h.status = CAM_REQ_INVALID;
|
|
|
|
xpt_done(ccb);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XPT_PATH_INQ: /* Path routing inquiry */
|
|
|
|
{
|
|
|
|
struct ccb_pathinq *cpi = &ccb->cpi;
|
|
|
|
|
|
|
|
SBP_DEBUG(1)
|
|
|
|
printf("%s:%d:%d XPT_PATH_INQ:.\n",
|
|
|
|
device_get_nameunit(sbp->fd.dev),
|
|
|
|
ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
|
|
|
|
END_DEBUG
|
|
|
|
cpi->version_num = 1; /* XXX??? */
|
2003-02-27 12:51:24 +00:00
|
|
|
cpi->hba_inquiry = PI_TAG_ABLE;
|
2002-09-13 12:31:56 +00:00
|
|
|
cpi->target_sprt = 0;
|
2003-07-28 06:15:59 +00:00
|
|
|
cpi->hba_misc = PIM_NOBUSRESET | PIM_NO_6_BYTE;
|
2002-09-13 12:31:56 +00:00
|
|
|
cpi->hba_eng_cnt = 0;
|
|
|
|
cpi->max_target = SBP_NUM_TARGETS - 1;
|
|
|
|
cpi->max_lun = SBP_NUM_LUNS - 1;
|
|
|
|
cpi->initiator_id = SBP_INITIATOR;
|
|
|
|
cpi->bus_id = sim->bus_id;
|
|
|
|
cpi->base_transfer_speed = 400 * 1000 / 8;
|
|
|
|
strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
|
|
|
|
strncpy(cpi->hba_vid, "SBP", HBA_IDLEN);
|
|
|
|
strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
|
|
|
|
cpi->unit_number = sim->unit_number;
|
2006-10-31 05:53:29 +00:00
|
|
|
cpi->transport = XPORT_SPI; /* XX should have a FireWire */
|
|
|
|
cpi->transport_version = 2;
|
|
|
|
cpi->protocol = PROTO_SCSI;
|
|
|
|
cpi->protocol_version = SCSI_REV_2;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
cpi->ccb_h.status = CAM_REQ_CMP;
|
|
|
|
xpt_done(ccb);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XPT_GET_TRAN_SETTINGS:
|
|
|
|
{
|
|
|
|
struct ccb_trans_settings *cts = &ccb->cts;
|
2006-10-31 05:53:29 +00:00
|
|
|
struct ccb_trans_settings_scsi *scsi =
|
|
|
|
&cts->proto_specific.scsi;
|
|
|
|
struct ccb_trans_settings_spi *spi =
|
|
|
|
&cts->xport_specific.spi;
|
|
|
|
|
|
|
|
cts->protocol = PROTO_SCSI;
|
|
|
|
cts->protocol_version = SCSI_REV_2;
|
|
|
|
cts->transport = XPORT_SPI; /* should have a FireWire */
|
|
|
|
cts->transport_version = 2;
|
|
|
|
spi->valid = CTS_SPI_VALID_DISC;
|
|
|
|
spi->flags = CTS_SPI_FLAGS_DISC_ENB;
|
|
|
|
scsi->valid = CTS_SCSI_VALID_TQ;
|
|
|
|
scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
|
2002-09-13 12:31:56 +00:00
|
|
|
SBP_DEBUG(1)
|
|
|
|
printf("%s:%d:%d XPT_GET_TRAN_SETTINGS:.\n",
|
|
|
|
device_get_nameunit(sbp->fd.dev),
|
|
|
|
ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
|
|
|
|
END_DEBUG
|
|
|
|
cts->ccb_h.status = CAM_REQ_CMP;
|
|
|
|
xpt_done(ccb);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XPT_ABORT:
|
|
|
|
ccb->ccb_h.status = CAM_UA_ABORT;
|
|
|
|
xpt_done(ccb);
|
|
|
|
break;
|
2003-02-27 12:51:24 +00:00
|
|
|
case XPT_SET_TRAN_SETTINGS:
|
|
|
|
/* XXX */
|
2002-09-13 12:31:56 +00:00
|
|
|
default:
|
|
|
|
ccb->ccb_h.status = CAM_REQ_INVALID;
|
|
|
|
xpt_done(ccb);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_action(struct cam_sim *sim, union ccb *ccb)
|
|
|
|
{
|
|
|
|
int s;
|
|
|
|
|
|
|
|
s = splfw();
|
|
|
|
sbp_action1(sim, ccb);
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_execute_ocb(void *arg, bus_dma_segment_t *segments, int seg, int error)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct sbp_ocb *ocb;
|
|
|
|
struct sbp_ocb *prev;
|
2002-10-21 15:36:59 +00:00
|
|
|
bus_dma_segment_t *s;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
printf("sbp_execute_ocb: error=%d\n", error);
|
|
|
|
|
|
|
|
ocb = (struct sbp_ocb *)arg;
|
2003-04-17 03:38:03 +00:00
|
|
|
|
2003-10-18 04:59:47 +00:00
|
|
|
SBP_DEBUG(2)
|
2003-04-17 03:38:03 +00:00
|
|
|
printf("sbp_execute_ocb: seg %d", seg);
|
|
|
|
for (i = 0; i < seg; i++)
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__DragonFly__) || __FreeBSD_version < 500000
|
|
|
|
printf(", %x:%d", segments[i].ds_addr, segments[i].ds_len);
|
|
|
|
#else
|
2003-04-24 15:27:06 +00:00
|
|
|
printf(", %jx:%jd", (uintmax_t)segments[i].ds_addr,
|
|
|
|
(uintmax_t)segments[i].ds_len);
|
2003-04-17 03:38:03 +00:00
|
|
|
#endif
|
|
|
|
printf("\n");
|
|
|
|
END_DEBUG
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
if (seg == 1) {
|
|
|
|
/* direct pointer */
|
2003-04-14 14:17:49 +00:00
|
|
|
s = &segments[0];
|
|
|
|
if (s->ds_len > SBP_SEG_MAX)
|
|
|
|
panic("ds_len > SBP_SEG_MAX, fix busdma code");
|
|
|
|
ocb->orb[3] = htonl(s->ds_addr);
|
|
|
|
ocb->orb[4] |= htonl(s->ds_len);
|
2002-09-13 12:31:56 +00:00
|
|
|
} else if(seg > 1) {
|
|
|
|
/* page table */
|
|
|
|
for (i = 0; i < seg; i++) {
|
2002-10-21 15:36:59 +00:00
|
|
|
s = &segments[i];
|
2003-01-07 12:58:08 +00:00
|
|
|
SBP_DEBUG(0)
|
|
|
|
/* XXX LSI Logic "< 16 byte" bug might be hit */
|
2002-10-21 15:36:59 +00:00
|
|
|
if (s->ds_len < 16)
|
|
|
|
printf("sbp_execute_ocb: warning, "
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__DragonFly__) || __FreeBSD_version < 500000
|
2003-01-07 12:58:08 +00:00
|
|
|
"segment length(%d) is less than 16."
|
2004-03-26 23:17:10 +00:00
|
|
|
#else
|
|
|
|
"segment length(%zd) is less than 16."
|
2002-10-21 15:36:59 +00:00
|
|
|
#endif
|
2010-03-29 17:24:23 +00:00
|
|
|
"(seg=%d/%d)\n", (size_t)s->ds_len, i+1, seg);
|
2003-01-07 12:58:08 +00:00
|
|
|
END_DEBUG
|
2003-04-14 14:17:49 +00:00
|
|
|
if (s->ds_len > SBP_SEG_MAX)
|
|
|
|
panic("ds_len > SBP_SEG_MAX, fix busdma code");
|
2002-10-21 15:36:59 +00:00
|
|
|
ocb->ind_ptr[i].hi = htonl(s->ds_len << 16);
|
|
|
|
ocb->ind_ptr[i].lo = htonl(s->ds_addr);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
ocb->orb[4] |= htonl(ORB_CMD_PTBL | seg);
|
|
|
|
}
|
|
|
|
|
2003-04-17 03:38:03 +00:00
|
|
|
if (seg > 0)
|
|
|
|
bus_dmamap_sync(ocb->sdev->target->sbp->dmat, ocb->dmamap,
|
|
|
|
(ntohl(ocb->orb[4]) & ORB_CMD_IN) ?
|
|
|
|
BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
|
2002-09-13 12:31:56 +00:00
|
|
|
prev = sbp_enqueue_ocb(ocb->sdev, ocb);
|
2003-04-17 03:38:03 +00:00
|
|
|
fwdma_sync(&ocb->sdev->dma, BUS_DMASYNC_PREWRITE);
|
2004-03-26 23:17:10 +00:00
|
|
|
if (use_doorbell) {
|
|
|
|
if (prev == NULL) {
|
|
|
|
if (ocb->sdev->last_ocb != NULL)
|
|
|
|
sbp_doorbell(ocb->sdev);
|
|
|
|
else
|
|
|
|
sbp_orb_pointer(ocb->sdev, ocb);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (prev == NULL || (ocb->sdev->flags & ORB_LINK_DEAD) != 0) {
|
|
|
|
ocb->sdev->flags &= ~ORB_LINK_DEAD;
|
|
|
|
sbp_orb_pointer(ocb->sdev, ocb);
|
|
|
|
}
|
2003-10-06 03:44:37 +00:00
|
|
|
}
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_poll(struct cam_sim *sim)
|
|
|
|
{
|
2003-10-06 05:40:47 +00:00
|
|
|
struct sbp_softc *sbp;
|
|
|
|
struct firewire_comm *fc;
|
|
|
|
|
|
|
|
sbp = (struct sbp_softc *)sim->softc;
|
|
|
|
fc = sbp->fd.fc;
|
|
|
|
|
|
|
|
fc->poll(fc, 0, -1);
|
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
return;
|
|
|
|
}
|
2003-10-06 05:40:47 +00:00
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
static struct sbp_ocb *
|
2003-02-27 12:51:24 +00:00
|
|
|
sbp_dequeue_ocb(struct sbp_dev *sdev, struct sbp_status *sbp_status)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
|
|
|
struct sbp_ocb *ocb;
|
|
|
|
struct sbp_ocb *next;
|
|
|
|
int s = splfw(), order = 0;
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
SBP_DEBUG(1)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__DragonFly__) || __FreeBSD_version < 500000
|
2009-02-18 18:41:34 +00:00
|
|
|
"%s:%s 0x%08lx src %d\n",
|
2004-03-26 23:17:10 +00:00
|
|
|
#else
|
2009-02-18 18:41:34 +00:00
|
|
|
"%s:%s 0x%08x src %d\n",
|
2003-01-05 14:58:45 +00:00
|
|
|
#endif
|
2009-02-18 18:41:34 +00:00
|
|
|
__func__, sdev->bustgtlun, ntohl(sbp_status->orb_lo), sbp_status->src);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sdev->target->sbp);
|
2003-10-18 04:59:47 +00:00
|
|
|
for (ocb = STAILQ_FIRST(&sdev->ocbs); ocb != NULL; ocb = next) {
|
|
|
|
next = STAILQ_NEXT(ocb, ocb);
|
|
|
|
flags = ocb->flags;
|
2003-02-27 12:51:24 +00:00
|
|
|
if (OCB_MATCH(ocb, sbp_status)) {
|
2002-09-13 12:31:56 +00:00
|
|
|
/* found */
|
2003-03-03 15:27:29 +00:00
|
|
|
STAILQ_REMOVE(&sdev->ocbs, ocb, sbp_ocb, ocb);
|
2002-09-13 12:31:56 +00:00
|
|
|
if (ocb->ccb != NULL)
|
|
|
|
untimeout(sbp_timeout, (caddr_t)ocb,
|
2013-09-25 17:16:21 +00:00
|
|
|
ocb->timeout_ch);
|
2003-04-17 03:38:03 +00:00
|
|
|
if (ntohl(ocb->orb[4]) & 0xffff) {
|
|
|
|
bus_dmamap_sync(sdev->target->sbp->dmat,
|
|
|
|
ocb->dmamap,
|
|
|
|
(ntohl(ocb->orb[4]) & ORB_CMD_IN) ?
|
|
|
|
BUS_DMASYNC_POSTREAD :
|
|
|
|
BUS_DMASYNC_POSTWRITE);
|
|
|
|
bus_dmamap_unload(sdev->target->sbp->dmat,
|
|
|
|
ocb->dmamap);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
2004-03-26 23:17:10 +00:00
|
|
|
if (!use_doorbell) {
|
|
|
|
if (sbp_status->src == SRC_NO_NEXT) {
|
|
|
|
if (next != NULL)
|
|
|
|
sbp_orb_pointer(sdev, next);
|
|
|
|
else if (order > 0) {
|
|
|
|
/*
|
|
|
|
* Unordered execution
|
|
|
|
* We need to send pointer for
|
|
|
|
* next ORB
|
|
|
|
*/
|
|
|
|
sdev->flags |= ORB_LINK_DEAD;
|
|
|
|
}
|
2003-10-06 03:44:37 +00:00
|
|
|
}
|
2004-03-26 23:17:10 +00:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* XXX this is not correct for unordered
|
|
|
|
* execution.
|
|
|
|
*/
|
2007-06-16 00:59:41 +00:00
|
|
|
if (sdev->last_ocb != NULL) {
|
|
|
|
SBP_UNLOCK(sdev->target->sbp);
|
2004-03-26 23:17:10 +00:00
|
|
|
sbp_free_ocb(sdev, sdev->last_ocb);
|
2007-06-16 00:59:41 +00:00
|
|
|
SBP_LOCK(sdev->target->sbp);
|
|
|
|
}
|
2004-03-26 23:17:10 +00:00
|
|
|
sdev->last_ocb = ocb;
|
|
|
|
if (next != NULL &&
|
|
|
|
sbp_status->src == SRC_NO_NEXT)
|
|
|
|
sbp_doorbell(sdev);
|
2003-10-06 03:44:37 +00:00
|
|
|
}
|
2002-09-13 12:31:56 +00:00
|
|
|
break;
|
2003-03-03 15:27:29 +00:00
|
|
|
} else
|
|
|
|
order ++;
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sdev->target->sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
splx(s);
|
|
|
|
SBP_DEBUG(0)
|
|
|
|
if (ocb && order > 0) {
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
|
|
|
"%s:%s unordered execution order:%d\n",
|
|
|
|
__func__, sdev->bustgtlun, order);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
END_DEBUG
|
|
|
|
return (ocb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sbp_ocb *
|
|
|
|
sbp_enqueue_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb)
|
|
|
|
{
|
|
|
|
int s = splfw();
|
2004-03-26 23:17:10 +00:00
|
|
|
struct sbp_ocb *prev, *prev2;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
2007-06-16 00:59:41 +00:00
|
|
|
mtx_assert(&sdev->target->sbp->mtx, MA_OWNED);
|
2003-10-18 04:59:47 +00:00
|
|
|
SBP_DEBUG(1)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__DragonFly__) || __FreeBSD_version < 500000
|
2009-02-18 18:41:34 +00:00
|
|
|
"%s:%s 0x%08x\n", __func__, sdev->bustgtlun, ocb->bus_addr);
|
2003-01-05 14:58:45 +00:00
|
|
|
#else
|
2009-02-18 18:41:34 +00:00
|
|
|
"%s:%s 0x%08jx\n", __func__, sdev->bustgtlun, (uintmax_t)ocb->bus_addr);
|
2003-01-05 14:58:45 +00:00
|
|
|
#endif
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2004-03-26 23:17:10 +00:00
|
|
|
prev2 = prev = STAILQ_LAST(&sdev->ocbs, sbp_ocb, ocb);
|
2002-09-13 12:31:56 +00:00
|
|
|
STAILQ_INSERT_TAIL(&sdev->ocbs, ocb, ocb);
|
|
|
|
|
|
|
|
if (ocb->ccb != NULL)
|
2013-09-25 17:16:21 +00:00
|
|
|
ocb->timeout_ch = timeout(sbp_timeout, (caddr_t)ocb,
|
2002-09-13 12:31:56 +00:00
|
|
|
(ocb->ccb->ccb_h.timeout * hz) / 1000);
|
|
|
|
|
2004-03-26 23:17:10 +00:00
|
|
|
if (use_doorbell && prev == NULL)
|
|
|
|
prev2 = sdev->last_ocb;
|
|
|
|
|
2007-06-16 00:59:41 +00:00
|
|
|
if (prev2 != NULL && (ocb->sdev->flags & ORB_LINK_DEAD) == 0) {
|
|
|
|
SBP_DEBUG(1)
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__DragonFly__) || __FreeBSD_version < 500000
|
2003-10-06 03:44:37 +00:00
|
|
|
printf("linking chain 0x%x -> 0x%x\n",
|
2004-03-26 23:17:10 +00:00
|
|
|
prev2->bus_addr, ocb->bus_addr);
|
|
|
|
#else
|
|
|
|
printf("linking chain 0x%jx -> 0x%jx\n",
|
|
|
|
(uintmax_t)prev2->bus_addr, (uintmax_t)ocb->bus_addr);
|
2003-01-05 14:58:45 +00:00
|
|
|
#endif
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2007-06-14 12:52:13 +00:00
|
|
|
/*
|
|
|
|
* Suppress compiler optimization so that orb[1] must be written first.
|
|
|
|
* XXX We may need an explicit memory barrier for other architectures
|
|
|
|
* other than i386/amd64.
|
|
|
|
*/
|
|
|
|
*(volatile uint32_t *)&prev2->orb[1] = htonl(ocb->bus_addr);
|
|
|
|
*(volatile uint32_t *)&prev2->orb[0] = 0;
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
return prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sbp_ocb *
|
2003-04-17 03:38:03 +00:00
|
|
|
sbp_get_ocb(struct sbp_dev *sdev)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
|
|
|
struct sbp_ocb *ocb;
|
|
|
|
int s = splfw();
|
2007-06-06 14:31:36 +00:00
|
|
|
|
|
|
|
mtx_assert(&sdev->target->sbp->mtx, MA_OWNED);
|
2003-04-17 03:38:03 +00:00
|
|
|
ocb = STAILQ_FIRST(&sdev->free_ocbs);
|
2002-09-13 12:31:56 +00:00
|
|
|
if (ocb == NULL) {
|
2004-03-26 23:17:10 +00:00
|
|
|
sdev->flags |= ORB_SHORTAGE;
|
2002-09-13 12:31:56 +00:00
|
|
|
printf("ocb shortage!!!\n");
|
2004-09-06 20:42:34 +00:00
|
|
|
splx(s);
|
2002-09-13 12:31:56 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2003-04-17 03:38:03 +00:00
|
|
|
STAILQ_REMOVE_HEAD(&sdev->free_ocbs, ocb);
|
2002-09-13 12:31:56 +00:00
|
|
|
splx(s);
|
|
|
|
ocb->ccb = NULL;
|
|
|
|
return (ocb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2003-04-17 03:38:03 +00:00
|
|
|
sbp_free_ocb(struct sbp_dev *sdev, struct sbp_ocb *ocb)
|
2002-09-13 12:31:56 +00:00
|
|
|
{
|
|
|
|
ocb->flags = 0;
|
|
|
|
ocb->ccb = NULL;
|
2007-06-06 14:31:36 +00:00
|
|
|
|
|
|
|
SBP_LOCK(sdev->target->sbp);
|
2003-04-17 03:38:03 +00:00
|
|
|
STAILQ_INSERT_TAIL(&sdev->free_ocbs, ocb, ocb);
|
2004-03-26 23:17:10 +00:00
|
|
|
if ((sdev->flags & ORB_SHORTAGE) != 0) {
|
|
|
|
int count;
|
|
|
|
|
|
|
|
sdev->flags &= ~ORB_SHORTAGE;
|
|
|
|
count = sdev->freeze;
|
|
|
|
sdev->freeze = 0;
|
|
|
|
xpt_release_devq(sdev->path, count, TRUE);
|
|
|
|
}
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sdev->target->sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_abort_ocb(struct sbp_ocb *ocb, int status)
|
|
|
|
{
|
|
|
|
struct sbp_dev *sdev;
|
|
|
|
|
|
|
|
sdev = ocb->sdev;
|
2003-04-17 03:38:03 +00:00
|
|
|
SBP_DEBUG(0)
|
2009-02-18 18:41:34 +00:00
|
|
|
device_printf(sdev->target->sbp->fd.dev,
|
2004-03-26 23:17:10 +00:00
|
|
|
#if defined(__DragonFly__) || __FreeBSD_version < 500000
|
2009-02-18 18:41:34 +00:00
|
|
|
"%s:%s 0x%x\n", __func__, sdev->bustgtlun, ocb->bus_addr);
|
2004-03-26 23:17:10 +00:00
|
|
|
#else
|
2009-02-18 18:41:34 +00:00
|
|
|
"%s:%s 0x%jx\n", __func__, sdev->bustgtlun, (uintmax_t)ocb->bus_addr);
|
2003-03-03 15:27:29 +00:00
|
|
|
#endif
|
2003-04-17 03:38:03 +00:00
|
|
|
END_DEBUG
|
|
|
|
SBP_DEBUG(1)
|
2002-10-23 13:04:02 +00:00
|
|
|
if (ocb->ccb != NULL)
|
|
|
|
sbp_print_scsi_cmd(ocb);
|
2002-09-13 12:31:56 +00:00
|
|
|
END_DEBUG
|
2003-04-17 03:38:03 +00:00
|
|
|
if (ntohl(ocb->orb[4]) & 0xffff) {
|
|
|
|
bus_dmamap_sync(sdev->target->sbp->dmat, ocb->dmamap,
|
|
|
|
(ntohl(ocb->orb[4]) & ORB_CMD_IN) ?
|
|
|
|
BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
|
|
|
|
bus_dmamap_unload(sdev->target->sbp->dmat, ocb->dmamap);
|
|
|
|
}
|
2003-03-03 15:27:29 +00:00
|
|
|
if (ocb->ccb != NULL) {
|
2003-02-04 17:08:45 +00:00
|
|
|
untimeout(sbp_timeout, (caddr_t)ocb,
|
2013-09-25 17:16:21 +00:00
|
|
|
ocb->timeout_ch);
|
2002-09-13 12:31:56 +00:00
|
|
|
ocb->ccb->ccb_h.status = status;
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_LOCK(sdev->target->sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
xpt_done(ocb->ccb);
|
2007-06-06 14:31:36 +00:00
|
|
|
SBP_UNLOCK(sdev->target->sbp);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
2003-04-17 03:38:03 +00:00
|
|
|
sbp_free_ocb(sdev, ocb);
|
2002-09-13 12:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sbp_abort_all_ocbs(struct sbp_dev *sdev, int status)
|
|
|
|
{
|
|
|
|
int s;
|
2002-10-23 13:04:02 +00:00
|
|
|
struct sbp_ocb *ocb, *next;
|
|
|
|
STAILQ_HEAD(, sbp_ocb) temp;
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
s = splfw();
|
2002-10-23 13:04:02 +00:00
|
|
|
|
2007-06-16 00:59:41 +00:00
|
|
|
STAILQ_INIT(&temp);
|
|
|
|
SBP_LOCK(sdev->target->sbp);
|
|
|
|
STAILQ_CONCAT(&temp, &sdev->ocbs);
|
2002-10-23 13:04:02 +00:00
|
|
|
STAILQ_INIT(&sdev->ocbs);
|
2007-06-16 00:59:41 +00:00
|
|
|
SBP_UNLOCK(sdev->target->sbp);
|
|
|
|
|
2002-10-23 13:04:02 +00:00
|
|
|
for (ocb = STAILQ_FIRST(&temp); ocb != NULL; ocb = next) {
|
|
|
|
next = STAILQ_NEXT(ocb, ocb);
|
2002-09-13 12:31:56 +00:00
|
|
|
sbp_abort_ocb(ocb, status);
|
|
|
|
}
|
2004-03-26 23:17:10 +00:00
|
|
|
if (sdev->last_ocb != NULL) {
|
|
|
|
sbp_free_ocb(sdev, sdev->last_ocb);
|
|
|
|
sdev->last_ocb = NULL;
|
|
|
|
}
|
2002-10-23 13:04:02 +00:00
|
|
|
|
2002-09-13 12:31:56 +00:00
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static devclass_t sbp_devclass;
|
|
|
|
|
|
|
|
static device_method_t sbp_methods[] = {
|
|
|
|
/* device interface */
|
|
|
|
DEVMETHOD(device_identify, sbp_identify),
|
|
|
|
DEVMETHOD(device_probe, sbp_probe),
|
|
|
|
DEVMETHOD(device_attach, sbp_attach),
|
|
|
|
DEVMETHOD(device_detach, sbp_detach),
|
2003-01-31 14:11:22 +00:00
|
|
|
DEVMETHOD(device_shutdown, sbp_shutdown),
|
2002-09-13 12:31:56 +00:00
|
|
|
|
|
|
|
{ 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static driver_t sbp_driver = {
|
|
|
|
"sbp",
|
|
|
|
sbp_methods,
|
|
|
|
sizeof(struct sbp_softc),
|
|
|
|
};
|
2004-03-26 23:17:10 +00:00
|
|
|
#ifdef __DragonFly__
|
|
|
|
DECLARE_DUMMY_MODULE(sbp);
|
|
|
|
#endif
|
2002-09-13 12:31:56 +00:00
|
|
|
DRIVER_MODULE(sbp, firewire, sbp_driver, sbp_devclass, 0, 0);
|
|
|
|
MODULE_VERSION(sbp, 1);
|
|
|
|
MODULE_DEPEND(sbp, firewire, 1, 1, 1);
|
|
|
|
MODULE_DEPEND(sbp, cam, 1, 1, 1);
|