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.
This commit is contained in:
parent
8fc4d0f9a7
commit
455454994f
sys/dev/firewire
@ -422,11 +422,6 @@ firewire_attach( device_t dev )
|
||||
dev_depends(sc->dev, d);
|
||||
#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);
|
||||
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_probe_target(struct sbp_target *target, int alive)
|
||||
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(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 void
|
||||
sbp_cam_callback(struct cam_periph *periph, union ccb *ccb)
|
||||
static struct sbp_dev *
|
||||
sbp_next_dev(struct sbp_target *target, int lun)
|
||||
{
|
||||
struct sbp_dev *sdev;
|
||||
sdev = (struct sbp_dev *) ccb->ccb_h.ccb_sdev_ptr;
|
||||
SBP_DEBUG(0)
|
||||
sbp_show_sdev_info(sdev, 2);
|
||||
printf("sbp_cam_callback\n");
|
||||
END_DEBUG
|
||||
sdev->status = SBP_DEV_ATTACHED;
|
||||
free(ccb, M_SBP);
|
||||
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_scan_lun(struct sbp_dev *sdev)
|
||||
sbp_cam_scan_lun(struct cam_periph *periph, union ccb *ccb)
|
||||
{
|
||||
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");
|
||||
return;
|
||||
}
|
||||
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_scan_lun\n");
|
||||
END_DEBUG
|
||||
xpt_setup_ccb(&ccb->ccb_h, sdev->path, 5/*priority (low)*/);
|
||||
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_target(void *arg)
|
||||
{
|
||||
struct sbp_target *target = (struct sbp_target *)arg;
|
||||
struct sbp_dev *sdev;
|
||||
union ccb *ccb;
|
||||
|
||||
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_target\n");
|
||||
END_DEBUG
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user