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 /*
  27  * RAM Safe Store Module
  28  */
  29 
  30 #include <sys/types.h>
  31 #include <sys/ksynch.h>
  32 #include <sys/kmem.h>
  33 #include <sys/cmn_err.h>
  34 #include <sys/errno.h>
  35 
  36 #include <sys/nsc_thread.h>
  37 #include "sd_cache.h"
  38 #include "sd_trace.h"
  39 #include <sys/unistat/spcs_s.h>
  40 #include <sys/unistat/spcs_s_k.h>
  41 #include <sys/unistat/spcs_errors.h>
  42 
  43 #include "safestore.h"
  44 #include "safestore_impl.h"
  45 #include "safestore_ram.h"
  46 
  47 extern void _sd_print(int level, char *fmt, ...);
  48 
  49 static int ss_ram_configure(ss_common_config_t *, spcs_s_info_t);
  50 static int ss_ram_deconfigure(int);
  51 static int ss_ram_getvdir(const ss_vdirkey_t *, ss_vdir_t *);
  52 static int ss_ram_getvdirent(const ss_vdir_t *, ss_voldata_t *);
  53 static int ss_ram_getvol(ss_voldata_t *);
  54 static int ss_ram_setvol(const ss_voldata_t *);
  55 static int ss_ram_getcdir(const ss_cdirkey_t *, ss_cdir_t *);
  56 static int ss_ram_getcdirent(ss_cdir_t *, ss_centry_info_t *);
  57 static int ss_ram_allocresource(int, int *, ss_resourcelist_t **);
  58 static void ss_ram_deallocresource(ss_resource_t *);
  59 static int ss_ram_getresource(ss_resourcelist_t **, ss_resource_t **);
  60 static int ss_ram_getcentry(ss_centry_info_t *);
  61 static int ss_ram_setcentry(const ss_centry_info_t *);
  62 static int ss_ram_cblock_read(const ss_resource_t *, void *, int, int);
  63 static int ss_ram_cblock_write(const ss_resource_t *, const void *, int, int);
  64 static int ss_ram_ctl(uint_t, uintptr_t);
  65 
  66 
  67 safestore_ops_t ss_ram_ops = {
  68         "safestore_ram",
  69         SS_M_RAM | SS_T_NONE,
  70         0,
  71         ss_ram_configure,
  72         ss_ram_deconfigure,
  73         ss_ram_getvdir,
  74         ss_ram_getvdirent,
  75         ss_ram_getvol,
  76         ss_ram_setvol,
  77         ss_ram_getcdir,
  78         ss_ram_getcdirent,
  79         ss_ram_allocresource,
  80         ss_ram_deallocresource,
  81         ss_ram_getresource,
  82         ss_ram_getcentry,
  83         ss_ram_setcentry,
  84         ss_ram_cblock_read,
  85         ss_ram_cblock_write,
  86         ss_ram_ctl
  87 };
  88 
  89 static void ss_ram_vol_deconfigure();
  90 static int ss_ram_vol_configure(int);
  91 static int ss_ram_wctl_configure();
  92 static void ss_ram_wctl_deconfigure(void);
  93 static int ss_ram_deconfigure_locked();
  94 
  95 static kmutex_t ss_ram_config_lock;
  96 
  97 static ss_common_config_t ss_ramcommon_config;
  98 static ss_ram_config_t ss_ram_config;
  99 
 100 static char default_cblock [8192];
 101 
 102 
 103 #define MEGABYTE (1024*1024)
 104 
 105 void
 106 ss_ram_init()
 107 {
 108         mutex_init(&ss_ram_config_lock, NULL, MUTEX_DRIVER, NULL);
 109         bzero(&ss_ram_config, sizeof (ss_ram_config_t));
 110         bzero(&ss_ramcommon_config, sizeof (ss_common_config_t));
 111         sst_register_mod(&ss_ram_ops);
 112 
 113         ss_ram_config.ss_configured = SS_INITTED;
 114 }
 115 
 116 void
 117 ss_ram_deinit()
 118 {
 119         mutex_destroy(&ss_ram_config_lock);
 120         sst_unregister_mod(&ss_ram_ops);
 121 }
 122 
 123 
 124 /* ARGSUSED */
 125 static int
 126 ss_ram_configure(ss_common_config_t *clientptr, spcs_s_info_t kstatus)
 127 {
 128 
 129         if (clientptr->ssc_wsize == 0) /* choose a default? */
 130                 return (EINVAL);
 131 
 132         mutex_enter(&ss_ram_config_lock);
 133 
 134         /* read in the parameters */
 135         bcopy(clientptr, &ss_ramcommon_config, sizeof (ss_common_config_t));
 136 
 137         /* set the page size */
 138         ss_ramcommon_config.ssc_ss_psize = BLK_SIZE(1);
 139 
 140         /* initialize client page size if not set */
 141         if (ss_ramcommon_config.ssc_client_psize == 0)
 142                 ss_ramcommon_config.ssc_client_psize =
 143                                         ss_ramcommon_config.ssc_ss_psize;
 144 
 145         /* setup volume directory */
 146         if (ss_ram_vol_configure(clientptr->ssc_maxfiles)) {
 147                 (void) ss_ram_deconfigure_locked();
 148                 mutex_exit(&ss_ram_config_lock);
 149                 return (SDBC_ENONETMEM);
 150         }
 151 
 152         /* setup write q */
 153         if (ss_ram_wctl_configure()) {
 154                 (void) ss_ram_deconfigure_locked();
 155                 mutex_exit(&ss_ram_config_lock);
 156                 return (SDBC_ENONETMEM);
 157         }
 158 
 159         if (ss_ramcommon_config.ssc_flag & SS_GENPATTERN) {
 160                 (void) _sd_fill_pattern(default_cblock,
 161                                         ss_ramcommon_config.ssc_pattern,
 162                                         sizeof (default_cblock));
 163         }
 164 
 165         ss_ram_config.ss_configured = SS_CONFIGURED;
 166         /* update client */
 167         bcopy(&ss_ramcommon_config, clientptr, sizeof (ss_common_config_t));
 168 
 169         mutex_exit(&ss_ram_config_lock);
 170         return (SS_OK);
 171 }
 172 
 173 /* acquires the ss_ram_config_lock and calls ss_ram_deconfigure_locked() */
 174 /* ARGSUSED */
 175 static int
 176 ss_ram_deconfigure(int dirty)
 177 {
 178         int rc;
 179 
 180         if (ss_ram_config.ss_configured != SS_CONFIGURED)
 181                 return (SS_ERR);
 182 
 183         mutex_enter(&ss_ram_config_lock);
 184         rc = ss_ram_deconfigure_locked();
 185         mutex_exit(&ss_ram_config_lock);
 186 
 187         return (rc);
 188 }
 189 
 190 /*
 191  * internal use only
 192  * caller should acquire config lock before calling this function
 193  */
 194 static int
 195 ss_ram_deconfigure_locked()
 196 {
 197         ss_ram_wctl_deconfigure();
 198         ss_ram_vol_deconfigure();
 199 
 200         ss_ram_config.ss_configured = 0;
 201         return (SS_OK);
 202 }
 203 
 204 static int
 205 ss_ram_getvdir(const ss_vdirkey_t *key, ss_vdir_t *vdir)
 206 {
 207         ss_ram_vdir_t *ram_vdir = (ss_ram_vdir_t *)vdir;
 208         int rc = SS_OK;
 209 
 210         if ((key == NULL) || (vdir == NULL))
 211                 return (SS_ERR);
 212 
 213         switch (key->vk_type) {
 214                 case VDIR_ALL:
 215                         ram_vdir->rv_type = VDIR_ALL;
 216                         ram_vdir->rv_u.rv_all.rv_current =
 217                                                 ss_ram_config.sn_volumes;
 218                         ram_vdir->rv_u.rv_all.rv_end =
 219                                         ss_ram_config.sn_volumes +
 220                                         ss_ramcommon_config.ssc_maxfiles;
 221                         break;
 222                 case VDIR_VOL:
 223                 case VDIR_NODE:
 224                 default:
 225                         rc = SS_ERR;
 226                         break;
 227         }
 228 
 229         return (rc);
 230 }
 231 
 232 
 233 static int
 234 ss_ram_getvdirent(const ss_vdir_t *vdir, ss_voldata_t *vol)
 235 {
 236         int rc = SS_OK;
 237 
 238         ss_ram_vdir_t *ram_vdir = (ss_ram_vdir_t *)vdir;
 239 
 240         if (vol == NULL)
 241                 return (SS_ERR);
 242 
 243         if (vdir == NULL)
 244                 return (SS_ERR);
 245 
 246         switch (ram_vdir->rv_type) {
 247                 case VDIR_ALL:
 248                         if (ram_vdir->rv_u.rv_all.rv_current ==
 249                                         ram_vdir->rv_u.rv_all.rv_end) {
 250                                 rc = SS_EOF;
 251                         } else {
 252                                 /* stuff client copy with token */
 253                                 vol->sv_vol = (ss_vol_t *)
 254                                         ram_vdir->rv_u.rv_all.rv_current++;
 255 
 256                                 /* get the volume data */
 257                                 rc = ss_ram_getvol(vol);
 258                         }
 259                         break;
 260                 case VDIR_VOL:
 261                 case VDIR_NODE:
 262                 default:
 263                         rc = SS_ERR;
 264                         break;
 265         }
 266 
 267         return (rc);
 268 }
 269 
 270 static int
 271 ss_ram_getvol(ss_voldata_t *voldata)
 272 {
 273         ss_voldata_impl_t *ramvoldata;
 274 
 275         if (voldata == NULL)
 276                 return (SS_ERR);
 277 
 278         /* get the pointer to the volume entry */
 279         ramvoldata = (ss_voldata_impl_t *)voldata->sv_vol;
 280 
 281         if (ramvoldata == NULL)
 282                 return (SS_ERR);
 283 
 284         /* stuff the client structure from the ram entry */
 285         voldata->sv_cd = ramvoldata->svi_cd;
 286         voldata->sv_pinned = ramvoldata->svi_pinned;
 287         voldata->sv_attached = ramvoldata->svi_attached;
 288         voldata->sv_devidsz = ramvoldata->svi_devidsz;
 289 
 290         bcopy(ramvoldata->svi_volname, voldata->sv_volname,
 291                                 sizeof (voldata->sv_volname));
 292 
 293         bcopy(ramvoldata->svi_devid, voldata->sv_devid,
 294                                 sizeof (voldata->sv_devid));
 295         return (SS_OK);
 296 }
 297 
 298 static int
 299 ss_ram_setvol(const ss_voldata_t *voldata)
 300 {
 301         ss_voldata_impl_t *ramvoldata;
 302 
 303         if (voldata == NULL)
 304                 return (SS_ERR);
 305 
 306         /* get the pointer to the volume entry */
 307         ramvoldata = (ss_voldata_impl_t *)voldata->sv_vol;
 308 
 309         if (ramvoldata == NULL)
 310                 return (SS_ERR);
 311 
 312         /* load the volume entry from the client structure */
 313         ramvoldata->svi_cd = voldata->sv_cd;
 314         ramvoldata->svi_pinned = voldata->sv_pinned;
 315         ramvoldata->svi_attached = voldata->sv_attached;
 316         ramvoldata->svi_devidsz = voldata->sv_devidsz;
 317         bcopy(voldata->sv_volname, ramvoldata->svi_volname,
 318                                 sizeof (ramvoldata->svi_volname));
 319 
 320         bcopy(voldata->sv_devid, ramvoldata->svi_devid,
 321                                 sizeof (ramvoldata->svi_devid));
 322         return (SS_OK);
 323 }
 324 
 325 static int
 326 ss_ram_getcdir(const ss_cdirkey_t *key, ss_cdir_t *cdir)
 327 {
 328         ss_ram_cdir_t *ram_cdir = (ss_ram_cdir_t *)cdir;
 329         int rc = 0;
 330 
 331         if ((key == NULL) || (cdir == NULL))
 332                 return (SS_ERR);
 333 
 334         switch (key->ck_type) {
 335                 case CDIR_ALL:
 336                         { int blocks;
 337 
 338                                 blocks = ss_ramcommon_config.ssc_wsize /
 339                                         ss_ramcommon_config.ssc_client_psize;
 340 
 341                                 ram_cdir->rc_type = CDIR_ALL;
 342                                 ram_cdir->rc_u.rc_all.rc_current =
 343                                                 ss_ram_config.sn_wr_cctl;
 344                                 ram_cdir->rc_u.rc_all.rc_end =
 345                                         ss_ram_config.sn_wr_cctl + blocks;
 346                         }
 347                         break;
 348                 case CDIR_VOL:
 349                 case CDIR_NODE:
 350                 default:
 351                         rc = SS_ERR;
 352                         break;
 353         }
 354 
 355         return (rc);
 356 }
 357 
 358 static int
 359 ss_ram_getcdirent(ss_cdir_t *cdir, ss_centry_info_t *centry)
 360 {
 361         int rc = SS_OK;
 362 
 363         ss_ram_cdir_t *ram_cdir = (ss_ram_cdir_t *)cdir;
 364 
 365         if (centry == NULL)
 366                 return (SS_ERR);
 367 
 368         if (cdir == NULL)
 369                 return (SS_ERR);
 370 
 371         switch (ram_cdir->rc_type) {
 372                 case CDIR_ALL:
 373                         if (ram_cdir->rc_u.rc_all.rc_current ==
 374                                                 ram_cdir->rc_u.rc_all.rc_end) {
 375                                 rc = SS_EOF;
 376                         } else {
 377                                 /* stuff client copy with token */
 378                                 centry->sc_res = (ss_resource_t *)
 379                                         ram_cdir->rc_u.rc_all.rc_current++;
 380 
 381                                 /* get the centry data */
 382                                 rc = ss_ram_getcentry(centry);
 383                         }
 384                         break;
 385                 case CDIR_VOL:
 386                 case CDIR_NODE:
 387                 default:
 388                         rc = SS_ERR;
 389                         break;
 390         }
 391 
 392         return (rc);
 393 }
 394 
 395 static int
 396 ss_ram_allocresource(int need, int *stall, ss_resourcelist_t **reslist)
 397 {
 398         if (reslist == NULL)
 399                 return (SS_ERR);
 400 
 401         *reslist = ((ss_resourcelist_t *)ss_alloc_write(need, stall,
 402                                         &(ss_ram_config.sn_wr_queue)));
 403         if (*reslist == NULL)    /* do sync write */
 404                 return (SS_ERR);
 405 
 406         return (SS_OK);
 407 }
 408 
 409 static void
 410 ss_ram_deallocresource(ss_resource_t *res)
 411 {
 412         ss_release_write((ss_wr_cctl_t *)res, &(ss_ram_config.sn_wr_queue));
 413 }
 414 
 415 static int
 416 ss_ram_getresource(ss_resourcelist_t **reslist, ss_resource_t **res)
 417 {
 418         if ((res == NULL) || (reslist == NULL)) {
 419                 return (SS_ERR);
 420         }
 421 
 422         if (*reslist == NULL)
 423                 return (SS_EOF);
 424 
 425         *res = (ss_resource_t *)(*reslist);
 426         *reslist = (ss_resourcelist_t *)
 427                 ((ss_wr_cctl_t *)(*reslist))->wc_next;
 428 
 429         return (SS_OK);
 430 }
 431 
 432 static int
 433 ss_ram_getcentry(ss_centry_info_t *centry)
 434 {
 435         ss_wr_cctl_t *wctl;
 436         ss_centry_info_impl_t *ramcentry = (ss_centry_info_impl_t *)centry;
 437 
 438         if (centry == NULL)
 439                 return (SS_ERR);
 440         else
 441                 wctl = (ss_wr_cctl_t *)centry->sc_res;
 442 
 443         if (wctl == NULL)
 444                 return (SS_ERR);
 445 
 446         if (wctl->wc_gl_info)
 447                 bcopy(wctl->wc_gl_info, ramcentry,
 448                         sizeof (ss_centry_info_impl_t));
 449         else
 450                 return (SS_ERR);
 451 
 452         return (SS_OK);
 453 }
 454 
 455 static int
 456 ss_ram_setcentry(const ss_centry_info_t *centry)
 457 {
 458         ss_wr_cctl_t *wctl;
 459         ss_centry_info_impl_t *ramcentry = (ss_centry_info_impl_t *)centry;
 460 
 461         if (centry == NULL)
 462                 return (SS_ERR);
 463         else
 464                 wctl = (ss_wr_cctl_t *)centry->sc_res;
 465 
 466         if (wctl == NULL)
 467                 return (SS_ERR);
 468 
 469         if (wctl->wc_gl_info)
 470                 bcopy(ramcentry, wctl->wc_gl_info,
 471                                 sizeof (ss_centry_info_impl_t));
 472         else
 473                 return (SS_ERR);
 474 
 475         return (SS_OK);
 476 }
 477 
 478 
 479 static int
 480 ss_ram_cblock_read(const ss_resource_t *res, void *buf,
 481                                 int count, int srcoffset)
 482 {
 483         if ((res == NULL) || (buf == NULL))
 484                 return (SS_ERR);
 485 
 486         if ((srcoffset < 0) ||
 487                         (srcoffset > ss_ramcommon_config.ssc_client_psize))
 488                 return (SS_ERR);
 489 
 490         bcopy(default_cblock + srcoffset, buf, count);
 491 
 492         return (SS_OK);
 493 }
 494 
 495 static int
 496 ss_ram_cblock_write(const ss_resource_t *res,
 497                         const void *buf, int count, int destoffset)
 498 {
 499         if ((res == NULL) || (buf == NULL))
 500                 return (SS_ERR);
 501 
 502         if ((destoffset < 0) ||
 503                         (destoffset > ss_ramcommon_config.ssc_client_psize))
 504                 return (SS_ERR);
 505 
 506         bcopy(buf, default_cblock + destoffset, count);
 507 
 508         return (SS_OK);
 509 }
 510 
 511 static int
 512 ss_ram_ctl(uint_t cmd, uintptr_t arg)
 513 {
 514         int rc = SS_OK;
 515 
 516         switch (cmd) {
 517                 case SSIOC_STATS:
 518                         ((ssioc_stats_t *)arg)->wq_inq =
 519                                         ss_ram_config.sn_wr_queue.wq_inq;
 520                         break;
 521                 default:
 522                         cmn_err(CE_WARN, "ss_nvs_ctl: cmd %x not supported",
 523                                                         cmd);
 524                         rc = ENOTTY;
 525                         break;
 526         }
 527 
 528         return (rc);
 529 }
 530 
 531 static int
 532 ss_ram_vol_configure(int maxvols)
 533 {
 534         if ((ss_ram_config.sn_volumes = kmem_zalloc(maxvols *
 535                         sizeof (ss_voldata_impl_t), KM_NOSLEEP)) == NULL)
 536                 return (-1);
 537 
 538         return (0);
 539 }
 540 
 541 static void
 542 ss_ram_vol_deconfigure()
 543 {
 544         int maxvols = ss_ramcommon_config.ssc_maxfiles;
 545 
 546         if (ss_ram_config.sn_volumes)
 547                 kmem_free(ss_ram_config.sn_volumes,
 548                                         maxvols * sizeof (ss_voldata_impl_t));
 549 }
 550 
 551 static int
 552 ss_ram_wctl_configure()
 553 {
 554         int blocks;
 555         ss_wr_cctl_t *wentry;
 556         static ss_centry_info_impl_t *gl;
 557         int i;
 558 
 559         blocks = ss_ramcommon_config.ssc_wsize /
 560                         ss_ramcommon_config.ssc_client_psize;
 561 
 562         if ((ss_ram_config.sn_wr_cctl = (ss_wr_cctl_t *)
 563                 kmem_zalloc(blocks * sizeof (ss_wr_cctl_t), KM_NOSLEEP))
 564                                                                 == NULL) {
 565                 return (-1);
 566         }
 567 
 568         if ((ss_ram_config.sn_gl_centry_info = (ss_centry_info_impl_t *)
 569                 kmem_zalloc(blocks * sizeof (ss_centry_info_impl_t),
 570                                         KM_NOSLEEP)) == NULL) {
 571                 return (-1);
 572         }
 573 
 574         /*
 575          * Mini-DSP: no write/ft area
 576          * (ie forced_wrthru clear)
 577          */
 578 
 579         if (_sdbc_writeq_configure(&(ss_ram_config.sn_wr_queue)) != 0)
 580                 return (-1);
 581 
 582         gl = ss_ram_config.sn_gl_centry_info;
 583 
 584         wentry = ss_ram_config.sn_wr_cctl;
 585         for (i = 0; i < blocks; ++i, ++wentry) {
 586                 wentry->wc_gl_info = gl++;
 587                 ss_release_write(wentry, &(ss_ram_config.sn_wr_queue));
 588         }
 589 
 590         ss_ram_config.sn_wr_queue.wq_nentries = blocks;
 591 
 592         return (0);
 593 }
 594 
 595 static void
 596 ss_ram_wctl_deconfigure()
 597 {
 598         int blocks;
 599 
 600         _sdbc_writeq_deconfigure(&(ss_ram_config.sn_wr_queue));
 601 
 602         blocks = ss_ramcommon_config.ssc_wsize /
 603                         ss_ramcommon_config.ssc_client_psize;
 604 
 605         if (ss_ram_config.sn_wr_cctl) {
 606                 kmem_free(ss_ram_config.sn_wr_cctl,
 607                                 blocks * sizeof (ss_wr_cctl_t));
 608         }
 609 
 610         if (ss_ram_config.sn_gl_centry_info) {
 611                 kmem_free(ss_ram_config.sn_gl_centry_info,
 612                                 blocks * sizeof (ss_centry_info_impl_t));
 613         }
 614 }