Print this page
7367 blkdev: support block size larger than 512
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
*** 21,30 ****
--- 21,31 ----
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
* Copyright 2012 Alexey Zaytsev <alexey.zaytsev@gmail.com> All rights reserved.
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 The MathWorks, Inc. All rights reserved.
*/
#include <sys/types.h>
#include <sys/ksynch.h>
#include <sys/kmem.h>
*** 751,761 ****
ASSERT(bp);
xi->i_bp = bp;
xi->i_func = func;
! xi->i_blkno = bp->b_lblkno;
if (bp->b_bcount == 0) {
xi->i_len = 0;
xi->i_nblks = 0;
xi->i_kaddr = NULL;
--- 752,762 ----
ASSERT(bp);
xi->i_bp = bp;
xi->i_func = func;
! xi->i_blkno = bp->b_lblkno >> (bd->d_blkshift - DEV_BSHIFT);
if (bp->b_bcount == 0) {
xi->i_len = 0;
xi->i_nblks = 0;
xi->i_kaddr = NULL;
*** 781,791 ****
xi->i_offset = 0;
xi->i_num_win =
(bp->b_bcount + (bd->d_maxxfer - 1)) / bd->d_maxxfer;
xi->i_cur_win = 0;
xi->i_len = min(bp->b_bcount, bd->d_maxxfer);
! xi->i_nblks = xi->i_len >> shift;
xi->i_kaddr = bp->b_un.b_addr;
xi->i_resid = bp->b_bcount;
} else {
/*
--- 782,792 ----
xi->i_offset = 0;
xi->i_num_win =
(bp->b_bcount + (bd->d_maxxfer - 1)) / bd->d_maxxfer;
xi->i_cur_win = 0;
xi->i_len = min(bp->b_bcount, bd->d_maxxfer);
! xi->i_nblks = howmany(xi->i_len, (1U << shift));
xi->i_kaddr = bp->b_un.b_addr;
xi->i_resid = bp->b_bcount;
} else {
/*
*** 804,814 ****
case DDI_DMA_MAPPED:
xi->i_num_win = 1;
xi->i_cur_win = 0;
xi->i_offset = 0;
xi->i_len = bp->b_bcount;
! xi->i_nblks = xi->i_len >> shift;
xi->i_resid = bp->b_bcount;
rv = 0;
break;
case DDI_DMA_PARTIAL_MAP:
xi->i_cur_win = 0;
--- 805,815 ----
case DDI_DMA_MAPPED:
xi->i_num_win = 1;
xi->i_cur_win = 0;
xi->i_offset = 0;
xi->i_len = bp->b_bcount;
! xi->i_nblks = howmany(xi->i_len, (1U << shift));
xi->i_resid = bp->b_bcount;
rv = 0;
break;
case DDI_DMA_PARTIAL_MAP:
xi->i_cur_win = 0;
*** 816,832 ****
if ((ddi_dma_numwin(xi->i_dmah, &xi->i_num_win) !=
DDI_SUCCESS) ||
(ddi_dma_getwin(xi->i_dmah, 0, &xi->i_offset,
&len, &xi->i_dmac, &xi->i_ndmac) !=
DDI_SUCCESS) ||
! (P2PHASE(len, shift) != 0)) {
(void) ddi_dma_unbind_handle(xi->i_dmah);
rv = EFAULT;
goto done;
}
xi->i_len = len;
! xi->i_nblks = xi->i_len >> shift;
xi->i_resid = bp->b_bcount;
rv = 0;
break;
case DDI_DMA_NORESOURCES:
rv = EAGAIN;
--- 817,833 ----
if ((ddi_dma_numwin(xi->i_dmah, &xi->i_num_win) !=
DDI_SUCCESS) ||
(ddi_dma_getwin(xi->i_dmah, 0, &xi->i_offset,
&len, &xi->i_dmac, &xi->i_ndmac) !=
DDI_SUCCESS) ||
! (P2PHASE(len, (1U << DEV_BSHIFT)) != 0)) {
(void) ddi_dma_unbind_handle(xi->i_dmah);
rv = EFAULT;
goto done;
}
xi->i_len = len;
! xi->i_nblks = howmany(xi->i_len, (1U << shift));
xi->i_resid = bp->b_bcount;
rv = 0;
break;
case DDI_DMA_NORESOURCES:
rv = EAGAIN;
*** 1033,1084 ****
diskaddr_t psize;
bd_t *bd;
bd_xfer_impl_t *xi;
buf_t *bp;
int rv;
rw_enter(&bd_lock, RW_READER);
part = BDPART(dev);
inst = BDINST(dev);
if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
rw_exit(&bd_lock);
return (ENXIO);
}
/*
* do cmlb, but do it synchronously unless we already have the
* partition (which we probably should.)
*/
if (cmlb_partinfo(bd->d_cmlbh, part, &psize, &pstart, NULL, NULL,
(void *)1)) {
rw_exit(&bd_lock);
return (ENXIO);
}
! if ((blkno + nblk) > psize) {
rw_exit(&bd_lock);
return (EINVAL);
}
bp = getrbuf(KM_NOSLEEP);
if (bp == NULL) {
rw_exit(&bd_lock);
return (ENOMEM);
}
! bp->b_bcount = nblk << bd->d_blkshift;
bp->b_resid = bp->b_bcount;
bp->b_lblkno = blkno;
bp->b_un.b_addr = caddr;
xi = bd_xfer_alloc(bd, bp, bd->d_ops.o_write, KM_NOSLEEP);
if (xi == NULL) {
rw_exit(&bd_lock);
freerbuf(bp);
return (ENOMEM);
}
! xi->i_blkno = blkno + pstart;
xi->i_flags = BD_XFER_POLL;
bd_submit(bd, xi);
rw_exit(&bd_lock);
/*
--- 1034,1091 ----
diskaddr_t psize;
bd_t *bd;
bd_xfer_impl_t *xi;
buf_t *bp;
int rv;
+ uint32_t shift;
+ daddr_t d_blkno;
+ int d_nblk;
rw_enter(&bd_lock, RW_READER);
part = BDPART(dev);
inst = BDINST(dev);
if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
rw_exit(&bd_lock);
return (ENXIO);
}
+ shift = bd->d_blkshift;
+ d_blkno = blkno >> (shift - DEV_BSHIFT);
+ d_nblk = howmany((nblk << DEV_BSHIFT), (1U << shift));
/*
* do cmlb, but do it synchronously unless we already have the
* partition (which we probably should.)
*/
if (cmlb_partinfo(bd->d_cmlbh, part, &psize, &pstart, NULL, NULL,
(void *)1)) {
rw_exit(&bd_lock);
return (ENXIO);
}
! if ((d_blkno + d_nblk) > psize) {
rw_exit(&bd_lock);
return (EINVAL);
}
bp = getrbuf(KM_NOSLEEP);
if (bp == NULL) {
rw_exit(&bd_lock);
return (ENOMEM);
}
! bp->b_bcount = nblk << DEV_BSHIFT;
bp->b_resid = bp->b_bcount;
bp->b_lblkno = blkno;
bp->b_un.b_addr = caddr;
xi = bd_xfer_alloc(bd, bp, bd->d_ops.o_write, KM_NOSLEEP);
if (xi == NULL) {
rw_exit(&bd_lock);
freerbuf(bp);
return (ENOMEM);
}
! xi->i_blkno = d_blkno + pstart;
xi->i_flags = BD_XFER_POLL;
bd_submit(bd, xi);
rw_exit(&bd_lock);
/*
*** 1150,1159 ****
--- 1157,1167 ----
diskaddr_t p_nblks;
diskaddr_t b_nblks;
bd_xfer_impl_t *xi;
uint32_t shift;
int (*func)(void *, bd_xfer_t *);
+ diskaddr_t lblkno;
part = BDPART(bp->b_edev);
inst = BDINST(bp->b_edev);
ASSERT(bp);
*** 1172,1196 ****
biodone(bp);
return (0);
}
shift = bd->d_blkshift;
!
! if ((P2PHASE(bp->b_bcount, (1U << shift)) != 0) ||
! (bp->b_lblkno > p_nblks)) {
bioerror(bp, ENXIO);
biodone(bp);
return (0);
}
! b_nblks = bp->b_bcount >> shift;
! if ((bp->b_lblkno == p_nblks) || (bp->b_bcount == 0)) {
biodone(bp);
return (0);
}
! if ((b_nblks + bp->b_lblkno) > p_nblks) {
! bp->b_resid = ((bp->b_lblkno + b_nblks - p_nblks) << shift);
bp->b_bcount -= bp->b_resid;
} else {
bp->b_resid = 0;
}
func = (bp->b_flags & B_READ) ? bd->d_ops.o_read : bd->d_ops.o_write;
--- 1180,1204 ----
biodone(bp);
return (0);
}
shift = bd->d_blkshift;
! lblkno = bp->b_lblkno >> (shift - DEV_BSHIFT);
! if ((P2PHASE(bp->b_bcount, (1U << DEV_BSHIFT)) != 0) ||
! (lblkno > p_nblks)) {
bioerror(bp, ENXIO);
biodone(bp);
return (0);
}
! b_nblks = howmany(bp->b_bcount, (1U << shift));
! if ((lblkno == p_nblks) || (bp->b_bcount == 0)) {
biodone(bp);
return (0);
}
! if ((b_nblks + lblkno) > p_nblks) {
! bp->b_resid = ((lblkno + b_nblks - p_nblks) << shift);
bp->b_bcount -= bp->b_resid;
} else {
bp->b_resid = 0;
}
func = (bp->b_flags & B_READ) ? bd->d_ops.o_read : bd->d_ops.o_write;
*** 1202,1212 ****
if (xi == NULL) {
/* bd_request_alloc will have done bioerror */
biodone(bp);
return (0);
}
! xi->i_blkno = bp->b_lblkno + p_lba;
bd_submit(bd, xi);
return (0);
}
--- 1210,1220 ----
if (xi == NULL) {
/* bd_request_alloc will have done bioerror */
biodone(bp);
return (0);
}
! xi->i_blkno = lblkno + p_lba;
bd_submit(bd, xi);
return (0);
}
*** 1384,1394 ****
*/
kmflag = tg_cookie ? KM_NOSLEEP : KM_SLEEP;
bd = ddi_get_soft_state(bd_state, ddi_get_instance(dip));
! if (P2PHASE(length, (1U << bd->d_blkshift)) != 0) {
/* We can only transfer whole blocks at a time! */
return (EINVAL);
}
if ((bp = getrbuf(kmflag)) == NULL) {
--- 1392,1402 ----
*/
kmflag = tg_cookie ? KM_NOSLEEP : KM_SLEEP;
bd = ddi_get_soft_state(bd_state, ddi_get_instance(dip));
! if (P2PHASE(length, (1U << DEV_BSHIFT)) != 0) {
/* We can only transfer whole blocks at a time! */
return (EINVAL);
}
if ((bp = getrbuf(kmflag)) == NULL) {
*** 1903,1923 ****
len = min(bp->b_bcount - xi->i_offset, bd->d_maxxfer);
}
if ((rv != DDI_SUCCESS) ||
! (P2PHASE(len, (1U << xi->i_blkshift) != 0))) {
bd_runq_exit(xi, EFAULT);
bp->b_resid += xi->i_resid;
bd_xfer_free(xi);
bioerror(bp, EFAULT);
biodone(bp);
return;
}
xi->i_len = len;
! xi->i_nblks = len >> xi->i_blkshift;
/* Submit next window to hardware. */
rv = xi->i_func(bd->d_private, &xi->i_public);
if (rv != 0) {
bd_runq_exit(xi, rv);
--- 1911,1931 ----
len = min(bp->b_bcount - xi->i_offset, bd->d_maxxfer);
}
if ((rv != DDI_SUCCESS) ||
! (P2PHASE(len, (1U << DEV_BSHIFT) != 0))) {
bd_runq_exit(xi, EFAULT);
bp->b_resid += xi->i_resid;
bd_xfer_free(xi);
bioerror(bp, EFAULT);
biodone(bp);
return;
}
xi->i_len = len;
! xi->i_nblks = howmany(len, (1U << xi->i_blkshift));
/* Submit next window to hardware. */
rv = xi->i_func(bd->d_private, &xi->i_public);
if (rv != 0) {
bd_runq_exit(xi, rv);