summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorsimokawa <simokawa@FreeBSD.org>2003-02-27 12:51:24 +0000
committersimokawa <simokawa@FreeBSD.org>2003-02-27 12:51:24 +0000
commit15b70bcd2e4f67772c1a7611a7f17d291acbff3f (patch)
tree9dc6d0572414885de0d9b6a17ee7854130b3e2e9 /sys/dev
parent6eb790939b8d733c0cad2a9b724d11fb1c5c344e (diff)
downloadFreeBSD-src-15b70bcd2e4f67772c1a7611a7f17d291acbff3f.zip
FreeBSD-src-15b70bcd2e4f67772c1a7611a7f17d291acbff3f.tar.gz
MFp4(simokawa_sbp branch)
Improve SBP device probeing: - Wait 2 sec before issuing LOGIN ORB expecting the reconnection hold timer expires. - Serialize management ORB and scanning LUN by CAM on each target. This should fix the problem for devices which have multiple LUNs. Test device is donated by: Jaye Mathisen <mrcpu@internetcds.com> - Freeze SIM queue for 2 sec after BUS RESET. - Retry with LOGIN rather than RECONNECT after LOGIN is not completed for BUS RESET. - Use appropriate CAM status for BUS RESET and DEVICE RESET. - Let CAM to scan targets after BUS REST. - Implement CAM scan target function. - Keep our own devq freeze count. - Let CAM to know that SBP does tagged queuing. These should be merged to RELENG_4 before 4.8-RELEASE.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/firewire/firewire.c12
-rw-r--r--sys/dev/firewire/firewirereg.h6
-rw-r--r--sys/dev/firewire/fwdev.c8
-rw-r--r--sys/dev/firewire/fwmem.c4
-rw-r--r--sys/dev/firewire/sbp.c388
5 files changed, 310 insertions, 108 deletions
diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c
index b25ede6..afd65e5 100644
--- a/sys/dev/firewire/firewire.c
+++ b/sys/dev/firewire/firewire.c
@@ -423,11 +423,6 @@ firewire_attach( device_t dev )
#else
sc->dev[i] = d;
#endif
-#if __FreeBSD_version >= 500000
-#define CALLOUT_INIT(x) callout_init(x, 0 /* mpsafe */)
-#else
-#define CALLOUT_INIT(x) callout_init(x)
-#endif
CALLOUT_INIT(&sc->fc->timeout_callout);
CALLOUT_INIT(&sc->fc->bmr_callout);
CALLOUT_INIT(&sc->fc->retry_probe_callout);
@@ -1787,13 +1782,14 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u
ntohl(fp->mode.rreqq.dest_lo));
if(bind == NULL){
#if __FreeBSD_version >= 500000
- printf("Unknown service addr 0x%08x:0x%08x tcode=%x\n",
+ printf("Unknown service addr 0x%08x:0x%08x tcode=%x\n src=0x%x",
#else
- printf("Unknown service addr 0x%08x:0x%08lx tcode=%x\n",
+ printf("Unknown service addr 0x%08x:0x%08lx tcode=%x src=0x%x\n",
#endif
ntohs(fp->mode.rreqq.dest_hi),
ntohl(fp->mode.rreqq.dest_lo),
- fp->mode.common.tcode);
+ fp->mode.common.tcode,
+ fp->mode.hdr.src);
if (fc->status == FWBUSRESET) {
printf("fw_rcv: cannot respond(bus reset)!\n");
goto err;
diff --git a/sys/dev/firewire/firewirereg.h b/sys/dev/firewire/firewirereg.h
index 0998575..9cbcadf 100644
--- a/sys/dev/firewire/firewirereg.h
+++ b/sys/dev/firewire/firewirereg.h
@@ -368,5 +368,11 @@ extern devclass_t firewire_devclass;
#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va))
#endif /* __alpha__ */
+#if __FreeBSD_version >= 500000
+#define CALLOUT_INIT(x) callout_init(x, 0 /* mpsafe */)
+#else
+#define CALLOUT_INIT(x) callout_init(x)
+#endif
+
MALLOC_DECLARE(M_FW);
MALLOC_DECLARE(M_FWXFER);
diff --git a/sys/dev/firewire/fwdev.c b/sys/dev/firewire/fwdev.c
index a85db14..a25af15 100644
--- a/sys/dev/firewire/fwdev.c
+++ b/sys/dev/firewire/fwdev.c
@@ -921,13 +921,21 @@ fw_poll(dev_t dev, int events, fw_proc *td)
}
static int
+#if __FreeBSD_version < 500000
+fw_mmap (dev_t dev, vm_offset_t offset, int nproto)
+#else
fw_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto)
+#endif
{
struct firewire_softc *fc;
int unit = DEV2UNIT(dev);
if (DEV_FWMEM(dev))
+#if __FreeBSD_version < 500000
+ return fwmem_mmap(dev, offset, nproto);
+#else
return fwmem_mmap(dev, offset, paddr, nproto);
+#endif
fc = devclass_get_softc(firewire_devclass, unit);
diff --git a/sys/dev/firewire/fwmem.c b/sys/dev/firewire/fwmem.c
index 9c64fdc..182ea6a 100644
--- a/sys/dev/firewire/fwmem.c
+++ b/sys/dev/firewire/fwmem.c
@@ -419,7 +419,11 @@ fwmem_poll (dev_t dev, int events, fw_proc *td)
return EINVAL;
}
int
+#if __FreeBSD_version < 500000
+fwmem_mmap (dev_t dev, vm_offset_t offset, int nproto)
+#else
fwmem_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto)
+#endif
{
return EINVAL;
}
diff --git a/sys/dev/firewire/sbp.c b/sys/dev/firewire/sbp.c
index b4c157b..bc0bd39 100644
--- a/sys/dev/firewire/sbp.c
+++ b/sys/dev/firewire/sbp.c
@@ -68,20 +68,32 @@
#define ccb_sdev_ptr spriv_ptr0
#define ccb_sbp_ptr spriv_ptr1
-#define SBP_NUM_TARGETS 8
+#define SBP_NUM_TARGETS 8 /* MAX 64 */
#define SBP_NUM_LUNS 8 /* limited by CAM_SCSI2_MAXLUN in cam_xpt.c */
#define SBP_QUEUE_LEN 4
#define SBP_NUM_OCB (SBP_QUEUE_LEN * SBP_NUM_TARGETS)
#define SBP_INITIATOR 7
-#define SBP_ESELECT_TIMEOUT 1
+
+#define LOGIN_DELAY 2
+
+/*
+ * STATUS FIFO addressing
+ * bit
+ * -----------------------
+ * 0- 1( 2): 0 (alingment)
+ * 2- 7( 6): target
+ * 8-15( 8): lun
+ * 16-23( 8): unit
+ * 24-31( 8): reserved
+ * 32-47(16): SBP_BIND_HI
+ * 48-64(16): bus_id, node_id
+ */
#define SBP_BIND_HI 0x1
-#define SBP_DEV2ADDR(u, t, l) \
+#define SBP_DEV2ADDR(u, t, l) \
((((u) & 0xff) << 16) | (((l) & 0xff) << 8) | (((t) & 0x3f) << 2))
#define SBP_ADDR2TRG(a) (((a) >> 2) & 0x3f)
#define SBP_ADDR2LUN(a) (((a) >> 8) & 0xff)
-#define MAX_FREEZE 10
-
#define ORB_NOTIFY (1 << 31)
#define ORB_FMT_STD (0 << 29)
#define ORB_FMT_VED (2 << 29)
@@ -106,6 +118,7 @@
#define ORB_FUN_LUR (0xe << 16)
#define ORB_FUN_RST (0xf << 16)
#define ORB_FUN_MSK (0xf << 16)
+#define ORB_FUN_RUNQUEUE 0xffff
static char *orb_fun_name[] = {
/* 0 */ "LOGIN",
@@ -168,8 +181,8 @@ struct sbp_ocb {
#define OCB_ACT_MASK 3
#define OCB_RESERVED 0x10
#define OCB_DONE 0x20
+#define OCB_MATCH(o,s) (vtophys(&(o)->orb[0]) == ntohl((s)->orb_lo))
-#define SBP_RESOURCE_SHORTAGE 0x10
struct sbp_login_res{
u_int16_t len;
@@ -225,9 +238,11 @@ struct sbp_dev{
flags:4;
u_int8_t type;
u_int16_t lun_id;
+ int freeze;
struct cam_path *path;
struct sbp_target *target;
struct sbp_login_res login;
+ struct callout login_callout;
STAILQ_HEAD(, sbp_ocb) ocbs;
char vendor[32];
char product[32];
@@ -241,17 +256,24 @@ struct sbp_target {
struct sbp_softc *sbp;
struct fw_device *fwdev;
u_int32_t mgm_hi, mgm_lo;
+ struct sbp_ocb *mgm_ocb_cur;
+ STAILQ_HEAD(, sbp_ocb) mgm_ocb_queue;
+ struct callout mgm_ocb_timeout;
+#define SCAN_DELAY 2
+ struct callout scan_callout;
};
struct sbp_softc {
struct firewire_dev_comm fd;
- unsigned char flags;
struct cam_sim *sim;
+ struct cam_path *path;
struct sbp_target targets[SBP_NUM_TARGETS];
struct fw_bind fwb;
STAILQ_HEAD(, sbp_ocb) free_ocbs;
struct sbp_ocb *ocb;
bus_dma_tag_t dmat;
+#define SBP_RESOURCE_SHORTAGE 0x10
+ unsigned char flags;
};
static void sbp_post_explore __P((void *));
static void sbp_recv __P((struct fw_xfer *));
@@ -265,19 +287,21 @@ static void sbp_abort_all_ocbs __P((struct sbp_dev *, int));
static struct fw_xfer * sbp_write_cmd __P((struct sbp_dev *, int, int));
static struct sbp_ocb * sbp_get_ocb __P((struct sbp_softc *));
static struct sbp_ocb * sbp_enqueue_ocb __P((struct sbp_dev *, struct sbp_ocb *));
-static struct sbp_ocb * sbp_dequeue_ocb __P((struct sbp_dev *, u_int32_t));
+static struct sbp_ocb * sbp_dequeue_ocb __P((struct sbp_dev *, struct sbp_status *));
static void sbp_cam_detach_target __P((struct sbp_target *));
static void sbp_timeout __P((void *arg));
-static void sbp_mgm_orb __P((struct sbp_dev *, int, u_int16_t, u_int32_t));
+static void sbp_mgm_orb __P((struct sbp_dev *, int, struct sbp_ocb *));
+#define sbp_login(sdev) \
+ callout_reset(&(sdev)->login_callout, LOGIN_DELAY * hz, \
+ sbp_login_callout, (void *)(sdev));
MALLOC_DEFINE(M_SBP, "sbp", "SBP-II/FireWire");
/* cam related functions */
static void sbp_action(struct cam_sim *sim, union ccb *ccb);
static void sbp_poll(struct cam_sim *sim);
-static void sbp_cam_callback(struct cam_periph *periph,
- union ccb *ccb);
-static void sbp_cam_scan_lun(struct sbp_dev *sdev);
+static void sbp_cam_scan_lun(struct cam_periph *, union ccb *);
+static void sbp_cam_scan_target(void *arg);
static char *orb_status0[] = {
/* 0 */ "No additional information to report",
@@ -352,6 +376,9 @@ END_DEBUG
}
device_set_desc(dev, "SBP2/SCSI over firewire");
+
+ if (bootverbose)
+ debug = bootverbose;
return (0);
}
@@ -469,6 +496,11 @@ END_DEBUG
}
target->mgm_hi = 0xffff;
target->mgm_lo = 0xf0000000 | target->mgm_lo << 2;
+ target->mgm_ocb_cur = NULL;
+ STAILQ_INIT(&target->mgm_ocb_queue);
+ CALLOUT_INIT(&target->mgm_ocb_timeout);
+ CALLOUT_INIT(&target->scan_callout);
+
/* XXX num_lun may be changed. realloc luns? */
crom_init_context(&cc, target->fwdev->csrrom);
/* XXX shoud parse appropriate unit directories only */
@@ -498,6 +530,7 @@ END_DEBUG
sdev->lun_id = i;
sdev->target = target;
STAILQ_INIT(&sdev->ocbs);
+ CALLOUT_INIT(&sdev->login_callout);
sdev->status = SBP_DEV_DEAD;
}
crom_init_context(&cc, target->fwdev->csrrom);
@@ -565,14 +598,30 @@ sbp_probe_lun(struct sbp_dev *sdev)
rev = getcsrdata(sdev->target->fwdev, 0x3c);
snprintf(sdev->revision, sizeof(sdev->revision), "%06x", rev);
}
+
+
+static void
+sbp_login_callout(void *arg)
+{
+ struct sbp_dev *sdev = (struct sbp_dev *)arg;
+ sbp_mgm_orb(sdev, ORB_FUN_LGI, NULL);
+}
+
+#define SBP_FWDEV_ALIVE(fwdev) \
+ ((fwdev->status == FWDEVATTACHED) \
+ && (getcsrdata(fwdev, CSRKEY_SPEC) == CSRVAL_ANSIT10) \
+ && (getcsrdata(fwdev, CSRKEY_VER) == CSRVAL_T10SBP2))
+
static void
-sbp_probe_target(struct sbp_target *target, int alive)
+sbp_probe_target(void *arg)
{
+ struct sbp_target *target = (struct sbp_target *)arg;
struct sbp_softc *sbp;
struct sbp_dev *sdev;
struct firewire_comm *fc;
- int i;
+ int i, alive;
+ alive = SBP_FWDEV_ALIVE(target->fwdev);
SBP_DEBUG(1)
printf("sbp_probe_target %d\n", target->target_id);
if (!alive)
@@ -581,32 +630,43 @@ END_DEBUG
sbp = target->sbp;
fc = target->sbp->fd.fc;
+ /* XXX untimeout mgm_ocb and dequeue */
for (i=0; i < target->num_lun; i++) {
sdev = &target->luns[i];
if (alive && (sdev->status != SBP_DEV_DEAD)) {
if (sdev->path != NULL) {
xpt_freeze_devq(sdev->path, 1);
+ sdev->freeze ++;
}
- sbp_abort_all_ocbs(sdev, CAM_REQUEUE_REQ);
+ sbp_probe_lun(sdev);
+SBP_DEBUG(0)
+ sbp_show_sdev_info(sdev,
+#if 0
+ (sdev->status == SBP_DEV_TOATTACH));
+#else
+ (sdev->status == SBP_DEV_RESET));
+#endif
+END_DEBUG
+
+ sbp_abort_all_ocbs(sdev, CAM_SCSI_BUS_RESET);
switch (sdev->status) {
case SBP_DEV_RESET:
/* new or revived target */
- sbp_probe_lun(sdev);
if (auto_login) {
+#if 0
sdev->status = SBP_DEV_TOATTACH;
- sbp_mgm_orb(sdev, ORB_FUN_LGI, 0, 0);
+#endif
+ sbp_login(sdev);
}
break;
+ case SBP_DEV_TOATTACH:
+ case SBP_DEV_PROBE:
+ case SBP_DEV_ATTACHED:
case SBP_DEV_RETRY:
- sbp_probe_lun(sdev);
default:
- sbp_mgm_orb(sdev, ORB_FUN_RCN, 0, 0);
+ sbp_mgm_orb(sdev, ORB_FUN_RCN, NULL);
break;
}
-SBP_DEBUG(0)
- sbp_show_sdev_info(sdev,
- (sdev->status == SBP_DEV_TOATTACH));
-END_DEBUG
} else {
switch (sdev->status) {
case SBP_DEV_ATTACHED:
@@ -615,10 +675,12 @@ SBP_DEBUG(0)
sbp_show_sdev_info(sdev, 2);
printf("lost target\n");
END_DEBUG
- if (sdev->path)
+ if (sdev->path) {
xpt_freeze_devq(sdev->path, 1);
+ sdev->freeze ++;
+ }
sdev->status = SBP_DEV_RETRY;
- sbp_abort_all_ocbs(sdev, CAM_REQUEUE_REQ);
+ sbp_abort_all_ocbs(sdev, CAM_SCSI_BUS_RESET);
break;
case SBP_DEV_PROBE:
case SBP_DEV_TOATTACH:
@@ -644,11 +706,15 @@ sbp_post_explore(void *arg)
SBP_DEBUG(0)
printf("sbp_post_explore (sbp_cold=%d)\n", sbp_cold);
END_DEBUG
-#if 0
- xpt_freeze_simq(sbp->sim, /*count*/ 1);
+#if 0 /*
+ * XXX don't let CAM the bus rest. CAM tries to do something with
+ * freezed (DEV_RETRY) devices
+ */
+ xpt_async(AC_BUS_RESET, sbp->path, /*arg*/ NULL);
#endif
if (sbp_cold > 0)
sbp_cold --;
+
/* Gabage Collection */
for(i = 0 ; i < SBP_NUM_TARGETS ; i ++){
target = &sbp->targets[i];
@@ -678,9 +744,7 @@ SBP_DEBUG(0)
printf("not attached, state=%d.\n", fwdev->status);
}
END_DEBUG
- alive = (fwdev->status == FWDEVATTACHED)
- && (getcsrdata(fwdev, CSRKEY_SPEC) == CSRVAL_ANSIT10)
- && (getcsrdata(fwdev, CSRKEY_VER) == CSRVAL_T10SBP2);
+ alive = SBP_FWDEV_ALIVE(fwdev);
for(i = 0 ; i < SBP_NUM_TARGETS ; i ++){
target = &sbp->targets[i];
if(target->fwdev == fwdev ) {
@@ -698,7 +762,7 @@ END_DEBUG
continue;
}
}
- sbp_probe_target(target, alive);
+ sbp_probe_target((void *)target);
}
#if 0
timeout(sbp_release_queue, (caddr_t)sbp, bus_reset_rest * hz / 1000);
@@ -745,46 +809,91 @@ END_DEBUG
return;
}
+static struct sbp_dev *
+sbp_next_dev(struct sbp_target *target, int lun)
+{
+ struct sbp_dev *sdev;
+ int i;
+
+ for (i = lun, sdev = &target->luns[lun];
+ i < target->num_lun; i++, sdev++) {
+ if (sdev->status == SBP_DEV_PROBE)
+ break;
+ }
+ if (i >= target->num_lun)
+ return(NULL);
+ return(sdev);
+}
+
+#define SCAN_PRI 1
static void
-sbp_cam_callback(struct cam_periph *periph, union ccb *ccb)
+sbp_cam_scan_lun(struct cam_periph *periph, union ccb *ccb)
{
+ struct sbp_target *target;
struct sbp_dev *sdev;
+
sdev = (struct sbp_dev *) ccb->ccb_h.ccb_sdev_ptr;
+ target = sdev->target;
SBP_DEBUG(0)
sbp_show_sdev_info(sdev, 2);
- printf("sbp_cam_callback\n");
+ printf("sbp_cam_scan_lun\n");
END_DEBUG
- sdev->status = SBP_DEV_ATTACHED;
- free(ccb, M_SBP);
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
+ sdev->status = SBP_DEV_ATTACHED;
+ } else {
+ sbp_show_sdev_info(sdev, 2);
+ printf("scan failed\n");
+ }
+ 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;
}
static void
-sbp_cam_scan_lun(struct sbp_dev *sdev)
+sbp_cam_scan_target(void *arg)
{
+ struct sbp_target *target = (struct sbp_target *)arg;
+ struct sbp_dev *sdev;
union ccb *ccb;
- ccb = malloc(sizeof(union ccb), M_SBP, M_NOWAIT | M_ZERO);
- if (ccb == NULL) {
- printf("sbp_cam_scan_lun: malloc failed\n");
+ sdev = sbp_next_dev(target, 0);
+ if (sdev == NULL) {
+ printf("sbp_cam_scan_target: nothing to do for target%d\n",
+ target->target_id);
return;
}
-
SBP_DEBUG(0)
sbp_show_sdev_info(sdev, 2);
- printf("sbp_cam_scan_lun\n");
+ printf("sbp_cam_scan_target\n");
END_DEBUG
- xpt_setup_ccb(&ccb->ccb_h, sdev->path, 5/*priority (low)*/);
+ 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);
ccb->ccb_h.func_code = XPT_SCAN_LUN;
- ccb->ccb_h.cbfcnp = sbp_cam_callback;
+ ccb->ccb_h.cbfcnp = sbp_cam_scan_lun;
+ ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
ccb->crcn.flags = CAM_FLAG_NONE;
ccb->ccb_h.ccb_sdev_ptr = sdev;
/* The scan is in progress now. */
- sdev->status = SBP_DEV_PROBE;
xpt_action(ccb);
+ xpt_release_devq(sdev->path, sdev->freeze, TRUE);
+ sdev->freeze = 1;
}
+#if 0
static void
sbp_ping_unit_callback(struct cam_periph *periph, union ccb *ccb)
{
@@ -804,13 +913,15 @@ END_DEBUG
} else {
/* requeue */
xpt_action(ccb);
- xpt_release_devq(sdev->path, MAX_FREEZE, TRUE);
+ xpt_release_devq(sdev->path, sdev->freeze, TRUE);
+ sdev->freeze = 1; /* we will freeze */
}
} else {
free(ccb->csio.data_ptr, M_SBP);
free(ccb, M_SBP);
sdev->status = SBP_DEV_ATTACHED;
- xpt_release_devq(sdev->path, MAX_FREEZE, TRUE);
+ xpt_release_devq(sdev->path, sdev->freeze, TRUE);
+ sdev->freeze = 0;
}
}
@@ -850,7 +961,7 @@ END_DEBUG
/*
* We need to execute this command before any other queued command.
- * Make priority 0 and freeze queue after execution for retry.
+ * Make priority 0 and freeze the queue after execution for retry.
* cam's scan_lun command doesn't provide this feature.
*/
xpt_setup_ccb(&ccb->ccb_h, sdev->path, 0/*priority (high)*/);
@@ -867,16 +978,33 @@ END_DEBUG
/*timeout*/60000
);
ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
+ ccb->ccb_h.ccb_sdev_ptr = sdev;
xpt_action(ccb);
+ if (sdev->status != SBP_DEV_ATTACHED)
+ sdev->status = SBP_DEV_PROBE;
+ xpt_release_devq(sdev->path, sdev->freeze, TRUE);
+ sdev->freeze = 1; /* We will freeze the queue */
+}
+#endif
+
+static __inline void
+sbp_scan_dev(struct sbp_dev *sdev)
+{
sdev->status = SBP_DEV_PROBE;
+ callout_reset(&sdev->target->scan_callout, SCAN_DELAY * hz,
+ sbp_cam_scan_target, (void *)sdev->target);
}
static void
sbp_do_attach(struct fw_xfer *xfer)
{
struct sbp_dev *sdev;
+ struct sbp_target *target;
+ struct sbp_softc *sbp;
sdev = (struct sbp_dev *)xfer->sc;
+ target = sdev->target;
+ sbp = target->sbp;
SBP_DEBUG(0)
sbp_show_sdev_info(sdev, 2);
printf("sbp_do_attach\n");
@@ -885,8 +1013,8 @@ END_DEBUG
if (sdev->path == NULL)
xpt_create_path(&sdev->path, xpt_periph,
- cam_sim_path(sdev->target->sbp->sim),
- sdev->target->target_id, sdev->lun_id);
+ cam_sim_path(target->sbp->sim),
+ target->target_id, sdev->lun_id);
/*
* Let CAM scan the bus if we are in the boot process.
@@ -894,15 +1022,11 @@ END_DEBUG
* if LUN 0 doesn't exists.
*/
if (sbp_cold > 0) {
- sdev->status = SBP_DEV_PROBE;
+ sdev->status = SBP_DEV_ATTACHED;
return;
}
- if (sdev->status == SBP_DEV_RETRY)
- sbp_ping_unit(sdev);
- else
- sbp_cam_scan_lun(sdev);
- xpt_release_devq(sdev->path, MAX_FREEZE, TRUE);
+ sbp_scan_dev(sdev);
return;
}
@@ -917,9 +1041,10 @@ SBP_DEBUG(1)
printf("sbp_cmd_callback\n");
END_DEBUG
fw_xfer_free(xfer);
- sbp_abort_all_ocbs(sdev, CAM_REQUEUE_REQ);
- if (sdev->path)
- xpt_release_devq(sdev->path, MAX_FREEZE, TRUE);
+ if (sdev->path) {
+ xpt_release_devq(sdev->path, sdev->freeze, TRUE);
+ sdev->freeze = 0;
+ }
}
static void
@@ -942,6 +1067,7 @@ END_DEBUG
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.wreqq.data = htonl(0xf);
fw_asyreq(xfer->fc, -1, xfer);
+ sbp_abort_all_ocbs(sdev, CAM_BDR_SENT);
}
static void
@@ -1088,29 +1214,40 @@ sbp_write_cmd(struct sbp_dev *sdev, int tcode, int offset)
}
static void
-sbp_mgm_orb(struct sbp_dev *sdev, int func, u_int16_t orb_hi, u_int32_t orb_lo)
+sbp_mgm_orb(struct sbp_dev *sdev, int func, struct sbp_ocb *aocb)
{
struct fw_xfer *xfer;
struct fw_pkt *fp;
struct sbp_ocb *ocb;
+ struct sbp_target *target;
int s, nid;
- if ((ocb = sbp_get_ocb(sdev->target->sbp)) == NULL) {
- s = splfw();
- sdev->target->sbp->flags |= SBP_RESOURCE_SHORTAGE;
+ target = sdev->target;
+ nid = target->sbp->fd.fc->nodeid | FWLOCALBUS;
+
+ s = splfw();
+ if (func == ORB_FUN_RUNQUEUE) {
+ ocb = STAILQ_FIRST(&target->mgm_ocb_queue);
+ if (target->mgm_ocb_cur != NULL || ocb == NULL) {
+ splx(s);
+ return;
+ }
+ STAILQ_REMOVE_HEAD(&target->mgm_ocb_queue, ocb);
+ goto start;
+ }
+ if ((ocb = sbp_get_ocb(target->sbp)) == NULL) {
+ target->sbp->flags |= SBP_RESOURCE_SHORTAGE;
splx(s);
return;
}
ocb->flags = OCB_ACT_MGM;
ocb->sdev = sdev;
- ocb->ccb = NULL;
- nid = sdev->target->sbp->fd.fc->nodeid | FWLOCALBUS;
bzero((void *)(uintptr_t)(volatile void *)ocb->orb, sizeof(ocb->orb));
ocb->orb[6] = htonl((nid << 16) | SBP_BIND_HI);
ocb->orb[7] = htonl(SBP_DEV2ADDR(
- device_get_unit(sdev->target->sbp->fd.dev),
- sdev->target->target_id,
+ device_get_unit(target->sbp->fd.dev),
+ target->target_id,
sdev->lun_id));
SBP_DEBUG(0)
@@ -1125,8 +1262,8 @@ END_DEBUG
ocb->orb[5] = htonl(sizeof(struct sbp_login_res));
break;
case ORB_FUN_ATA:
- ocb->orb[0] = htonl((0 << 16) | orb_hi);
- ocb->orb[1] = htonl(orb_lo);
+ ocb->orb[0] = htonl((0 << 16) | 0);
+ ocb->orb[1] = htonl(vtophys(&aocb->orb[0]));
/* fall through */
case ORB_FUN_RCN:
case ORB_FUN_LGO:
@@ -1137,6 +1274,18 @@ END_DEBUG
break;
}
+ if (target->mgm_ocb_cur != NULL) {
+ /* there is a standing ORB */
+ STAILQ_INSERT_TAIL(&sdev->target->mgm_ocb_queue, ocb, ocb);
+ splx(s);
+ return;
+ }
+start:
+ target->mgm_ocb_cur = ocb;
+ splx(s);
+
+ callout_reset(&target->mgm_ocb_timeout, 5*hz,
+ sbp_timeout, (caddr_t)ocb);
xfer = sbp_write_cmd(sdev, FWTCODE_WREQB, 0);
if(xfer == NULL){
return;
@@ -1150,7 +1299,6 @@ END_DEBUG
fp->mode.wreqb.extcode = 0;
fp->mode.wreqb.payload[0] = htonl(nid << 16);
fp->mode.wreqb.payload[1] = htonl(vtophys(&ocb->orb[0]));
- sbp_enqueue_ocb(sdev, ocb);
fw_asyreq(xfer->fc, -1, xfer);
}
@@ -1314,15 +1462,19 @@ END_DEBUG
#endif
/* fall through */
case T_RBC:
- /* disable tag queuing */
- inq->flags &= ~SID_CmdQue;
+ /* enable tag queuing */
+#if 1
+ inq->flags |= SID_CmdQue;
+#endif
/*
* Override vendor/product/revision information.
* Some devices sometimes return strange strings.
*/
+#if 1
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));
+#endif
break;
}
}
@@ -1339,7 +1491,7 @@ sbp_recv1(struct fw_xfer *xfer){
struct sbp_login_res *login_res = NULL;
struct sbp_status *sbp_status;
struct sbp_target *target;
- int orb_fun, status_valid, t, l;
+ int orb_fun, status_valid0, status_valid, t, l;
u_int32_t addr;
/*
u_int32_t *ld;
@@ -1392,7 +1544,16 @@ END_DEBUG
switch (sbp_status->src) {
case 0:
case 1:
- ocb = sbp_dequeue_ocb(sdev, ntohl(sbp_status->orb_lo));
+ /* 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);
if (ocb == NULL) {
sbp_show_sdev_info(sdev, 2);
printf("No ocb on the queue\n");
@@ -1408,12 +1569,12 @@ END_DEBUG
printf("unknown sbp_status->src\n");
}
- status_valid = (sbp_status->src < 2
+ status_valid0 = (sbp_status->src < 2
&& sbp_status->resp == ORB_RES_CMPL
- && sbp_status->dead == 0
- && sbp_status->status == 0);
+ && sbp_status->dead == 0);
+ status_valid = (status_valid0 && sbp_status->status == 0);
- if (!status_valid || debug > 1){
+ if (!status_valid0 || debug > 1){
int status;
SBP_DEBUG(0)
sbp_show_sdev_info(sdev, 2);
@@ -1454,8 +1615,10 @@ END_DEBUG
/* we have to reset the fetch agent if it's dead */
if (sbp_status->dead) {
- if (sdev->path)
+ if (sdev->path) {
xpt_freeze_devq(sdev->path, 1);
+ sdev->freeze ++;
+ }
sbp_agent_reset(sdev);
}
@@ -1487,10 +1650,13 @@ SBP_DEBUG(0)
sbp_show_sdev_info(sdev, 2);
printf("login: len %d, ID %d, cmd %08x%08x, recon_hold %d\n", login_res->len, login_res->id, login_res->cmd_hi, login_res->cmd_lo, ntohs(login_res->recon_hold));
END_DEBUG
+#if 0
+ sdev->status = SBP_DEV_TOATTACH;
+#endif
#if 1
sbp_busy_timeout(sdev);
#else
- sbp_mgm_orb(sdev, ORB_FUN_ATS, 0, 0);
+ sbp_mgm_orb(sdev, ORB_FUN_ATS, NULL);
#endif
} else {
/* forgot logout? */
@@ -1507,12 +1673,13 @@ sbp_show_sdev_info(sdev, 2);
printf("reconnect: len %d, ID %d, cmd %08x%08x\n", login_res->len, login_res->id, login_res->cmd_hi, login_res->cmd_lo);
END_DEBUG
#if 1
- sbp_ping_unit(sdev);
- xpt_release_devq(sdev->path,
- MAX_FREEZE, TRUE);
+ if (sdev->status == SBP_DEV_ATTACHED)
+ sbp_scan_dev(sdev);
+ else
+ sbp_agent_reset(sdev);
#else
sdev->status = SBP_DEV_ATTACHED;
- sbp_mgm_orb(sdev, ORB_FUN_ATS, 0, 0);
+ sbp_mgm_orb(sdev, ORB_FUN_ATS, NULL);
#endif
} else {
/* reconnection hold time exceed? */
@@ -1520,7 +1687,7 @@ SBP_DEBUG(0)
sbp_show_sdev_info(sdev, 2);
printf("reconnect failed\n");
END_DEBUG
- sbp_mgm_orb(sdev, ORB_FUN_LGI, 0, 0);
+ sbp_login(sdev);
}
break;
case ORB_FUN_LGO:
@@ -1539,6 +1706,7 @@ END_DEBUG
printf("unknown function %d\n", orb_fun);
break;
}
+ sbp_mgm_orb(sdev, ORB_FUN_RUNQUEUE, NULL);
break;
case OCB_ACT_CMD:
if(ocb->ccb != NULL){
@@ -1664,8 +1832,9 @@ END_DEBUG
sbp->sim = cam_sim_alloc(sbp_action, sbp_poll, "sbp", sbp,
device_get_unit(dev),
- /*untagged*/ SBP_QUEUE_LEN,
- /*tagged*/0, devq);
+ /*untagged*/ 1,
+ /*tagged*/ SBP_QUEUE_LEN,
+ devq);
if (sbp->sim == NULL) {
cam_simq_free(devq);
@@ -1687,12 +1856,12 @@ END_DEBUG
sbp_free_ocb(sbp, &sbp->ocb[i]);
}
- if (xpt_bus_register(sbp->sim, /*bus*/0) != CAM_SUCCESS) {
- cam_sim_free(sbp->sim, /*free_devq*/TRUE);
- contigfree(sbp->ocb, sizeof (struct sbp_ocb) * SBP_NUM_OCB,
- M_SBP);
- return (ENXIO);
- }
+ if (xpt_bus_register(sbp->sim, /*bus*/0) != CAM_SUCCESS)
+ goto fail;
+
+ if (xpt_create_path(&sbp->path, xpt_periph, cam_sim_path(sbp->sim),
+ CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP)
+ goto fail;
xfer = fw_xfer_alloc(M_SBP);
xfer->act.hand = sbp_recv;
@@ -1718,6 +1887,10 @@ END_DEBUG
}
return (0);
+fail:
+ cam_sim_free(sbp->sim, /*free_devq*/TRUE);
+ contigfree(sbp->ocb, sizeof (struct sbp_ocb) * SBP_NUM_OCB, M_SBP);
+ return (ENXIO);
}
static int
@@ -1738,7 +1911,7 @@ END_DEBUG
sdev = &target->luns[j];
if (sdev->status >= SBP_DEV_TOATTACH &&
sdev->status <= SBP_DEV_ATTACHED)
- sbp_mgm_orb(sdev, ORB_FUN_LGO, 0, 0);
+ sbp_mgm_orb(sdev, ORB_FUN_LGO, NULL);
}
}
return 0;
@@ -1771,6 +1944,7 @@ END_DEBUG
for (i = 0; i < SBP_NUM_TARGETS; i ++)
sbp_cam_detach_target(&sbp->targets[i]);
+ xpt_free_path(sbp->path);
xpt_bus_deregister(cam_sim_path(sbp->sim));
sbp_logout_all(sbp);
@@ -1798,8 +1972,11 @@ sbp_cam_detach_target(struct sbp_target *target)
SBP_DEBUG(0)
printf("sbp_detach_target %d\n", target->target_id);
END_DEBUG
+ callout_stop(&target->scan_callout);
+ callout_stop(&target->mgm_ocb_timeout);
for (i = 0; i < target->num_lun; i++) {
sdev = &target->luns[i];
+ callout_stop(&sdev->login_callout);
if (sdev->status == SBP_DEV_RESET ||
sdev->status == SBP_DEV_DEAD)
continue;
@@ -1822,7 +1999,16 @@ sbp_timeout(void *arg)
sbp_show_sdev_info(sdev, 2);
printf("request timeout ... ");
+ if (ocb->flags == OCB_ACT_MGM) {
+ printf("management ORB\n");
+ /* XXX just ignore for now */
+ sdev->target->mgm_ocb_cur = NULL;
+ sbp_mgm_orb(sdev, ORB_FUN_RUNQUEUE, NULL);
+ return;
+ }
+
xpt_freeze_devq(sdev->path, 1);
+ sdev->freeze ++;
sbp_abort_all_ocbs(sdev, CAM_CMD_TIMEOUT);
if (sdev->flags & SBP_DEV_TIMEOUT) {
#if 0
@@ -1834,7 +2020,7 @@ sbp_timeout(void *arg)
sdev->status == SBP_DEV_RETRY;
#else
printf("target reset\n");
- sbp_mgm_orb(sdev, ORB_FUN_RST, 0, 0);
+ sbp_mgm_orb(sdev, ORB_FUN_RST, NULL);
#endif
sdev->flags &= ~SBP_DEV_TIMEOUT;
} else {
@@ -2086,7 +2272,7 @@ SBP_DEBUG(1)
ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
END_DEBUG
cpi->version_num = 1; /* XXX??? */
- cpi->hba_inquiry = 0;
+ cpi->hba_inquiry = PI_TAG_ABLE;
cpi->target_sprt = 0;
cpi->hba_misc = PIM_NOBUSRESET;
cpi->hba_eng_cnt = 0;
@@ -2112,9 +2298,9 @@ SBP_DEBUG(1)
device_get_nameunit(sbp->fd.dev),
ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
END_DEBUG
- /* Disable disconnect and tagged queuing */
+ /* Enable disconnect and tagged queuing */
cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
- cts->flags = 0;
+ cts->flags = CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB;
cts->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
@@ -2124,6 +2310,8 @@ END_DEBUG
ccb->ccb_h.status = CAM_UA_ABORT;
xpt_done(ccb);
break;
+ case XPT_SET_TRAN_SETTINGS:
+ /* XXX */
default:
ccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(ccb);
@@ -2206,7 +2394,7 @@ sbp_poll(struct cam_sim *sim)
return;
}
static struct sbp_ocb *
-sbp_dequeue_ocb(struct sbp_dev *sdev, u_int32_t orb_lo)
+sbp_dequeue_ocb(struct sbp_dev *sdev, struct sbp_status *sbp_status)
{
struct sbp_ocb *ocb;
struct sbp_ocb *next;
@@ -2225,7 +2413,7 @@ SBP_DEBUG(1)
#endif
vtophys(&ocb->orb[0]), ntohl(ocb->orb[1]), flags);
END_DEBUG
- if (vtophys(&ocb->orb[0]) == orb_lo) {
+ if (OCB_MATCH(ocb, sbp_status)) {
/* found */
if (ocb->flags & OCB_RESERVED)
ocb->flags |= OCB_DONE;
@@ -2309,7 +2497,7 @@ sbp_get_ocb(struct sbp_softc *sbp)
printf("ocb shortage!!!\n");
return NULL;
}
- STAILQ_REMOVE(&sbp->free_ocbs, ocb, sbp_ocb, ocb);
+ STAILQ_REMOVE_HEAD(&sbp->free_ocbs, ocb);
splx(s);
ocb->ccb = NULL;
return (ocb);
OpenPOWER on IntegriCloud