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);
  }