1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/ksynch.h>
  28 #include <sys/errno.h>
  29 #include <sys/uio.h>
  30 #include <sys/ddi.h>
  31 
  32 #define __NSC_GEN__
  33 #include "nsc_dev.h"
  34 
  35 #ifdef DS_DDICT
  36 #include "../contract.h"
  37 #endif
  38 
  39 #include "../nsctl.h"
  40 
  41 
  42 #define _I(x)   (((long)(&((nsc_io_t *)0)->x))/sizeof (long))
  43 
  44 
  45 nsc_def_t _nsc_cache_def[] = {
  46         { "AllocBuf",   (uintptr_t)nsc_ioerr,   _I(alloc_buf) },
  47         { "FreeBuf",    (uintptr_t)nsc_fatal,   _I(free_buf) },
  48         { "Read",       (uintptr_t)nsc_fatal,   _I(read) },
  49         { "Write",      (uintptr_t)nsc_fatal,   _I(write) },
  50         { "Zero",       (uintptr_t)nsc_fatal,   _I(zero) },
  51         { "Copy",       (uintptr_t)nsc_ioerr,   _I(copy) },
  52         { "CopyDirect", (uintptr_t)nsc_ioerr,   _I(copy_direct) },
  53         { "Uncommit",   (uintptr_t)nsc_null,    _I(uncommit) },
  54         { "AllocHandle", (uintptr_t)nsc_null,   _I(alloc_h) },
  55         { "FreeHandle", (uintptr_t)nsc_fatal,   _I(free_h) },
  56         { "TrackSize",  (uintptr_t)nsc_null,    _I(trksize) },
  57         { "Discard",    (uintptr_t)nsc_null,    _I(discard) },
  58         { "Sizes",      (uintptr_t)nsc_null,    _I(sizes) },
  59         { "GetPinned",  (uintptr_t)nsc_null,    _I(getpin) },
  60         { "NodeHints",  (uintptr_t)nsc_inval,   _I(nodehints) },
  61         { NULL,         (uintptr_t)NULL,        0 }
  62 };
  63 
  64 
  65 static int _nsc_alloc_buf_h(blind_t, nsc_off_t, nsc_size_t, int,
  66     nsc_buf_t **, nsc_fd_t *);
  67 static int _nsc_copy_h(nsc_buf_t *, nsc_buf_t *, nsc_off_t,
  68     nsc_off_t, nsc_size_t);
  69 
  70 extern nsc_io_t *_nsc_reserve_io(char *, int);
  71 extern void _nsc_release_io(nsc_io_t *);
  72 
  73 extern kmutex_t _nsc_io_lock;
  74 
  75 
  76 
  77 
  78 /* ARGSUSED */
  79 
  80 void
  81 _nsc_add_cache(nsc_io_t *io)
  82 {
  83 }
  84 
  85 
  86 nsc_buf_t *
  87 nsc_alloc_handle(nsc_fd_t *fd, void (*d_cb)(), void (*r_cb)(), void (*w_cb)())
  88 {
  89         nsc_buf_t *h = (*fd->sf_aio->alloc_h)(d_cb, r_cb, w_cb, fd->sf_cd);
  90 
  91         if (h)
  92                 h->sb_fd = fd;
  93 
  94         return (h);
  95 }
  96 
  97 
  98 int
  99 nsc_free_handle(nsc_buf_t *h)
 100 {
 101         if (h == NULL || (h->sb_flag & NSC_ABUF))
 102                 return (EINVAL);
 103 
 104         return ((*h->sb_fd->sf_aio->free_h)(h, h->sb_fd->sf_cd));
 105 }
 106 
 107 
 108 int
 109 nsc_alloc_abuf(nsc_off_t pos, nsc_size_t len, int flag, nsc_buf_t **ptr)
 110 {
 111         nsc_buf_t *h;
 112         nsc_io_t *io;
 113         int rc;
 114 
 115         if (*ptr != NULL)
 116                 return (EINVAL);
 117 
 118         if (flag & NSC_NODATA)
 119                 return (EINVAL);
 120 
 121         io = _nsc_reserve_io(NULL, NSC_ANON);
 122         if (io == NULL)
 123                 return (ENOBUFS);
 124 
 125         if ((h = (*io->alloc_h)(NULL, NULL, NULL, NSC_ANON_CD)) == NULL) {
 126                 _nsc_release_io(io);
 127                 return (ENOBUFS);
 128         }
 129 
 130         rc = (*io->alloc_buf)(NSC_ANON_CD, pos, len,
 131             NSC_NOCACHE|flag, &h, NULL);
 132         if (rc <= 0) {
 133                 h->sb_flag &= ~NSC_HALLOCATED;
 134                 h->sb_flag |= NSC_ABUF;
 135                 h->sb_fd = (nsc_fd_t *)io;   /* note overloaded field */
 136 
 137                 *ptr = h;
 138 
 139                 mutex_enter(&_nsc_io_lock);
 140                 io->abufcnt++;
 141                 mutex_exit(&_nsc_io_lock);
 142         }
 143 
 144         _nsc_release_io(io);
 145         return (rc);
 146 }
 147 
 148 
 149 int
 150 nsc_alloc_buf(nsc_fd_t *fd, nsc_off_t pos, nsc_size_t len,
 151     int flag, nsc_buf_t **ptr)
 152 {
 153         int (*fn)() = _nsc_alloc_buf_h;
 154 
 155         if ((fd->sf_avail & NSC_WRITE) == 0)
 156                 if (flag & NSC_WRBUF)
 157                         return (EACCES);
 158 
 159         if ((flag & (NSC_READ|NSC_WRITE|NSC_NODATA)) ==
 160             (NSC_READ|NSC_NODATA)) {
 161                 /*
 162                  * NSC_NODATA access checks.
 163                  *
 164                  * - NSC_READ|NSC_NODATA is illegal since there would
 165                  *   be no data buffer to immediately read the data into.
 166                  * - NSC_WRITE|NSC_NODATA is valid since the client can
 167                  *   provide the buffer and then call nsc_write() as
 168                  *   necessary.
 169                  * - NSC_NODATA is valid since the client can provide the
 170                  *   buffer and then call nsc_read() or nsc_write() as
 171                  *   necessary.
 172                  */
 173                 return (EACCES);
 174         }
 175 
 176         if (*ptr) {
 177                 fn = fd->sf_aio->alloc_buf;
 178                 (*ptr)->sb_fd = fd;
 179         }
 180 
 181         return (*fn)(fd->sf_cd, pos, len, flag, ptr, fd);
 182 }
 183 
 184 
 185 /* ARGSUSED */
 186 
 187 static int
 188 _nsc_alloc_buf_h(blind_t cd, nsc_off_t pos, nsc_size_t len,
 189     int flag, nsc_buf_t **ptr, nsc_fd_t *fd)
 190 {
 191         nsc_buf_t *h;
 192         int rc;
 193 
 194         if (!(h = nsc_alloc_handle(fd, NULL, NULL, NULL)))
 195                 return (ENOBUFS);
 196 
 197         if ((rc = nsc_alloc_buf(fd, pos, len, flag, &h)) <= 0) {
 198                 h->sb_flag &= ~NSC_HALLOCATED;
 199                 *ptr = h;
 200                 return (rc);
 201         }
 202 
 203         (void) nsc_free_handle(h);
 204         return (rc);
 205 }
 206 
 207 
 208 int
 209 nsc_read(nsc_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
 210 {
 211         if ((h->sb_flag & NSC_ABUF) ||
 212             ((h->sb_flag & NSC_NODATA) && h->sb_vec == NULL))
 213                 return (EIO);
 214 
 215         return ((*h->sb_fd->sf_aio->read)(h, pos, len, flag));
 216 }
 217 
 218 
 219 int
 220 nsc_write(nsc_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
 221 {
 222         if ((h->sb_flag & NSC_ABUF) ||
 223             ((h->sb_flag & NSC_NODATA) && h->sb_vec == NULL))
 224                 return (EIO);
 225 
 226         return ((*h->sb_fd->sf_aio->write)(h, pos, len, flag));
 227 }
 228 
 229 
 230 int
 231 nsc_zero(nsc_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
 232 {
 233         if ((h->sb_flag & NSC_ABUF) ||
 234             ((h->sb_flag & NSC_NODATA) && h->sb_vec == NULL))
 235                 return (EIO);
 236 
 237         return ((*h->sb_fd->sf_aio->zero)(h, pos, len, flag));
 238 }
 239 
 240 
 241 int
 242 nsc_copy(nsc_buf_t *h1, nsc_buf_t *h2, nsc_off_t pos1,
 243     nsc_off_t pos2, nsc_size_t len)
 244 {
 245         nsc_io_t *io1, *io2;
 246         int rc = EIO;
 247 
 248         if (((h1->sb_flag & NSC_NODATA) && h1->sb_vec == NULL) ||
 249             ((h2->sb_flag & NSC_NODATA) && h2->sb_vec == NULL))
 250                 return (EIO);
 251 
 252         if (h1->sb_fd && h2->sb_fd) {
 253                 io1 = (h1->sb_flag & NSC_ABUF) ?
 254                     (nsc_io_t *)h1->sb_fd : h1->sb_fd->sf_aio;
 255 
 256                 io2 = (h2->sb_flag & NSC_ABUF) ?
 257                     (nsc_io_t *)h2->sb_fd : h2->sb_fd->sf_aio;
 258 
 259                 if (io1 == io2)
 260                         rc = (*io1->copy)(h1, h2, pos1, pos2, len);
 261         }
 262 
 263         if (rc != EIO)
 264                 return (rc);
 265 
 266         return (_nsc_copy_h(h1, h2, pos1, pos2, len));
 267 }
 268 
 269 
 270 static int
 271 _nsc_copy_h(nsc_buf_t *h1, nsc_buf_t *h2, nsc_off_t pos1,
 272     nsc_off_t pos2, nsc_size_t len)
 273 {
 274         nsc_vec_t *v1, *v2;
 275         uchar_t *a1, *a2;
 276         int sz, l1, l2, lenbytes;       /* byte sizes within an nsc_vec_t */
 277 
 278         if (pos1 < h1->sb_pos || pos1 + len > h1->sb_pos + h1->sb_len ||
 279             pos2 < h2->sb_pos || pos2 + len > h2->sb_pos + h2->sb_len)
 280                 return (EINVAL);
 281 
 282         if (!len)
 283                 return (0);
 284 
 285         /* find starting point in "from" vector */
 286 
 287         v1 = h1->sb_vec;
 288         pos1 -= h1->sb_pos;
 289 
 290         for (; pos1 >= FBA_NUM(v1->sv_len); v1++)
 291                 pos1 -= FBA_NUM(v1->sv_len);
 292 
 293         a1 = v1->sv_addr + FBA_SIZE(pos1);
 294         l1 = v1->sv_len - FBA_SIZE(pos1);
 295 
 296         /* find starting point in "to" vector */
 297 
 298         v2 = h2->sb_vec;
 299         pos2 -= h2->sb_pos;
 300 
 301         for (; pos2 >= FBA_NUM(v2->sv_len); v2++)
 302                 pos2 -= FBA_NUM(v2->sv_len);
 303 
 304         a2 = v2->sv_addr + FBA_SIZE(pos2);
 305         l2 = v2->sv_len - FBA_SIZE(pos2);
 306 
 307         /* copy required data */
 308 
 309         ASSERT(FBA_SIZE(len) < INT_MAX);
 310         lenbytes = (int)FBA_SIZE(len);
 311 
 312         while (lenbytes) {
 313                 sz = min(l1, l2);
 314                 sz = min(sz, lenbytes);
 315 
 316                 bcopy(a1, a2, sz);
 317 
 318                 l1 -= sz; l2 -= sz;
 319                 a1 += sz; a2 += sz;
 320                 lenbytes -= sz;
 321 
 322                 if (!l1)
 323                         a1 = (++v1)->sv_addr, l1 = v1->sv_len;
 324                 if (!l2)
 325                         a2 = (++v2)->sv_addr, l2 = v2->sv_len;
 326         }
 327 
 328         return (0);
 329 }
 330 
 331 
 332 int
 333 nsc_copy_direct(nsc_buf_t *h1, nsc_buf_t *h2, nsc_off_t pos1,
 334     nsc_off_t pos2, nsc_size_t len)
 335 {
 336         int rc = EIO;
 337 
 338         if (!h1 || !h2)
 339                 return (EINVAL);
 340 
 341         if (((h1->sb_flag & NSC_NODATA) && h1->sb_vec == NULL) ||
 342             ((h2->sb_flag & NSC_NODATA) && h2->sb_vec == NULL))
 343                 return (EIO);
 344 
 345         if ((h2->sb_flag & NSC_RDWR) != NSC_WRITE) {
 346                 cmn_err(CE_WARN,
 347                     "nsc_copy_direct: h2 (%p) flags (%x) include NSC_READ",
 348                     (void *)h2, h2->sb_flag);
 349         }
 350 
 351         if ((h2->sb_flag & NSC_WRTHRU) == 0) {
 352                 cmn_err(CE_WARN,
 353                     "nsc_copy_direct: h2 (%p) flags (%x) do not "
 354                     "include NSC_WRTHRU", (void *)h2, h2->sb_flag);
 355                 h2->sb_flag |= NSC_WRTHRU;
 356         }
 357 
 358         if (h1->sb_fd && h2->sb_fd && h1->sb_fd->sf_aio == h2->sb_fd->sf_aio)
 359                 rc = (*h1->sb_fd->sf_aio->copy_direct)(h1, h2, pos1, pos2, len);
 360 
 361         if (rc != EIO)
 362                 return (rc);
 363 
 364         /*
 365          * The slow way ...
 366          */
 367 
 368         rc = nsc_copy(h1, h2, pos1, pos2, len);
 369         if (rc <= 0)
 370                 rc = nsc_write(h2, pos2, len, NSC_WRTHRU);
 371 
 372         return (rc);
 373 }
 374 
 375 
 376 int
 377 nsc_uncommit(nsc_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
 378 {
 379         if (h->sb_flag & NSC_ABUF)
 380                 return (EIO);
 381 
 382         return ((*h->sb_fd->sf_aio->uncommit)(h, pos, len, flag));
 383 }
 384 
 385 
 386 int
 387 nsc_free_buf(nsc_buf_t *h)
 388 {
 389         nsc_io_t *io;
 390         int abuf;
 391         int rc;
 392 
 393         if (h == NULL)
 394                 return (0);
 395 
 396         if ((h->sb_flag & NSC_NODATA) && (h->sb_vec != NULL)) {
 397                 h->sb_vec = NULL;
 398         }
 399 
 400         abuf = (h->sb_flag & NSC_ABUF);
 401 
 402         if (abuf)
 403                 io = (nsc_io_t *)h->sb_fd;
 404         else
 405                 io = h->sb_fd->sf_aio;
 406 
 407         rc = (*io->free_buf)(h);
 408 
 409         if (abuf && rc <= 0) {
 410                 mutex_enter(&_nsc_io_lock);
 411                 io->abufcnt--;
 412                 mutex_exit(&_nsc_io_lock);
 413         }
 414 
 415         return (rc);
 416 }
 417 
 418 
 419 int
 420 nsc_node_hints(uint_t *hints)
 421 {
 422         return (_nsc_call_io(_I(nodehints), (blind_t)hints,
 423             (blind_t)NSC_GET_NODE_HINT, 0));
 424 }
 425 
 426 int
 427 nsc_node_hints_set(uint_t hints)
 428 {
 429         return (_nsc_call_io(_I(nodehints), (blind_t)(unsigned long)hints,
 430             (blind_t)NSC_SET_NODE_HINT, 0));
 431 }
 432 
 433 
 434 int
 435 nsc_cache_sizes(int *asize, int *wsize)
 436 {
 437         return (_nsc_call_io(_I(sizes), (blind_t)asize, (blind_t)wsize, 0));
 438 }
 439 
 440 
 441 int
 442 nsc_set_trksize(nsc_fd_t *fd, nsc_size_t trsize)
 443 {
 444         return (*fd->sf_aio->trksize)(fd->sf_cd, trsize);
 445 }
 446 
 447 
 448 int
 449 nsc_get_pinned(nsc_fd_t *fd)
 450 {
 451         return (*fd->sf_aio->getpin)(fd->sf_cd);
 452 }
 453 
 454 
 455 int
 456 nsc_discard_pinned(nsc_fd_t *fd, nsc_off_t pos, nsc_size_t len)
 457 {
 458         return (*fd->sf_aio->discard)(fd->sf_cd, pos, len);
 459 }
 460 
 461 
 462 void
 463 nsc_pinned_data(nsc_iodev_t *iodev, nsc_off_t pos, nsc_size_t len)
 464 {
 465         nsc_fd_t *fd;
 466 
 467         if (!iodev)
 468                 return;
 469 
 470         mutex_enter(&iodev->si_dev->nsc_lock);
 471         iodev->si_busy++;
 472         mutex_exit(&iodev->si_dev->nsc_lock);
 473 
 474         for (fd = iodev->si_open; fd; fd = fd->sf_next)
 475                 if (fd->sf_avail & _NSC_ATTACH)
 476                         (*fd->sf_pinned)(fd->sf_arg, pos, len);
 477 
 478         _nsc_wake_dev(iodev->si_dev, &iodev->si_busy);
 479 }
 480 
 481 
 482 void
 483 nsc_unpinned_data(nsc_iodev_t *iodev, nsc_off_t pos, nsc_size_t len)
 484 {
 485         nsc_fd_t *fd;
 486 
 487         if (!iodev)
 488                 return;
 489 
 490         mutex_enter(&iodev->si_dev->nsc_lock);
 491         iodev->si_busy++;
 492         mutex_exit(&iodev->si_dev->nsc_lock);
 493 
 494         for (fd = iodev->si_open; fd; fd = fd->sf_next)
 495                 if (fd->sf_avail & _NSC_ATTACH)
 496                         (*fd->sf_unpinned)(fd->sf_arg, pos, len);
 497 
 498         _nsc_wake_dev(iodev->si_dev, &iodev->si_busy);
 499 }