linux/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c
<<
>>
Prefs
   1/* cyanblkdev_block.c - West Bridge Linux Block Driver source file
   2## ===========================
   3## Copyright (C) 2010  Cypress Semiconductor
   4##
   5## This program is free software; you can redistribute it and/or
   6## modify it under the terms of the GNU General Public License
   7## as published by the Free Software Foundation; either version 2
   8## of the License, or (at your option) any later version.
   9##
  10## This program is distributed in the hope that it will be useful,
  11## but WITHOUT ANY WARRANTY; without even the implied warranty of
  12## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13## GNU General Public License for more details.
  14##
  15## You should have received a copy of the GNU General Public License
  16## along with this program; if not, write to the Free Software
  17## Foundation, Inc., 51 Franklin Street, Fifth Floor
  18## Boston, MA  02110-1301, USA.
  19## ===========================
  20*/
  21
  22/*
  23 * Linux block driver implementation for Cypress West Bridge.
  24 * Based on the mmc block driver implementation by Andrew Christian
  25 * for the linux 2.6.26 kernel.
  26 * mmc_block.c, 5/28/2002
  27 */
  28
  29/*
  30 * Block driver for media (i.e., flash cards)
  31 *
  32 * Copyright 2002 Hewlett-Packard Company
  33 *
  34 * Use consistent with the GNU GPL is permitted,
  35 * provided that this copyright notice is
  36 * preserved in its entirety in all copies and derived works.
  37 *
  38 * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
  39 * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
  40 * FITNESS FOR ANY PARTICULAR PURPOSE.
  41 *
  42 * Many thanks to Alessandro Rubini and Jonathan Corbet!
  43 *
  44 * Author:  Andrew Christian
  45 *                28 May 2002
  46 */
  47
  48#include <linux/moduleparam.h>
  49#include <linux/module.h>
  50#include <linux/init.h>
  51#include <linux/slab.h>
  52#include <linux/sched.h>
  53#include <linux/kernel.h>
  54#include <linux/fs.h>
  55#include <linux/errno.h>
  56#include <linux/hdreg.h>
  57#include <linux/kdev_t.h>
  58#include <linux/blkdev.h>
  59
  60#include <asm/system.h>
  61#include <linux/uaccess.h>
  62
  63#include <linux/scatterlist.h>
  64#include <linux/time.h>
  65#include <linux/signal.h>
  66#include <linux/delay.h>
  67
  68#include "cyasblkdev_queue.h"
  69
  70#define CYASBLKDEV_SHIFT        0 /* Only a single partition. */
  71#define CYASBLKDEV_MAX_REQ_LEN  (256)
  72#define CYASBLKDEV_NUM_MINORS   (256 >> CYASBLKDEV_SHIFT)
  73#define CY_AS_TEST_NUM_BLOCKS   (64)
  74#define CYASBLKDEV_MINOR_0 1
  75#define CYASBLKDEV_MINOR_1 2
  76#define CYASBLKDEV_MINOR_2 3
  77
  78static int major;
  79module_param(major, int, 0444);
  80MODULE_PARM_DESC(major,
  81        "specify the major device number for cyasblkdev block driver");
  82
  83/* parameters passed from the user space */
  84static int vfat_search;
  85module_param(vfat_search, bool, S_IRUGO | S_IWUSR);
  86MODULE_PARM_DESC(vfat_search,
  87        "dynamically find the location of the first sector");
  88
  89static int private_partition_bus = -1;
  90module_param(private_partition_bus, int, S_IRUGO | S_IWUSR);
  91MODULE_PARM_DESC(private_partition_bus,
  92        "bus number for private partition");
  93
  94static int private_partition_size = -1;
  95module_param(private_partition_size, int, S_IRUGO | S_IWUSR);
  96MODULE_PARM_DESC(private_partition_size,
  97        "size of the private partition");
  98
  99/*
 100 * There is one cyasblkdev_blk_data per slot.
 101 */
 102struct cyasblkdev_blk_data {
 103        spinlock_t        lock;
 104        int media_count[2];
 105        const struct block_device_operations *blkops;
 106        unsigned int    usage;
 107        unsigned int    suspended;
 108
 109        /* handle to the west bridge device this handle, typdefed as *void  */
 110        cy_as_device_handle             dev_handle;
 111
 112        /* our custom structure, in addition to request queue,
 113         * adds lock & semaphore items*/
 114        struct cyasblkdev_queue queue;
 115
 116        /* 16 entries is enough given max request size
 117         * 16 * 4K (64 K per request)*/
 118        struct scatterlist        sg[16];
 119
 120        /* non-zero enables printk of executed reqests */
 121        unsigned int    dbgprn_flags;
 122
 123        /*gen_disk for private, system disk */
 124        struct gendisk  *system_disk;
 125        cy_as_media_type   system_disk_type;
 126        cy_bool                  system_disk_read_only;
 127        cy_bool                  system_disk_bus_num;
 128
 129        /* sector size for the medium */
 130        unsigned int    system_disk_blk_size;
 131        unsigned int    system_disk_first_sector;
 132        unsigned int    system_disk_unit_no;
 133
 134        /*gen_disk for bus 0 */
 135        struct gendisk  *user_disk_0;
 136        cy_as_media_type   user_disk_0_type;
 137        cy_bool                  user_disk_0_read_only;
 138        cy_bool                  user_disk_0_bus_num;
 139
 140        /* sector size for the medium */
 141        unsigned int    user_disk_0_blk_size;
 142        unsigned int    user_disk_0_first_sector;
 143        unsigned int    user_disk_0_unit_no;
 144
 145        /*gen_disk for bus 1 */
 146        struct gendisk  *user_disk_1;
 147        cy_as_media_type   user_disk_1_type;
 148        cy_bool                  user_disk_1_read_only;
 149        cy_bool                  user_disk_1_bus_num;
 150
 151        /* sector size for the medium */
 152        unsigned int    user_disk_1_blk_size;
 153        unsigned int    user_disk_1_first_sector;
 154        unsigned int    user_disk_1_unit_no;
 155};
 156
 157/* pointer to west bridge block data device superstructure */
 158static struct cyasblkdev_blk_data *gl_bd;
 159
 160static DEFINE_SEMAPHORE(open_lock);
 161
 162/* local forwardd declarationss  */
 163static cy_as_device_handle *cyas_dev_handle;
 164static void cyasblkdev_blk_deinit(struct cyasblkdev_blk_data *bd);
 165
 166/*change debug print options */
 167 #define DBGPRN_RD_RQ      (1 < 0)
 168 #define DBGPRN_WR_RQ           (1 < 1)
 169 #define DBGPRN_RQ_END    (1 < 2)
 170
 171int blkdev_ctl_dbgprn(
 172                                                int prn_flags
 173                                                )
 174{
 175        int cur_options = gl_bd->dbgprn_flags;
 176
 177        DBGPRN_FUNC_NAME;
 178
 179        /* set new debug print options */
 180        gl_bd->dbgprn_flags = prn_flags;
 181
 182        /* return previous */
 183        return cur_options;
 184}
 185EXPORT_SYMBOL(blkdev_ctl_dbgprn);
 186
 187static struct cyasblkdev_blk_data *cyasblkdev_blk_get(
 188                                                        struct gendisk *disk
 189                                                        )
 190{
 191        struct cyasblkdev_blk_data *bd;
 192
 193        DBGPRN_FUNC_NAME;
 194
 195        down(&open_lock);
 196
 197        bd = disk->private_data;
 198
 199        if (bd && (bd->usage == 0))
 200                bd = NULL;
 201
 202        if (bd) {
 203                bd->usage++;
 204                #ifndef NBDEBUG
 205                cy_as_hal_print_message(
 206                        "cyasblkdev_blk_get: usage = %d\n", bd->usage);
 207                #endif
 208        }
 209        up(&open_lock);
 210
 211        return bd;
 212}
 213
 214static void cyasblkdev_blk_put(
 215                        struct cyasblkdev_blk_data *bd
 216                        )
 217{
 218        DBGPRN_FUNC_NAME;
 219
 220        down(&open_lock);
 221
 222        if (bd) {
 223                bd->usage--;
 224                #ifndef WESTBRIDGE_NDEBUG
 225                cy_as_hal_print_message(
 226                        " cyasblkdev_blk_put , bd->usage= %d\n", bd->usage);
 227                #endif
 228        } else  {
 229                #ifndef WESTBRIDGE_NDEBUG
 230                cy_as_hal_print_message(
 231                        "cyasblkdev: blk_put(bd) on bd = NULL!: usage = %d\n",
 232                        bd->usage);
 233                #endif
 234                up(&open_lock);
 235                return;
 236        }
 237
 238        if (bd->usage == 0) {
 239                put_disk(bd->user_disk_0);
 240                put_disk(bd->user_disk_1);
 241                put_disk(bd->system_disk);
 242                cyasblkdev_cleanup_queue(&bd->queue);
 243
 244                if (CY_AS_ERROR_SUCCESS !=
 245                        cy_as_storage_release(bd->dev_handle, 0, 0, 0, 0)) {
 246                        #ifndef WESTBRIDGE_NDEBUG
 247                        cy_as_hal_print_message(
 248                                "cyasblkdev: cannot release bus 0\n");
 249                        #endif
 250                }
 251
 252                if (CY_AS_ERROR_SUCCESS !=
 253                        cy_as_storage_release(bd->dev_handle, 1, 0, 0, 0)) {
 254                        #ifndef WESTBRIDGE_NDEBUG
 255                        cy_as_hal_print_message(
 256                                "cyasblkdev: cannot release bus 1\n");
 257                        #endif
 258                }
 259
 260                if (CY_AS_ERROR_SUCCESS !=
 261                        cy_as_storage_stop(bd->dev_handle, 0, 0)) {
 262                        #ifndef WESTBRIDGE_NDEBUG
 263                        cy_as_hal_print_message(
 264                                "cyasblkdev: cannot stop storage stack\n");
 265                        #endif
 266                }
 267
 268        #ifdef __CY_ASTORIA_SCM_KERNEL_HAL__
 269                /* If the SCM Kernel HAL is being used, disable the use
 270                 * of scatter/gather lists at the end of block driver usage.
 271                 */
 272                cy_as_hal_disable_scatter_list(cyasdevice_gethaltag());
 273        #endif
 274
 275                /*ptr to global struct cyasblkdev_blk_data */
 276                gl_bd = NULL;
 277                kfree(bd);
 278        }
 279
 280        #ifndef WESTBRIDGE_NDEBUG
 281        cy_as_hal_print_message(
 282                "cyasblkdev (blk_put): usage = %d\n",
 283                bd->usage);
 284        #endif
 285        up(&open_lock);
 286}
 287
 288static int cyasblkdev_blk_open(
 289                                        struct block_device *bdev,
 290                                        fmode_t mode
 291                                        )
 292{
 293        struct cyasblkdev_blk_data *bd = cyasblkdev_blk_get(bdev->bd_disk);
 294        int ret = -ENXIO;
 295
 296        DBGPRN_FUNC_NAME;
 297
 298        if (bd) {
 299                if (bd->usage == 2)
 300                        check_disk_change(bdev);
 301
 302                ret = 0;
 303
 304                if (bdev->bd_disk == bd->user_disk_0) {
 305                        if ((mode & FMODE_WRITE) && bd->user_disk_0_read_only) {
 306                                #ifndef WESTBRIDGE_NDEBUG
 307                                cy_as_hal_print_message(
 308                                        "device marked as readonly "
 309                                        "and write requested\n");
 310                                #endif
 311
 312                                cyasblkdev_blk_put(bd);
 313                                ret = -EROFS;
 314                        }
 315                } else if (bdev->bd_disk == bd->user_disk_1) {
 316                        if ((mode & FMODE_WRITE) && bd->user_disk_1_read_only) {
 317                                #ifndef WESTBRIDGE_NDEBUG
 318                                cy_as_hal_print_message(
 319                                        "device marked as readonly "
 320                                        "and write requested\n");
 321                                #endif
 322
 323                                cyasblkdev_blk_put(bd);
 324                                ret = -EROFS;
 325                        }
 326                } else if (bdev->bd_disk == bd->system_disk) {
 327                        if ((mode & FMODE_WRITE) && bd->system_disk_read_only) {
 328                                #ifndef WESTBRIDGE_NDEBUG
 329                                cy_as_hal_print_message(
 330                                        "device marked as readonly "
 331                                        "and write requested\n");
 332                                #endif
 333
 334                                cyasblkdev_blk_put(bd);
 335                                ret = -EROFS;
 336                        }
 337                }
 338        }
 339
 340        return ret;
 341}
 342
 343static int cyasblkdev_blk_release(
 344                                        struct gendisk *disk,
 345                                        fmode_t mode
 346                                        )
 347{
 348        struct cyasblkdev_blk_data *bd = disk->private_data;
 349
 350        DBGPRN_FUNC_NAME;
 351
 352        cyasblkdev_blk_put(bd);
 353        return 0;
 354}
 355
 356static int cyasblkdev_blk_ioctl(
 357                        struct block_device *bdev,
 358                        fmode_t mode,
 359                        unsigned int cmd,
 360                        unsigned long arg
 361                        )
 362{
 363        DBGPRN_FUNC_NAME;
 364
 365        if (cmd == HDIO_GETGEO) {
 366                /*for now  we only process geometry IOCTL*/
 367                struct hd_geometry geo;
 368
 369                memset(&geo, 0, sizeof(struct hd_geometry));
 370
 371                geo.cylinders   = get_capacity(bdev->bd_disk) / (4 * 16);
 372                geo.heads       = 4;
 373                geo.sectors     = 16;
 374                geo.start       = get_start_sect(bdev);
 375
 376                /* copy to user space */
 377                return copy_to_user((void __user *)arg, &geo, sizeof(geo))
 378                        ? -EFAULT : 0;
 379        }
 380
 381        return -ENOTTY;
 382}
 383
 384/* Media_changed block_device opp
 385 * this one is called by kernel to confirm if the media really changed
 386 * as we indicated by issuing check_disk_change() call */
 387int cyasblkdev_media_changed(struct gendisk *gd)
 388{
 389        struct cyasblkdev_blk_data *bd;
 390
 391        #ifndef WESTBRIDGE_NDEBUG
 392        cy_as_hal_print_message("cyasblkdev_media_changed() is called\n");
 393        #endif
 394
 395        if (gd)
 396                bd = gd->private_data;
 397        else {
 398                #ifndef WESTBRIDGE_NDEBUG
 399                cy_as_hal_print_message(
 400                        "cyasblkdev_media_changed() is called, "
 401                        "but gd is null\n");
 402                #endif
 403        }
 404
 405        /* return media change state "1" yes, 0 no */
 406        return 0;
 407}
 408
 409/*  this one called by kernel to give us a chence
 410 * to prep the new media before it starts to rescaning
 411 * of the newlly inserted SD media */
 412int cyasblkdev_revalidate_disk(struct gendisk *gd)
 413{
 414        /*int (*revalidate_disk) (struct gendisk *); */
 415
 416        #ifndef WESTBRIDGE_NDEBUG
 417        if (gd)
 418                cy_as_hal_print_message(
 419                        "cyasblkdev_revalidate_disk() is called, "
 420                        "(gl_bd->usage:%d)\n", gl_bd->usage);
 421        #endif
 422
 423        /* 0 means ok, kern can go ahead with partition rescan */
 424        return 0;
 425}
 426
 427
 428/*standard block device driver interface */
 429static struct block_device_operations cyasblkdev_bdops = {
 430        .open                   = cyasblkdev_blk_open,
 431        .release                = cyasblkdev_blk_release,
 432        .ioctl                  = cyasblkdev_blk_ioctl,
 433        /* .getgeo              = cyasblkdev_blk_getgeo, */
 434        /* added to support media removal( real and simulated) media */
 435        .media_changed  = cyasblkdev_media_changed,
 436        /* added to support media removal( real and simulated) media */
 437        .revalidate_disk = cyasblkdev_revalidate_disk,
 438        .owner                  = THIS_MODULE,
 439};
 440
 441/* west bridge block device prep request function */
 442static int cyasblkdev_blk_prep_rq(
 443                                        struct cyasblkdev_queue *bq,
 444                                        struct request *req
 445                                        )
 446{
 447        struct cyasblkdev_blk_data *bd = bq->data;
 448        int stat = BLKPREP_OK;
 449
 450        DBGPRN_FUNC_NAME;
 451
 452        /* If we have no device, we haven't finished initialising. */
 453        if (!bd || !bd->dev_handle) {
 454                #ifndef WESTBRIDGE_NDEBUG
 455                cy_as_hal_print_message(KERN_ERR
 456                        "cyasblkdev %s: killing request - no device/host\n",
 457                        req->rq_disk->disk_name);
 458                #endif
 459                stat = BLKPREP_KILL;
 460        }
 461
 462        if (bd->suspended) {
 463                blk_plug_device(bd->queue.queue);
 464                stat = BLKPREP_DEFER;
 465        }
 466
 467        /* Check for excessive requests.*/
 468        if (blk_rq_pos(req) + blk_rq_sectors(req) > get_capacity(req->rq_disk)) {
 469                cy_as_hal_print_message("cyasblkdev: bad request address\n");
 470                stat = BLKPREP_KILL;
 471        }
 472
 473        return stat;
 474}
 475
 476/*west bridge storage async api on_completed callback */
 477static void cyasblkdev_issuecallback(
 478        /* Handle to the device completing the storage operation */
 479        cy_as_device_handle handle,
 480        /* The media type completing the operation */
 481        cy_as_media_type type,
 482        /* The device completing the operation */
 483        uint32_t device,
 484        /* The unit completing the operation */
 485        uint32_t unit,
 486        /* The block number of the completed operation */
 487        uint32_t block_number,
 488        /* The type of operation */
 489        cy_as_oper_type op,
 490        /* The error status */
 491        cy_as_return_status_t status
 492        )
 493{
 494        int retry_cnt = 0;
 495        DBGPRN_FUNC_NAME;
 496
 497        if (status != CY_AS_ERROR_SUCCESS) {
 498                #ifndef WESTBRIDGE_NDEBUG
 499                cy_as_hal_print_message(
 500                  "%s: async r/w: op:%d failed with error %d at address %d\n",
 501                        __func__, op, status, block_number);
 502                #endif
 503        }
 504
 505        #ifndef WESTBRIDGE_NDEBUG
 506        cy_as_hal_print_message(
 507                "%s calling blk_end_request from issue_callback "
 508                "req=0x%x, status=0x%x, nr_sectors=0x%x\n",
 509                __func__, (unsigned int) gl_bd->queue.req, status,
 510                (unsigned int) blk_rq_sectors(gl_bd->queue.req));
 511        #endif
 512
 513        /* note: blk_end_request w/o __ prefix should
 514         * not require spinlocks on the queue*/
 515        while (blk_end_request(gl_bd->queue.req,
 516        status, blk_rq_sectors(gl_bd->queue.req)*512)) {
 517                retry_cnt++;
 518        };
 519
 520        #ifndef WESTBRIDGE_NDEBUG
 521        cy_as_hal_print_message(
 522                "%s blkdev_callback: ended rq on %d sectors, "
 523                "with err:%d, n:%d times\n", __func__,
 524                (int)blk_rq_sectors(gl_bd->queue.req), status,
 525                retry_cnt
 526        );
 527        #endif
 528
 529        spin_lock_irq(&gl_bd->lock);
 530
 531        /*elevate next request, if there is one*/
 532        if (!blk_queue_plugged(gl_bd->queue.queue)) {
 533                /* queue is not plugged */
 534                gl_bd->queue.req = blk_fetch_request(gl_bd->queue.queue);
 535                #ifndef WESTBRIDGE_NDEBUG
 536                cy_as_hal_print_message("%s blkdev_callback: "
 537                "blk_fetch_request():%p\n",
 538                        __func__, gl_bd->queue.req);
 539                #endif
 540        }
 541
 542        if (gl_bd->queue.req) {
 543                spin_unlock_irq(&gl_bd->lock);
 544
 545                #ifndef WESTBRIDGE_NDEBUG
 546                cy_as_hal_print_message("%s blkdev_callback: about to "
 547                "call issue_fn:%p\n", __func__, gl_bd->queue.req);
 548                #endif
 549
 550                gl_bd->queue.issue_fn(&gl_bd->queue, gl_bd->queue.req);
 551        } else {
 552                spin_unlock_irq(&gl_bd->lock);
 553        }
 554}
 555
 556/* issue astoria blkdev request (issue_fn) */
 557static int cyasblkdev_blk_issue_rq(
 558                                        struct cyasblkdev_queue *bq,
 559                                        struct request *req
 560                                        )
 561{
 562        struct cyasblkdev_blk_data *bd = bq->data;
 563        int index = 0;
 564        int ret = CY_AS_ERROR_SUCCESS;
 565        uint32_t req_sector = 0;
 566        uint32_t req_nr_sectors = 0;
 567        int bus_num = 0;
 568        int lcl_unit_no = 0;
 569
 570        DBGPRN_FUNC_NAME;
 571
 572        /*
 573         * will construct a scatterlist for the given request;
 574         * the return value is the number of actually used
 575         * entries in the resulting list. Then, this scatterlist
 576         * can be used for the actual DMA prep operation.
 577         */
 578        spin_lock_irq(&bd->lock);
 579        index = blk_rq_map_sg(bq->queue, req, bd->sg);
 580
 581        if (req->rq_disk == bd->user_disk_0) {
 582                bus_num = bd->user_disk_0_bus_num;
 583                req_sector = blk_rq_pos(req) + gl_bd->user_disk_0_first_sector;
 584                req_nr_sectors = blk_rq_sectors(req);
 585                lcl_unit_no = gl_bd->user_disk_0_unit_no;
 586
 587                #ifndef WESTBRIDGE_NDEBUG
 588                cy_as_hal_print_message("%s: request made to disk 0 "
 589                        "for sector=%d, num_sectors=%d, unit_no=%d\n",
 590                        __func__, req_sector, (int) blk_rq_sectors(req),
 591                        lcl_unit_no);
 592                #endif
 593        } else if (req->rq_disk == bd->user_disk_1) {
 594                bus_num = bd->user_disk_1_bus_num;
 595                req_sector = blk_rq_pos(req) + gl_bd->user_disk_1_first_sector;
 596                /*SECT_NUM_TRANSLATE(blk_rq_sectors(req));*/
 597                req_nr_sectors = blk_rq_sectors(req);
 598                lcl_unit_no = gl_bd->user_disk_1_unit_no;
 599
 600                #ifndef WESTBRIDGE_NDEBUG
 601                cy_as_hal_print_message("%s: request made to disk 1 for "
 602                        "sector=%d, num_sectors=%d, unit_no=%d\n", __func__,
 603                        req_sector, (int) blk_rq_sectors(req), lcl_unit_no);
 604                #endif
 605        } else if (req->rq_disk == bd->system_disk) {
 606                bus_num = bd->system_disk_bus_num;
 607                req_sector = blk_rq_pos(req) + gl_bd->system_disk_first_sector;
 608                req_nr_sectors = blk_rq_sectors(req);
 609                lcl_unit_no = gl_bd->system_disk_unit_no;
 610
 611                #ifndef WESTBRIDGE_NDEBUG
 612                cy_as_hal_print_message("%s: request made to system disk "
 613                        "for sector=%d, num_sectors=%d, unit_no=%d\n", __func__,
 614                        req_sector, (int) blk_rq_sectors(req), lcl_unit_no);
 615                #endif
 616        }
 617        #ifndef WESTBRIDGE_NDEBUG
 618        else {
 619                cy_as_hal_print_message(
 620                        "%s: invalid disk used for request\n", __func__);
 621        }
 622        #endif
 623
 624        spin_unlock_irq(&bd->lock);
 625
 626        if (rq_data_dir(req) == READ) {
 627                #ifndef WESTBRIDGE_NDEBUG
 628                cy_as_hal_print_message("%s: calling readasync() "
 629                        "req_sector=0x%x, req_nr_sectors=0x%x, bd->sg:%x\n\n",
 630                        __func__, req_sector, req_nr_sectors, (uint32_t)bd->sg);
 631                #endif
 632
 633                ret = cy_as_storage_read_async(bd->dev_handle, bus_num, 0,
 634                        lcl_unit_no, req_sector, bd->sg, req_nr_sectors,
 635                        (cy_as_storage_callback)cyasblkdev_issuecallback);
 636
 637                if (ret != CY_AS_ERROR_SUCCESS) {
 638                        #ifndef WESTBRIDGE_NDEBUG
 639                        cy_as_hal_print_message("%s:readasync() error %d at "
 640                                "address %ld, unit no %d\n", __func__, ret,
 641                                blk_rq_pos(req), lcl_unit_no);
 642                        cy_as_hal_print_message("%s:ending i/o request "
 643                                "on reg:%x\n", __func__, (uint32_t)req);
 644                        #endif
 645
 646                        while (blk_end_request(req,
 647                                (ret == CY_AS_ERROR_SUCCESS),
 648                                req_nr_sectors*512))
 649                                ;
 650
 651                        bq->req = NULL;
 652                }
 653        } else {
 654                ret = cy_as_storage_write_async(bd->dev_handle, bus_num, 0,
 655                        lcl_unit_no, req_sector, bd->sg, req_nr_sectors,
 656                        (cy_as_storage_callback)cyasblkdev_issuecallback);
 657
 658                if (ret != CY_AS_ERROR_SUCCESS) {
 659                        #ifndef WESTBRIDGE_NDEBUG
 660                        cy_as_hal_print_message("%s: write failed with "
 661                        "error %d at address %ld, unit no %d\n",
 662                        __func__, ret, blk_rq_pos(req), lcl_unit_no);
 663                        #endif
 664
 665                        /*end IO op on this request(does both
 666                         * end_that_request_... _first & _last) */
 667                        while (blk_end_request(req,
 668                                (ret == CY_AS_ERROR_SUCCESS),
 669                                req_nr_sectors*512))
 670                                ;
 671
 672                        bq->req = NULL;
 673                }
 674        }
 675
 676        return ret;
 677}
 678
 679static unsigned long
 680dev_use[CYASBLKDEV_NUM_MINORS / (8 * sizeof(unsigned long))];
 681
 682
 683/* storage event callback (note: called in astoria isr context) */
 684static void cyasblkdev_storage_callback(
 685                                        cy_as_device_handle dev_h,
 686                                        cy_as_bus_number_t bus,
 687                                        uint32_t device,
 688                                        cy_as_storage_event evtype,
 689                                        void *evdata
 690                                        )
 691{
 692        #ifndef WESTBRIDGE_NDEBUG
 693        cy_as_hal_print_message("%s: bus:%d, device:%d, evtype:%d, "
 694        "evdata:%p\n ", __func__, bus, device, evtype, evdata);
 695        #endif
 696
 697        switch (evtype) {
 698        case cy_as_storage_processor:
 699                break;
 700
 701        case cy_as_storage_removed:
 702                break;
 703
 704        case cy_as_storage_inserted:
 705                break;
 706
 707        default:
 708                break;
 709        }
 710}
 711
 712#define SECTORS_TO_SCAN 4096
 713
 714uint32_t cyasblkdev_get_vfat_offset(int bus_num, int unit_no)
 715{
 716        /*
 717         * for sd media, vfat partition boot record is not always
 718         * located at sector it greatly depends on the system and
 719         * software that was used to format the sd however, linux
 720         * fs layer always expects it at sector 0, this function
 721         * finds the offset and then uses it in all media r/w
 722         * operations
 723         */
 724        int sect_no, stat;
 725        uint8_t *sect_buf;
 726        bool br_found = false;
 727
 728        DBGPRN_FUNC_NAME;
 729
 730        sect_buf = kmalloc(1024, GFP_KERNEL);
 731
 732        /* since HAL layer always uses sg lists instead of the
 733         * buffer (for hw dmas) we need to initialize the sg list
 734         * for local buffer*/
 735        sg_init_one(gl_bd->sg, sect_buf, 512);
 736
 737        /*
 738        * Check MPR partition table 1st, then try to scan through
 739        * 1st 384 sectors until BR signature(intel JMP istruction
 740        * code and ,0x55AA) is found
 741        */
 742        #ifndef WESTBRIDGE_NDEBUG
 743          cy_as_hal_print_message(
 744                "%s scanning media for vfat partition...\n", __func__);
 745        #endif
 746
 747        for (sect_no = 0; sect_no < SECTORS_TO_SCAN; sect_no++) {
 748                #ifndef WESTBRIDGE_NDEBUG
 749                cy_as_hal_print_message("%s before cyasstorageread "
 750                        "gl_bd->sg addr=0x%x\n", __func__,
 751                        (unsigned int) gl_bd->sg);
 752                #endif
 753
 754                stat = cy_as_storage_read(
 755                        /* Handle to the device of interest */
 756                        gl_bd->dev_handle,
 757                        /* The bus to access */
 758                        bus_num,
 759                        /* The device to access */
 760                        0,
 761                        /* The unit to access */
 762                        unit_no,
 763                        /* absolute sector number */
 764                        sect_no,
 765                        /* sg structure */
 766                        gl_bd->sg,
 767                        /* The number of blocks to be read */
 768                        1
 769                );
 770
 771                /* try only sectors with boot signature */
 772                if ((sect_buf[510] == 0x55) && (sect_buf[511] == 0xaa)) {
 773                        /* vfat boot record may also be located at
 774                         * sector 0, check it first  */
 775                        if (sect_buf[0] == 0xEB) {
 776                                #ifndef WESTBRIDGE_NDEBUG
 777                                cy_as_hal_print_message(
 778                                        "%s vfat partition found "
 779                                        "at sector:%d\n",
 780                                        __func__, sect_no);
 781                                #endif
 782
 783                                br_found = true;
 784                                   break;
 785                        }
 786                }
 787
 788                if (stat != 0) {
 789                        #ifndef WESTBRIDGE_NDEBUG
 790                        cy_as_hal_print_message("%s sector scan error\n",
 791                                __func__);
 792                        #endif
 793                        break;
 794                }
 795        }
 796
 797        kfree(sect_buf);
 798
 799        if (br_found) {
 800                return sect_no;
 801        } else {
 802                #ifndef WESTBRIDGE_NDEBUG
 803                cy_as_hal_print_message(
 804                        "%s vfat partition is not found, using 0 offset\n",
 805                        __func__);
 806                #endif
 807                return 0;
 808        }
 809}
 810
 811cy_as_storage_query_device_data dev_data = {0};
 812
 813static int cyasblkdev_add_disks(int bus_num,
 814        struct cyasblkdev_blk_data *bd,
 815        int total_media_count,
 816        int devidx)
 817{
 818        int ret = 0;
 819        uint64_t disk_cap;
 820        int lcl_unit_no;
 821        cy_as_storage_query_unit_data unit_data = {0};
 822
 823        #ifndef WESTBRIDGE_NDEBUG
 824                cy_as_hal_print_message("%s:query device: "
 825                "type:%d, removable:%d, writable:%d, "
 826                "blksize %d, units:%d, locked:%d, "
 827                "erase_sz:%d\n",
 828                __func__,
 829                dev_data.desc_p.type,
 830                dev_data.desc_p.removable,
 831                dev_data.desc_p.writeable,
 832                dev_data.desc_p.block_size,
 833                dev_data.desc_p.number_units,
 834                dev_data.desc_p.locked,
 835                dev_data.desc_p.erase_unit_size
 836                );
 837        #endif
 838
 839        /*  make sure that device is not locked  */
 840        if (dev_data.desc_p.locked) {
 841                #ifndef WESTBRIDGE_NDEBUG
 842                cy_as_hal_print_message(
 843                        "%s: device is locked\n", __func__);
 844                #endif
 845                ret = cy_as_storage_release(
 846                        bd->dev_handle, bus_num, 0, 0, 0);
 847                if (ret != CY_AS_ERROR_SUCCESS) {
 848                        #ifndef WESTBRIDGE_NDEBUG
 849                        cy_as_hal_print_message("%s cannot release"
 850                                " storage\n", __func__);
 851                        #endif
 852                        goto out;
 853                }
 854                goto out;
 855        }
 856
 857        unit_data.device = 0;
 858        unit_data.unit   = 0;
 859        unit_data.bus    = bus_num;
 860        ret = cy_as_storage_query_unit(bd->dev_handle,
 861                &unit_data, 0, 0);
 862        if (ret != CY_AS_ERROR_SUCCESS) {
 863                #ifndef WESTBRIDGE_NDEBUG
 864                cy_as_hal_print_message("%s: cannot query "
 865                        "%d device unit - reason code %d\n",
 866                        __func__, bus_num, ret);
 867                #endif
 868                goto out;
 869        }
 870
 871        if (private_partition_bus == bus_num) {
 872                if (private_partition_size > 0) {
 873                        ret = cy_as_storage_create_p_partition(
 874                                bd->dev_handle, bus_num, 0,
 875                                private_partition_size, 0, 0);
 876                        if ((ret != CY_AS_ERROR_SUCCESS) &&
 877                        (ret != CY_AS_ERROR_ALREADY_PARTITIONED)) {
 878                        #ifndef WESTBRIDGE_NDEBUG
 879                                cy_as_hal_print_message("%s: cy_as_storage_"
 880                                "create_p_partition after size > 0 check "
 881                                "failed with error code %d\n",
 882                                __func__, ret);
 883                        #endif
 884
 885                                disk_cap = (uint64_t)
 886                                        (unit_data.desc_p.unit_size);
 887                                lcl_unit_no = 0;
 888
 889                        } else if (ret == CY_AS_ERROR_ALREADY_PARTITIONED) {
 890                                #ifndef WESTBRIDGE_NDEBUG
 891                                cy_as_hal_print_message(
 892                                "%s: cy_as_storage_create_p_partition "
 893                                "indicates memory already partitioned\n",
 894                                __func__);
 895                                #endif
 896
 897                                /*check to see that partition
 898                                 * matches size */
 899                                if (unit_data.desc_p.unit_size !=
 900                                        private_partition_size) {
 901                                        ret = cy_as_storage_remove_p_partition(
 902                                                bd->dev_handle,
 903                                                bus_num, 0, 0, 0);
 904                                        if (ret == CY_AS_ERROR_SUCCESS) {
 905                                                ret = cy_as_storage_create_p_partition(
 906                                                        bd->dev_handle, bus_num, 0,
 907                                                        private_partition_size, 0, 0);
 908                                                if (ret == CY_AS_ERROR_SUCCESS) {
 909                                                        unit_data.bus = bus_num;
 910                                                        unit_data.device = 0;
 911                                                        unit_data.unit = 1;
 912                                                } else {
 913                                                        #ifndef WESTBRIDGE_NDEBUG
 914                                                        cy_as_hal_print_message(
 915                                                        "%s: cy_as_storage_create_p_partition "
 916                                                        "after removal unexpectedly failed "
 917                                                        "with error %d\n", __func__, ret);
 918                                                        #endif
 919
 920                                                        /* need to requery bus
 921                                                         * seeing as delete
 922                                                         * successful and create
 923                                                         * failed we have changed
 924                                                         * the disk properties */
 925                                                        unit_data.bus   = bus_num;
 926                                                        unit_data.device = 0;
 927                                                        unit_data.unit   = 0;
 928                                                }
 929
 930                                                ret = cy_as_storage_query_unit(
 931                                                bd->dev_handle,
 932                                                &unit_data, 0, 0);
 933                                                if (ret != CY_AS_ERROR_SUCCESS) {
 934                                                        #ifndef WESTBRIDGE_NDEBUG
 935                                                        cy_as_hal_print_message(
 936                                                        "%s: cannot query %d "
 937                                                        "device unit - reason code %d\n",
 938                                                        __func__, bus_num, ret);
 939                                                        #endif
 940                                                        goto out;
 941                                                } else {
 942                                                        disk_cap = (uint64_t)
 943                                                                (unit_data.desc_p.unit_size);
 944                                                        lcl_unit_no =
 945                                                                unit_data.unit;
 946                                                }
 947                                        } else {
 948                                        #ifndef WESTBRIDGE_NDEBUG
 949                                        cy_as_hal_print_message(
 950                                        "%s: cy_as_storage_remove_p_partition "
 951                                        "failed with error %d\n",
 952                                        __func__, ret);
 953                                        #endif
 954
 955                                                unit_data.bus = bus_num;
 956                                                unit_data.device = 0;
 957                                                unit_data.unit = 1;
 958
 959                                                ret = cy_as_storage_query_unit(
 960                                                        bd->dev_handle, &unit_data, 0, 0);
 961                                                if (ret != CY_AS_ERROR_SUCCESS) {
 962                                                #ifndef WESTBRIDGE_NDEBUG
 963                                                        cy_as_hal_print_message(
 964                                                        "%s: cannot query %d "
 965                                                        "device unit - reason "
 966                                                        "code %d\n", __func__,
 967                                                        bus_num, ret);
 968                                                #endif
 969                                                        goto out;
 970                                                }
 971
 972                                                disk_cap = (uint64_t)
 973                                                        (unit_data.desc_p.unit_size);
 974                                                lcl_unit_no =
 975                                                        unit_data.unit;
 976                                        }
 977                                } else {
 978                                        #ifndef WESTBRIDGE_NDEBUG
 979                                        cy_as_hal_print_message("%s: partition "
 980                                                "exists and sizes equal\n",
 981                                                __func__);
 982                                        #endif
 983
 984                                        /*partition already existed,
 985                                         * need to query second unit*/
 986                                        unit_data.bus = bus_num;
 987                                        unit_data.device = 0;
 988                                        unit_data.unit = 1;
 989
 990                                        ret = cy_as_storage_query_unit(
 991                                                bd->dev_handle, &unit_data, 0, 0);
 992                                        if (ret != CY_AS_ERROR_SUCCESS) {
 993                                        #ifndef WESTBRIDGE_NDEBUG
 994                                                cy_as_hal_print_message(
 995                                                        "%s: cannot query %d "
 996                                                        "device unit "
 997                                                        "- reason code %d\n",
 998                                                        __func__, bus_num, ret);
 999                                        #endif
1000                                                goto out;
1001                                        } else {
1002                                                disk_cap = (uint64_t)
1003                                                (unit_data.desc_p.unit_size);
1004                                                lcl_unit_no = unit_data.unit;
1005                                        }
1006                                }
1007                        } else {
1008                                #ifndef WESTBRIDGE_NDEBUG
1009                                cy_as_hal_print_message(
1010                                "%s: cy_as_storage_create_p_partition "
1011                                "created successfully\n", __func__);
1012                                #endif
1013
1014                                disk_cap = (uint64_t)
1015                                (unit_data.desc_p.unit_size -
1016                                private_partition_size);
1017
1018                                lcl_unit_no = 1;
1019                        }
1020                }
1021                #ifndef WESTBRIDGE_NDEBUG
1022                else {
1023                        cy_as_hal_print_message(
1024                        "%s: invalid partition_size%d\n", __func__,
1025                        private_partition_size);
1026
1027                        disk_cap = (uint64_t)
1028                                (unit_data.desc_p.unit_size);
1029                        lcl_unit_no = 0;
1030                }
1031                #endif
1032        } else {
1033                disk_cap = (uint64_t)
1034                        (unit_data.desc_p.unit_size);
1035                lcl_unit_no = 0;
1036        }
1037
1038        if ((bus_num == 0) ||
1039                (total_media_count == 1)) {
1040                sprintf(bd->user_disk_0->disk_name,
1041                        "cyasblkdevblk%d", devidx);
1042
1043                #ifndef WESTBRIDGE_NDEBUG
1044                cy_as_hal_print_message(
1045                        "%s: disk unit_sz:%lu blk_sz:%d, "
1046                        "start_blk:%lu, capacity:%llu\n",
1047                        __func__, (unsigned long)
1048                        unit_data.desc_p.unit_size,
1049                        unit_data.desc_p.block_size,
1050                        (unsigned long)
1051                        unit_data.desc_p.start_block,
1052                        (uint64_t)disk_cap
1053                );
1054                #endif
1055
1056                #ifndef WESTBRIDGE_NDEBUG
1057                cy_as_hal_print_message("%s: setting gendisk disk "
1058                        "capacity to %d\n", __func__, (int) disk_cap);
1059                #endif
1060
1061                /* initializing bd->queue */
1062                #ifndef WESTBRIDGE_NDEBUG
1063                cy_as_hal_print_message("%s: init bd->queue\n",
1064                        __func__);
1065                #endif
1066
1067                /* this will create a
1068                 * queue kernel thread */
1069                cyasblkdev_init_queue(
1070                        &bd->queue, &bd->lock);
1071
1072                bd->queue.prep_fn = cyasblkdev_blk_prep_rq;
1073                bd->queue.issue_fn = cyasblkdev_blk_issue_rq;
1074                bd->queue.data = bd;
1075
1076                /*blk_size should always
1077                 * be a multiple of 512,
1078                 * set to the max to ensure
1079                 * that all accesses aligned
1080                 * to the greatest multiple,
1081                 * can adjust request to
1082                 * smaller block sizes
1083                 * dynamically*/
1084
1085                bd->user_disk_0_read_only = !dev_data.desc_p.writeable;
1086                bd->user_disk_0_blk_size = dev_data.desc_p.block_size;
1087                bd->user_disk_0_type = dev_data.desc_p.type;
1088                bd->user_disk_0_bus_num = bus_num;
1089                bd->user_disk_0->major = major;
1090                bd->user_disk_0->first_minor = devidx << CYASBLKDEV_SHIFT;
1091                bd->user_disk_0->minors = 8;
1092                bd->user_disk_0->fops = &cyasblkdev_bdops;
1093                bd->user_disk_0->private_data = bd;
1094                bd->user_disk_0->queue = bd->queue.queue;
1095                bd->dbgprn_flags = DBGPRN_RD_RQ;
1096                bd->user_disk_0_unit_no = lcl_unit_no;
1097
1098                blk_queue_logical_block_size(bd->queue.queue,
1099                        bd->user_disk_0_blk_size);
1100
1101                set_capacity(bd->user_disk_0,
1102                        disk_cap);
1103
1104                #ifndef WESTBRIDGE_NDEBUG
1105                cy_as_hal_print_message(
1106                        "%s: returned from set_capacity %d\n",
1107                        __func__, (int) disk_cap);
1108                #endif
1109
1110                /* need to start search from
1111                 * public partition beginning */
1112                if (vfat_search) {
1113                        bd->user_disk_0_first_sector =
1114                                cyasblkdev_get_vfat_offset(
1115                                        bd->user_disk_0_bus_num,
1116                                        bd->user_disk_0_unit_no);
1117                } else {
1118                        bd->user_disk_0_first_sector = 0;
1119                }
1120
1121                #ifndef WESTBRIDGE_NDEBUG
1122                cy_as_hal_print_message(
1123                        "%s: set user_disk_0_first "
1124                        "sector to %d\n", __func__,
1125                         bd->user_disk_0_first_sector);
1126                cy_as_hal_print_message(
1127                        "%s: add_disk: disk->major=0x%x\n",
1128                        __func__,
1129                        bd->user_disk_0->major);
1130                cy_as_hal_print_message(
1131                        "%s: add_disk: "
1132                        "disk->first_minor=0x%x\n", __func__,
1133                        bd->user_disk_0->first_minor);
1134                cy_as_hal_print_message(
1135                        "%s: add_disk: "
1136                        "disk->minors=0x%x\n", __func__,
1137                        bd->user_disk_0->minors);
1138                cy_as_hal_print_message(
1139                        "%s: add_disk: "
1140                        "disk->disk_name=%s\n",
1141                        __func__,
1142                        bd->user_disk_0->disk_name);
1143                cy_as_hal_print_message(
1144                        "%s: add_disk: "
1145                        "disk->part_tbl=0x%x\n", __func__,
1146                        (unsigned int)
1147                        bd->user_disk_0->part_tbl);
1148                cy_as_hal_print_message(
1149                        "%s: add_disk: "
1150                        "disk->queue=0x%x\n", __func__,
1151                        (unsigned int)
1152                        bd->user_disk_0->queue);
1153                cy_as_hal_print_message(
1154                        "%s: add_disk: "
1155                        "disk->flags=0x%x\n",
1156                        __func__, (unsigned int)
1157                        bd->user_disk_0->flags);
1158                cy_as_hal_print_message(
1159                        "%s: add_disk: "
1160                        "disk->driverfs_dev=0x%x\n",
1161                        __func__, (unsigned int)
1162                        bd->user_disk_0->driverfs_dev);
1163                cy_as_hal_print_message(
1164                        "%s: add_disk: "
1165                        "disk->slave_dir=0x%x\n",
1166                        __func__, (unsigned int)
1167                        bd->user_disk_0->slave_dir);
1168                cy_as_hal_print_message(
1169                        "%s: add_disk: "
1170                        "disk->random=0x%x\n",
1171                        __func__, (unsigned int)
1172                        bd->user_disk_0->random);
1173                cy_as_hal_print_message(
1174                        "%s: add_disk: "
1175                        "disk->node_id=0x%x\n",
1176                        __func__, (unsigned int)
1177                        bd->user_disk_0->node_id);
1178
1179                #endif
1180
1181                add_disk(bd->user_disk_0);
1182
1183        } else if ((bus_num == 1) &&
1184                (total_media_count == 2)) {
1185                bd->user_disk_1_read_only = !dev_data.desc_p.writeable;
1186                bd->user_disk_1_blk_size = dev_data.desc_p.block_size;
1187                bd->user_disk_1_type = dev_data.desc_p.type;
1188                bd->user_disk_1_bus_num = bus_num;
1189                bd->user_disk_1->major  = major;
1190                bd->user_disk_1->first_minor = (devidx + 1) << CYASBLKDEV_SHIFT;
1191                bd->user_disk_1->minors = 8;
1192                bd->user_disk_1->fops = &cyasblkdev_bdops;
1193                bd->user_disk_1->private_data = bd;
1194                bd->user_disk_1->queue = bd->queue.queue;
1195                bd->dbgprn_flags = DBGPRN_RD_RQ;
1196                bd->user_disk_1_unit_no = lcl_unit_no;
1197
1198                sprintf(bd->user_disk_1->disk_name,
1199                        "cyasblkdevblk%d", (devidx + 1));
1200
1201                #ifndef WESTBRIDGE_NDEBUG
1202                cy_as_hal_print_message(
1203                        "%s: disk unit_sz:%lu "
1204                        "blk_sz:%d, "
1205                        "start_blk:%lu, "
1206                        "capacity:%llu\n",
1207                        __func__,
1208                        (unsigned long)
1209                        unit_data.desc_p.unit_size,
1210                        unit_data.desc_p.block_size,
1211                        (unsigned long)
1212                        unit_data.desc_p.start_block,
1213                        (uint64_t)disk_cap
1214                );
1215                #endif
1216
1217                /*blk_size should always be a
1218                 * multiple of 512, set to the max
1219                 * to ensure that all accesses
1220                 * aligned to the greatest multiple,
1221                 * can adjust request to smaller
1222                 * block sizes dynamically*/
1223                if (bd->user_disk_0_blk_size >
1224                bd->user_disk_1_blk_size) {
1225                        blk_queue_logical_block_size(bd->queue.queue,
1226                                bd->user_disk_0_blk_size);
1227                        #ifndef WESTBRIDGE_NDEBUG
1228                        cy_as_hal_print_message(
1229                        "%s: set hard sect_sz:%d\n",
1230                        __func__,
1231                        bd->user_disk_0_blk_size);
1232                        #endif
1233                } else {
1234                        blk_queue_logical_block_size(bd->queue.queue,
1235                                bd->user_disk_1_blk_size);
1236                        #ifndef WESTBRIDGE_NDEBUG
1237                        cy_as_hal_print_message(
1238                        "%s: set hard sect_sz:%d\n",
1239                        __func__,
1240                        bd->user_disk_1_blk_size);
1241                        #endif
1242                }
1243
1244                set_capacity(bd->user_disk_1, disk_cap);
1245                if (vfat_search) {
1246                        bd->user_disk_1_first_sector =
1247                                cyasblkdev_get_vfat_offset(
1248                                        bd->user_disk_1_bus_num,
1249                                        bd->user_disk_1_unit_no);
1250                } else {
1251                        bd->user_disk_1_first_sector
1252                                = 0;
1253                }
1254
1255                add_disk(bd->user_disk_1);
1256        }
1257
1258        if (lcl_unit_no > 0) {
1259                if (bd->system_disk == NULL) {
1260                        bd->system_disk =
1261                                alloc_disk(8);
1262
1263                        if (bd->system_disk == NULL) {
1264                                kfree(bd);
1265                                bd = ERR_PTR(-ENOMEM);
1266                                return bd;
1267                        }
1268                        disk_cap = (uint64_t)
1269                                (private_partition_size);
1270
1271                        /* set properties of
1272                         * system disk */
1273                        bd->system_disk_read_only = !dev_data.desc_p.writeable;
1274                        bd->system_disk_blk_size = dev_data.desc_p.block_size;
1275                        bd->system_disk_bus_num = bus_num;
1276                        bd->system_disk->major = major;
1277                        bd->system_disk->first_minor =
1278                                (devidx + 2) << CYASBLKDEV_SHIFT;
1279                        bd->system_disk->minors = 8;
1280                        bd->system_disk->fops = &cyasblkdev_bdops;
1281                        bd->system_disk->private_data = bd;
1282                        bd->system_disk->queue = bd->queue.queue;
1283                        /* don't search for vfat
1284                         * with system disk */
1285                        bd->system_disk_first_sector = 0;
1286                        sprintf(
1287                                bd->system_disk->disk_name,
1288                                "cyasblkdevblk%d", (devidx + 2));
1289
1290                        set_capacity(bd->system_disk,
1291                                disk_cap);
1292
1293                        add_disk(bd->system_disk);
1294                }
1295                #ifndef WESTBRIDGE_NDEBUG
1296                else {
1297                        cy_as_hal_print_message(
1298                                "%s: system disk already allocated %d\n",
1299                                __func__, bus_num);
1300                }
1301                #endif
1302        }
1303out:
1304        return ret;
1305}
1306
1307static struct cyasblkdev_blk_data *cyasblkdev_blk_alloc(void)
1308{
1309        struct cyasblkdev_blk_data *bd;
1310        int ret = 0;
1311        cy_as_return_status_t stat = -1;
1312        int bus_num = 0;
1313        int total_media_count = 0;
1314        int devidx = 0;
1315        DBGPRN_FUNC_NAME;
1316
1317        total_media_count = 0;
1318        devidx = find_first_zero_bit(dev_use, CYASBLKDEV_NUM_MINORS);
1319        if (devidx >= CYASBLKDEV_NUM_MINORS)
1320                return ERR_PTR(-ENOSPC);
1321
1322        __set_bit(devidx, dev_use);
1323        __set_bit(devidx + 1, dev_use);
1324
1325        bd = kzalloc(sizeof(struct cyasblkdev_blk_data), GFP_KERNEL);
1326        if (bd) {
1327                gl_bd = bd;
1328
1329                spin_lock_init(&bd->lock);
1330                bd->usage = 1;
1331
1332                /* setup the block_dev_ops pointer*/
1333                bd->blkops = &cyasblkdev_bdops;
1334
1335                /* Get the device handle */
1336                bd->dev_handle = cyasdevice_getdevhandle();
1337                if (0 == bd->dev_handle) {
1338                        #ifndef WESTBRIDGE_NDEBUG
1339                        cy_as_hal_print_message(
1340                                "%s: get device failed\n", __func__);
1341                        #endif
1342                        ret = ENODEV;
1343                        goto out;
1344                }
1345
1346                #ifndef WESTBRIDGE_NDEBUG
1347                cy_as_hal_print_message("%s west bridge device handle:%x\n",
1348                        __func__, (uint32_t)bd->dev_handle);
1349                #endif
1350
1351                /* start the storage api and get a handle to the
1352                 * device we are interested in. */
1353
1354                /* Error code to use if the conditions are not satisfied. */
1355                ret = ENOMEDIUM;
1356
1357                stat = cy_as_misc_release_resource(bd->dev_handle, cy_as_bus_0);
1358                if ((stat != CY_AS_ERROR_SUCCESS) &&
1359                (stat != CY_AS_ERROR_RESOURCE_NOT_OWNED)) {
1360                        #ifndef WESTBRIDGE_NDEBUG
1361                        cy_as_hal_print_message("%s: cannot release "
1362                                "resource bus 0 - reason code %d\n",
1363                                __func__, stat);
1364                        #endif
1365                }
1366
1367                stat = cy_as_misc_release_resource(bd->dev_handle, cy_as_bus_1);
1368                if ((stat != CY_AS_ERROR_SUCCESS) &&
1369                (stat != CY_AS_ERROR_RESOURCE_NOT_OWNED)) {
1370                        #ifndef WESTBRIDGE_NDEBUG
1371                        cy_as_hal_print_message("%s: cannot release "
1372                                "resource bus 0 - reason code %d\n",
1373                                __func__, stat);
1374                        #endif
1375                }
1376
1377                /* start storage stack*/
1378                stat = cy_as_storage_start(bd->dev_handle, 0, 0x101);
1379                if (stat != CY_AS_ERROR_SUCCESS) {
1380                        #ifndef WESTBRIDGE_NDEBUG
1381                        cy_as_hal_print_message("%s: cannot start storage "
1382                                "stack - reason code %d\n", __func__, stat);
1383                        #endif
1384                        goto out;
1385                }
1386
1387                #ifndef WESTBRIDGE_NDEBUG
1388                cy_as_hal_print_message("%s: storage started:%d ok\n",
1389                        __func__, stat);
1390                #endif
1391
1392                stat = cy_as_storage_register_callback(bd->dev_handle,
1393                        cyasblkdev_storage_callback);
1394                if (stat != CY_AS_ERROR_SUCCESS) {
1395                        #ifndef WESTBRIDGE_NDEBUG
1396                        cy_as_hal_print_message("%s: cannot register callback "
1397                                "- reason code %d\n", __func__, stat);
1398                        #endif
1399                        goto out;
1400                }
1401
1402                for (bus_num = 0; bus_num < 2; bus_num++) {
1403                        stat = cy_as_storage_query_bus(bd->dev_handle,
1404                                bus_num, &bd->media_count[bus_num],  0, 0);
1405                        if (stat == CY_AS_ERROR_SUCCESS) {
1406                                total_media_count = total_media_count +
1407                                        bd->media_count[bus_num];
1408                        } else {
1409                                #ifndef WESTBRIDGE_NDEBUG
1410                                cy_as_hal_print_message("%s: cannot query %d, "
1411                                        "reason code: %d\n",
1412                                        __func__, bus_num, stat);
1413                                #endif
1414                                goto out;
1415                        }
1416                }
1417
1418                if (total_media_count == 0) {
1419                        #ifndef WESTBRIDGE_NDEBUG
1420                        cy_as_hal_print_message(
1421                                "%s: no storage media was found\n", __func__);
1422                        #endif
1423                        goto out;
1424                } else if (total_media_count >= 1) {
1425                        if (bd->user_disk_0 == NULL) {
1426
1427                                bd->user_disk_0 =
1428                                        alloc_disk(8);
1429                                if (bd->user_disk_0 == NULL) {
1430                                        kfree(bd);
1431                                        bd = ERR_PTR(-ENOMEM);
1432                                        return bd;
1433                                }
1434                        }
1435                        #ifndef WESTBRIDGE_NDEBUG
1436                        else {
1437                                cy_as_hal_print_message("%s: no available "
1438                                        "gen_disk for disk 0, "
1439                                        "physically inconsistent\n", __func__);
1440                        }
1441                        #endif
1442                }
1443
1444                if (total_media_count == 2) {
1445                        if (bd->user_disk_1 == NULL) {
1446                                bd->user_disk_1 =
1447                                        alloc_disk(8);
1448                                if (bd->user_disk_1 == NULL) {
1449                                        kfree(bd);
1450                                        bd = ERR_PTR(-ENOMEM);
1451                                        return bd;
1452                                }
1453                        }
1454                        #ifndef WESTBRIDGE_NDEBUG
1455                        else {
1456                                cy_as_hal_print_message("%s: no available "
1457                                        "gen_disk for media, "
1458                                        "physically inconsistent\n", __func__);
1459                        }
1460                        #endif
1461                }
1462                #ifndef WESTBRIDGE_NDEBUG
1463                else if (total_media_count > 2) {
1464                        cy_as_hal_print_message("%s: count corrupted = 0x%d\n",
1465                                __func__, total_media_count);
1466                }
1467                #endif
1468
1469                #ifndef WESTBRIDGE_NDEBUG
1470                cy_as_hal_print_message("%s: %d device(s) found\n",
1471                        __func__, total_media_count);
1472                #endif
1473
1474                for (bus_num = 0; bus_num <= 1; bus_num++) {
1475                        /*claim storage for cpu */
1476                        stat = cy_as_storage_claim(bd->dev_handle,
1477                                bus_num, 0, 0, 0);
1478                        if (stat != CY_AS_ERROR_SUCCESS) {
1479                                cy_as_hal_print_message("%s: cannot claim "
1480                                        "%d bus - reason code %d\n",
1481                                        __func__, bus_num, stat);
1482                                goto out;
1483                        }
1484
1485                        dev_data.bus = bus_num;
1486                        dev_data.device = 0;
1487
1488                        stat = cy_as_storage_query_device(bd->dev_handle,
1489                                &dev_data, 0, 0);
1490                        if (stat == CY_AS_ERROR_SUCCESS) {
1491                                cyasblkdev_add_disks(bus_num, bd,
1492                                        total_media_count, devidx);
1493                        } else if (stat == CY_AS_ERROR_NO_SUCH_DEVICE) {
1494                                #ifndef WESTBRIDGE_NDEBUG
1495                                cy_as_hal_print_message(
1496                                        "%s: no device on bus %d\n",
1497                                        __func__, bus_num);
1498                                #endif
1499                        } else {
1500                                #ifndef WESTBRIDGE_NDEBUG
1501                                cy_as_hal_print_message(
1502                                        "%s: cannot query %d device "
1503                                        "- reason code %d\n",
1504                                        __func__, bus_num, stat);
1505                                #endif
1506                                goto out;
1507                        }
1508                } /* end for (bus_num = 0; bus_num <= 1; bus_num++)*/
1509
1510                return bd;
1511        }
1512out:
1513        #ifndef WESTBRIDGE_NDEBUG
1514        cy_as_hal_print_message(
1515                "%s: bd failed to initialize\n", __func__);
1516        #endif
1517
1518        kfree(bd);
1519        bd = ERR_PTR(-ret);
1520        return bd;
1521}
1522
1523
1524/*init west bridge block device */
1525static int cyasblkdev_blk_initialize(void)
1526{
1527        struct cyasblkdev_blk_data *bd;
1528        int res;
1529
1530        DBGPRN_FUNC_NAME;
1531
1532        res = register_blkdev(major, "cyasblkdev");
1533
1534        if (res < 0) {
1535                #ifndef WESTBRIDGE_NDEBUG
1536                cy_as_hal_print_message(KERN_WARNING
1537                        "%s unable to get major %d for cyasblkdev media: %d\n",
1538                        __func__, major, res);
1539                #endif
1540                return res;
1541        }
1542
1543        if (major == 0)
1544                major = res;
1545
1546        #ifndef WESTBRIDGE_NDEBUG
1547        cy_as_hal_print_message(
1548                "%s cyasblkdev registered with major number: %d\n",
1549                __func__, major);
1550        #endif
1551
1552        bd = cyasblkdev_blk_alloc();
1553        if (IS_ERR(bd))
1554                return PTR_ERR(bd);
1555
1556        return 0;
1557}
1558
1559/* start block device */
1560static int __init cyasblkdev_blk_init(void)
1561{
1562        int res = -ENOMEM;
1563
1564        DBGPRN_FUNC_NAME;
1565
1566        /* get the cyasdev handle for future use*/
1567        cyas_dev_handle = cyasdevice_getdevhandle();
1568
1569        if  (cyasblkdev_blk_initialize() == 0)
1570                return 0;
1571
1572        #ifndef WESTBRIDGE_NDEBUG
1573        cy_as_hal_print_message("cyasblkdev init error:%d\n", res);
1574        #endif
1575        return res;
1576}
1577
1578
1579static void cyasblkdev_blk_deinit(struct cyasblkdev_blk_data *bd)
1580{
1581        DBGPRN_FUNC_NAME;
1582
1583        if (bd) {
1584                int devidx;
1585
1586                if (bd->user_disk_0 != NULL) {
1587                        del_gendisk(bd->user_disk_0);
1588                        devidx = bd->user_disk_0->first_minor
1589                                >> CYASBLKDEV_SHIFT;
1590                        __clear_bit(devidx, dev_use);
1591                }
1592
1593                if (bd->user_disk_1 != NULL) {
1594                        del_gendisk(bd->user_disk_1);
1595                        devidx = bd->user_disk_1->first_minor
1596                                >> CYASBLKDEV_SHIFT;
1597                        __clear_bit(devidx, dev_use);
1598                }
1599
1600                if (bd->system_disk != NULL) {
1601                        del_gendisk(bd->system_disk);
1602                        devidx = bd->system_disk->first_minor
1603                                >> CYASBLKDEV_SHIFT;
1604                        __clear_bit(devidx, dev_use);
1605                }
1606
1607                cyasblkdev_blk_put(bd);
1608        }
1609}
1610
1611/* block device exit */
1612static void __exit cyasblkdev_blk_exit(void)
1613{
1614        DBGPRN_FUNC_NAME;
1615
1616        cyasblkdev_blk_deinit(gl_bd);
1617        unregister_blkdev(major, "cyasblkdev");
1618
1619}
1620
1621module_init(cyasblkdev_blk_init);
1622module_exit(cyasblkdev_blk_exit);
1623
1624MODULE_LICENSE("GPL");
1625MODULE_DESCRIPTION("antioch (cyasblkdev) block device driver");
1626MODULE_AUTHOR("cypress semiconductor");
1627
1628/*[]*/
1629