Subject: Re: Promise onboard ATA RAID cannot work
To: Shin-ichi Yoshimoto <yosimoto@waishi.jp>
From: enami tsugutomo <enami@sm.sony.co.jp>
List: current-users
Date: 10/10/2003 18:00:26
Shin-ichi Yoshimoto <yosimoto@waishi.jp> writes:
> OK. Can I be of any help to you ?
If you want to play with, here is my change. No neat feature, but at
least normal operation works.
enami.
Index: ld_ataraid.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/ld_ataraid.c,v
retrieving revision 1.8
diff -c -r1.8 ld_ataraid.c
*** ld_ataraid.c 14 Jul 2003 15:47:02 -0000 1.8
--- ld_ataraid.c 10 Oct 2003 08:48:46 -0000
***************
*** 102,107 ****
--- 102,110 ----
struct ld_ataraid_softc *cb_sc; /* pointer to ld softc */
u_int cb_comp; /* target component */
SIMPLEQ_ENTRY(cbuf) cb_q; /* fifo of component buffers */
+ struct cbuf *cb_other; /* other cbuf in case of mirror */
+ int cb_flags;
+ #define CBUF_IODONE 0x00000001 /* I/O is already successfully done */
};
#define CBUF_GET() pool_get(&ld_ataraid_cbufpl, PR_NOWAIT);
***************
*** 154,163 ****
--- 157,170 ----
case AAI_L_RAID1:
level = "RAID1";
+ ld->sc_start = ld_ataraid_start_raid0;
+ sc->sc_iodone = ld_ataraid_iodone_raid0;
break;
case AAI_L_RAID0 | AAI_L_RAID1:
level = "RAID0+1";
+ ld->sc_start = ld_ataraid_start_raid0;
+ sc->sc_iodone = ld_ataraid_iodone_raid0;
break;
default:
***************
*** 248,253 ****
--- 255,262 ----
cbp->cb_obp = bp;
cbp->cb_sc = sc;
cbp->cb_comp = comp;
+ cbp->cb_other = NULL;
+ cbp->cb_flags = 0;
return (cbp);
}
***************
*** 322,333 ****
{
struct ld_ataraid_softc *sc = (void *) ld;
struct ataraid_array_info *aai = sc->sc_aai;
SIMPLEQ_HEAD(, cbuf) cbufq;
! struct cbuf *cbp;
caddr_t addr;
daddr_t bn, cbn, tbn, off;
long bcount, rcount;
u_int comp;
/* Allocate component buffers. */
SIMPLEQ_INIT(&cbufq);
--- 331,346 ----
{
struct ld_ataraid_softc *sc = (void *) ld;
struct ataraid_array_info *aai = sc->sc_aai;
+ struct ataraid_disk_info *adi;
SIMPLEQ_HEAD(, cbuf) cbufq;
! struct cbuf *cbp, *other_cbp;
caddr_t addr;
daddr_t bn, cbn, tbn, off;
long bcount, rcount;
u_int comp;
+ const int read = bp->b_flags & B_READ;
+ const int mirror = aai->aai_level & AAI_L_RAID1;
+ int error;
/* Allocate component buffers. */
SIMPLEQ_INIT(&cbufq);
***************
*** 357,372 ****
rcount = min(bcount, dbtob(aai->aai_interleave - off));
}
cbp = ld_ataraid_make_cbuf(sc, bp, comp, cbn, addr, rcount);
if (cbp == NULL) {
/* Free the already allocated component buffers. */
while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) {
SIMPLEQ_REMOVE_HEAD(&cbufq, cb_q);
CBUF_PUT(cbp);
}
! return (EAGAIN);
}
SIMPLEQ_INSERT_TAIL(&cbufq, cbp, cb_q);
bn += btodb(rcount);
addr += rcount;
}
--- 370,419 ----
rcount = min(bcount, dbtob(aai->aai_interleave - off));
}
+ /*
+ * See if a component is valid.
+ */
+ try_mirror:
+ adi = &aai->aai_disks[comp];
+ if ((adi->adi_status & ADI_S_ONLINE) == 0) {
+ if (mirror && comp < aai->aai_width) {
+ comp += aai->aai_width;
+ goto try_mirror;
+ }
+
+ /*
+ * No component available.
+ */
+ error = EIO;
+ goto free_and_exit;
+ }
+
cbp = ld_ataraid_make_cbuf(sc, bp, comp, cbn, addr, rcount);
if (cbp == NULL) {
+ resource_shortage:
+ error = EAGAIN;
+ free_and_exit:
/* Free the already allocated component buffers. */
while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) {
SIMPLEQ_REMOVE_HEAD(&cbufq, cb_q);
CBUF_PUT(cbp);
}
! return (error);
}
SIMPLEQ_INSERT_TAIL(&cbufq, cbp, cb_q);
+ if (mirror && !read && comp < aai->aai_width) {
+ comp += aai->aai_width;
+ adi = &aai->aai_disks[comp];
+ if (adi->adi_status & ADI_S_ONLINE) {
+ other_cbp = ld_ataraid_make_cbuf(sc, bp,
+ comp, cbn, addr, rcount);
+ if (other_cbp == NULL)
+ goto resource_shortage;
+ SIMPLEQ_INSERT_TAIL(&cbufq, other_cbp, cb_q);
+ other_cbp->cb_other = cbp;
+ cbp->cb_other = other_cbp;
+ }
+ }
bn += btodb(rcount);
addr += rcount;
}
***************
*** 389,421 ****
static void
ld_ataraid_iodone_raid0(struct buf *vbp)
{
! struct cbuf *cbp = (struct cbuf *) vbp;
struct buf *bp = cbp->cb_obp;
struct ld_ataraid_softc *sc = cbp->cb_sc;
long count;
! int s;
s = splbio();
if (cbp->cb_buf.b_flags & B_ERROR) {
! bp->b_flags |= B_ERROR;
! bp->b_error = cbp->cb_buf.b_error ?
! cbp->cb_buf.b_error : EIO;
/* XXX Update component config blocks. */
! printf("%s: error %d on component %d\n",
! sc->sc_ld.sc_dv.dv_xname, bp->b_error, cbp->cb_comp);
}
count = cbp->cb_buf.b_bcount;
CBUF_PUT(cbp);
/* If all done, "interrupt". */
bp->b_resid -= count;
if (bp->b_resid < 0)
panic("ld_ataraid_iodone_raid0: count");
if (bp->b_resid == 0)
lddone(&sc->sc_ld, bp);
splx(s);
}
--- 436,522 ----
static void
ld_ataraid_iodone_raid0(struct buf *vbp)
{
! struct cbuf *cbp = (struct cbuf *) vbp, *other_cbp;
struct buf *bp = cbp->cb_obp;
struct ld_ataraid_softc *sc = cbp->cb_sc;
+ struct ataraid_array_info *aai = sc->sc_aai;
+ struct ataraid_disk_info *adi;
long count;
! int s, iodone;
s = splbio();
+ iodone = cbp->cb_flags & CBUF_IODONE;
+ other_cbp = cbp->cb_other;
+ if (other_cbp != NULL)
+ /* You are alone */
+ other_cbp->cb_other = NULL;
+
if (cbp->cb_buf.b_flags & B_ERROR) {
! /*
! * Mark this component broken.
! */
! adi = &aai->aai_disks[cbp->cb_comp];
! adi->adi_status &= ~ADI_S_ONLINE;
!
! printf("%s: error %d on component %d (%s)\n",
! sc->sc_ld.sc_dv.dv_xname, bp->b_error, cbp->cb_comp,
! adi->adi_dev->dv_xname);
!
! /*
! * If we didn't see an error yet and we are reading
! * RAID1 disk, try another component.
! */
! if ((bp->b_flags & B_ERROR) == 0 &&
! (cbp->cb_buf.b_flags & B_READ) != 0 &&
! (aai->aai_level & AAI_L_RAID1) != 0 &&
! cbp->cb_comp < aai->aai_width) {
! cbp->cb_comp += aai->aai_width;
! adi = &aai->aai_disks[cbp->cb_comp];
! if (adi->adi_status & ADI_S_ONLINE) {
! cbp->cb_buf.b_flags &= ~B_ERROR;
! VOP_STRATEGY(&cbp->cb_buf);
! goto out;
! }
! }
!
! if (iodone || other_cbp != NULL)
! /*
! * If I/O on other component successfully done
! * or the I/O is still in progress, no need
! * to tell an error to upper layer.
! */
! ;
! else {
! bp->b_flags |= B_ERROR;
! bp->b_error = cbp->cb_buf.b_error ?
! cbp->cb_buf.b_error : EIO;
! }
/* XXX Update component config blocks. */
! } else {
! /*
! * If other I/O is still in progress, tell it that
! * our I/O is successfully done.
! */
! if (other_cbp != NULL)
! other_cbp->cb_flags |= CBUF_IODONE;
}
count = cbp->cb_buf.b_bcount;
CBUF_PUT(cbp);
+ if (other_cbp != NULL)
+ goto out;
+
/* If all done, "interrupt". */
bp->b_resid -= count;
if (bp->b_resid < 0)
panic("ld_ataraid_iodone_raid0: count");
if (bp->b_resid == 0)
lddone(&sc->sc_ld, bp);
+
+ out:
splx(s);
}