1
/* cyanblkdev_block.c - West Bridge Linux Block Driver source file
2
## ===========================
3
## Copyright (C) 2010 Cypress Semiconductor
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.
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.
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
## ===========================
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
30
* Block driver for media (i.e., flash cards)
32
* Copyright 2002 Hewlett-Packard Company
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.
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.
42
* Many thanks to Alessandro Rubini and Jonathan Corbet!
44
* Author: Andrew Christian
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>
55
#include <linux/errno.h>
56
#include <linux/hdreg.h>
57
#include <linux/kdev_t.h>
58
#include <linux/blkdev.h>
60
#include <asm/system.h>
61
#include <linux/uaccess.h>
63
#include <linux/scatterlist.h>
64
#include <linux/time.h>
65
#include <linux/signal.h>
66
#include <linux/delay.h>
68
#include "cyasblkdev_queue.h"
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
79
module_param(major, int, 0444);
80
MODULE_PARM_DESC(major,
81
"specify the major device number for cyasblkdev block driver");
83
/* parameters passed from the user space */
84
static int vfat_search;
85
module_param(vfat_search, bool, S_IRUGO | S_IWUSR);
86
MODULE_PARM_DESC(vfat_search,
87
"dynamically find the location of the first sector");
89
static int private_partition_bus = -1;
90
module_param(private_partition_bus, int, S_IRUGO | S_IWUSR);
91
MODULE_PARM_DESC(private_partition_bus,
92
"bus number for private partition");
94
static int private_partition_size = -1;
95
module_param(private_partition_size, int, S_IRUGO | S_IWUSR);
96
MODULE_PARM_DESC(private_partition_size,
97
"size of the private partition");
100
* There is one cyasblkdev_blk_data per slot.
102
struct cyasblkdev_blk_data {
105
const struct block_device_operations *blkops;
107
unsigned int suspended;
109
/* handle to the west bridge device this handle, typdefed as *void */
110
cy_as_device_handle dev_handle;
112
/* our custom structure, in addition to request queue,
113
* adds lock & semaphore items*/
114
struct cyasblkdev_queue queue;
116
/* 16 entries is enough given max request size
117
* 16 * 4K (64 K per request)*/
118
struct scatterlist sg[16];
120
/* non-zero enables printk of executed reqests */
121
unsigned int dbgprn_flags;
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;
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;
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;
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;
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;
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;
157
/* pointer to west bridge block data device superstructure */
158
static struct cyasblkdev_blk_data *gl_bd;
160
static DEFINE_SEMAPHORE(open_lock);
162
/* local forwardd declarationss */
163
static cy_as_device_handle *cyas_dev_handle;
164
static void cyasblkdev_blk_deinit(struct cyasblkdev_blk_data *bd);
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)
171
int blkdev_ctl_dbgprn(
175
int cur_options = gl_bd->dbgprn_flags;
179
/* set new debug print options */
180
gl_bd->dbgprn_flags = prn_flags;
182
/* return previous */
185
EXPORT_SYMBOL(blkdev_ctl_dbgprn);
187
static struct cyasblkdev_blk_data *cyasblkdev_blk_get(
191
struct cyasblkdev_blk_data *bd;
197
bd = disk->private_data;
199
if (bd && (bd->usage == 0))
205
cy_as_hal_print_message(
206
"cyasblkdev_blk_get: usage = %d\n", bd->usage);
214
static void cyasblkdev_blk_put(
215
struct cyasblkdev_blk_data *bd
224
#ifndef WESTBRIDGE_NDEBUG
225
cy_as_hal_print_message(
226
" cyasblkdev_blk_put , bd->usage= %d\n", bd->usage);
229
#ifndef WESTBRIDGE_NDEBUG
230
cy_as_hal_print_message(
231
"cyasblkdev: blk_put(bd) on bd = NULL!: usage = %d\n",
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);
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");
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");
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");
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.
272
cy_as_hal_disable_scatter_list(cyasdevice_gethaltag());
275
/*ptr to global struct cyasblkdev_blk_data */
280
#ifndef WESTBRIDGE_NDEBUG
281
cy_as_hal_print_message(
282
"cyasblkdev (blk_put): usage = %d\n",
288
static int cyasblkdev_blk_open(
289
struct block_device *bdev,
293
struct cyasblkdev_blk_data *bd = cyasblkdev_blk_get(bdev->bd_disk);
300
check_disk_change(bdev);
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");
312
cyasblkdev_blk_put(bd);
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");
323
cyasblkdev_blk_put(bd);
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");
334
cyasblkdev_blk_put(bd);
343
static int cyasblkdev_blk_release(
344
struct gendisk *disk,
348
struct cyasblkdev_blk_data *bd = disk->private_data;
352
cyasblkdev_blk_put(bd);
356
static int cyasblkdev_blk_ioctl(
357
struct block_device *bdev,
365
if (cmd == HDIO_GETGEO) {
366
/*for now we only process geometry IOCTL*/
367
struct hd_geometry geo;
369
memset(&geo, 0, sizeof(struct hd_geometry));
371
geo.cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
374
geo.start = get_start_sect(bdev);
376
/* copy to user space */
377
return copy_to_user((void __user *)arg, &geo, sizeof(geo))
384
/* check_events 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 */
387
unsigned int cyasblkdev_check_events(struct gendisk *gd, unsigned int clearing)
389
struct cyasblkdev_blk_data *bd;
391
#ifndef WESTBRIDGE_NDEBUG
392
cy_as_hal_print_message("cyasblkdev_media_changed() is called\n");
396
bd = gd->private_data;
398
#ifndef WESTBRIDGE_NDEBUG
399
cy_as_hal_print_message(
400
"cyasblkdev_media_changed() is called, "
405
/* return media change state - DISK_EVENT_MEDIA_CHANGE yes, 0 no */
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 */
412
int cyasblkdev_revalidate_disk(struct gendisk *gd)
414
/*int (*revalidate_disk) (struct gendisk *); */
416
#ifndef WESTBRIDGE_NDEBUG
418
cy_as_hal_print_message(
419
"cyasblkdev_revalidate_disk() is called, "
420
"(gl_bd->usage:%d)\n", gl_bd->usage);
423
/* 0 means ok, kern can go ahead with partition rescan */
428
/*standard block device driver interface */
429
static 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
.check_events = cyasblkdev_check_events,
436
/* added to support media removal( real and simulated) media */
437
.revalidate_disk = cyasblkdev_revalidate_disk,
438
.owner = THIS_MODULE,
441
/* west bridge block device prep request function */
442
static int cyasblkdev_blk_prep_rq(
443
struct cyasblkdev_queue *bq,
447
struct cyasblkdev_blk_data *bd = bq->data;
448
int stat = BLKPREP_OK;
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);
463
blk_plug_device(bd->queue.queue);
464
stat = BLKPREP_DEFER;
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");
476
/*west bridge storage async api on_completed callback */
477
static 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 */
484
/* The unit completing the operation */
486
/* The block number of the completed operation */
487
uint32_t block_number,
488
/* The type of operation */
490
/* The error status */
491
cy_as_return_status_t status
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);
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));
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)) {
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,
529
spin_lock_irq(&gl_bd->lock);
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);
542
if (gl_bd->queue.req) {
543
spin_unlock_irq(&gl_bd->lock);
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);
550
gl_bd->queue.issue_fn(&gl_bd->queue, gl_bd->queue.req);
552
spin_unlock_irq(&gl_bd->lock);
556
/* issue astoria blkdev request (issue_fn) */
557
static int cyasblkdev_blk_issue_rq(
558
struct cyasblkdev_queue *bq,
562
struct cyasblkdev_blk_data *bd = bq->data;
564
int ret = CY_AS_ERROR_SUCCESS;
565
uint32_t req_sector = 0;
566
uint32_t req_nr_sectors = 0;
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.
578
spin_lock_irq(&bd->lock);
579
index = blk_rq_map_sg(bq->queue, req, bd->sg);
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;
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),
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;
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);
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;
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);
617
#ifndef WESTBRIDGE_NDEBUG
619
cy_as_hal_print_message(
620
"%s: invalid disk used for request\n", __func__);
624
spin_unlock_irq(&bd->lock);
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);
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);
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);
646
while (blk_end_request(req,
647
(ret == CY_AS_ERROR_SUCCESS),
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);
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);
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),
680
dev_use[CYASBLKDEV_NUM_MINORS / (8 * sizeof(unsigned long))];
683
/* storage event callback (note: called in astoria isr context) */
684
static void cyasblkdev_storage_callback(
685
cy_as_device_handle dev_h,
686
cy_as_bus_number_t bus,
688
cy_as_storage_event evtype,
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);
698
case cy_as_storage_processor:
701
case cy_as_storage_removed:
704
case cy_as_storage_inserted:
712
#define SECTORS_TO_SCAN 4096
714
uint32_t cyasblkdev_get_vfat_offset(int bus_num, int unit_no)
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
726
bool br_found = false;
730
sect_buf = kmalloc(1024, GFP_KERNEL);
732
/* since HAL layer always uses sg lists instead of the
733
* buffer (for hw dmas) we need to initialize the sg list
735
sg_init_one(gl_bd->sg, sect_buf, 512);
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
742
#ifndef WESTBRIDGE_NDEBUG
743
cy_as_hal_print_message(
744
"%s scanning media for vfat partition...\n", __func__);
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);
754
stat = cy_as_storage_read(
755
/* Handle to the device of interest */
757
/* The bus to access */
759
/* The device to access */
761
/* The unit to access */
763
/* absolute sector number */
767
/* The number of blocks to be read */
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 "
789
#ifndef WESTBRIDGE_NDEBUG
790
cy_as_hal_print_message("%s sector scan error\n",
802
#ifndef WESTBRIDGE_NDEBUG
803
cy_as_hal_print_message(
804
"%s vfat partition is not found, using 0 offset\n",
811
cy_as_storage_query_device_data dev_data = {0};
813
static int cyasblkdev_add_disks(int bus_num,
814
struct cyasblkdev_blk_data *bd,
815
int total_media_count,
821
cy_as_storage_query_unit_data unit_data = {0};
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, "
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
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__);
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__);
857
unit_data.device = 0;
859
unit_data.bus = bus_num;
860
ret = cy_as_storage_query_unit(bd->dev_handle,
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);
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",
885
disk_cap = (uint64_t)
886
(unit_data.desc_p.unit_size);
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",
897
/*check to see that partition
899
if (unit_data.desc_p.unit_size !=
900
private_partition_size) {
901
ret = cy_as_storage_remove_p_partition(
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;
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);
920
/* need to requery bus
922
* successful and create
923
* failed we have changed
924
* the disk properties */
925
unit_data.bus = bus_num;
926
unit_data.device = 0;
930
ret = cy_as_storage_query_unit(
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);
942
disk_cap = (uint64_t)
943
(unit_data.desc_p.unit_size);
948
#ifndef WESTBRIDGE_NDEBUG
949
cy_as_hal_print_message(
950
"%s: cy_as_storage_remove_p_partition "
951
"failed with error %d\n",
955
unit_data.bus = bus_num;
956
unit_data.device = 0;
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__,
972
disk_cap = (uint64_t)
973
(unit_data.desc_p.unit_size);
978
#ifndef WESTBRIDGE_NDEBUG
979
cy_as_hal_print_message("%s: partition "
980
"exists and sizes equal\n",
984
/*partition already existed,
985
* need to query second unit*/
986
unit_data.bus = bus_num;
987
unit_data.device = 0;
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 "
997
"- reason code %d\n",
998
__func__, bus_num, ret);
1002
disk_cap = (uint64_t)
1003
(unit_data.desc_p.unit_size);
1004
lcl_unit_no = unit_data.unit;
1008
#ifndef WESTBRIDGE_NDEBUG
1009
cy_as_hal_print_message(
1010
"%s: cy_as_storage_create_p_partition "
1011
"created successfully\n", __func__);
1014
disk_cap = (uint64_t)
1015
(unit_data.desc_p.unit_size -
1016
private_partition_size);
1021
#ifndef WESTBRIDGE_NDEBUG
1023
cy_as_hal_print_message(
1024
"%s: invalid partition_size%d\n", __func__,
1025
private_partition_size);
1027
disk_cap = (uint64_t)
1028
(unit_data.desc_p.unit_size);
1033
disk_cap = (uint64_t)
1034
(unit_data.desc_p.unit_size);
1038
if ((bus_num == 0) ||
1039
(total_media_count == 1)) {
1040
sprintf(bd->user_disk_0->disk_name,
1041
"cyasblkdevblk%d", devidx);
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,
1051
unit_data.desc_p.start_block,
1056
#ifndef WESTBRIDGE_NDEBUG
1057
cy_as_hal_print_message("%s: setting gendisk disk "
1058
"capacity to %d\n", __func__, (int) disk_cap);
1061
/* initializing bd->queue */
1062
#ifndef WESTBRIDGE_NDEBUG
1063
cy_as_hal_print_message("%s: init bd->queue\n",
1067
/* this will create a
1068
* queue kernel thread */
1069
cyasblkdev_init_queue(
1070
&bd->queue, &bd->lock);
1072
bd->queue.prep_fn = cyasblkdev_blk_prep_rq;
1073
bd->queue.issue_fn = cyasblkdev_blk_issue_rq;
1074
bd->queue.data = bd;
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
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->events = DISK_EVENT_MEDIA_CHANGE;
1094
bd->user_disk_0->private_data = bd;
1095
bd->user_disk_0->queue = bd->queue.queue;
1096
bd->dbgprn_flags = DBGPRN_RD_RQ;
1097
bd->user_disk_0_unit_no = lcl_unit_no;
1099
blk_queue_logical_block_size(bd->queue.queue,
1100
bd->user_disk_0_blk_size);
1102
set_capacity(bd->user_disk_0,
1105
#ifndef WESTBRIDGE_NDEBUG
1106
cy_as_hal_print_message(
1107
"%s: returned from set_capacity %d\n",
1108
__func__, (int) disk_cap);
1111
/* need to start search from
1112
* public partition beginning */
1114
bd->user_disk_0_first_sector =
1115
cyasblkdev_get_vfat_offset(
1116
bd->user_disk_0_bus_num,
1117
bd->user_disk_0_unit_no);
1119
bd->user_disk_0_first_sector = 0;
1122
#ifndef WESTBRIDGE_NDEBUG
1123
cy_as_hal_print_message(
1124
"%s: set user_disk_0_first "
1125
"sector to %d\n", __func__,
1126
bd->user_disk_0_first_sector);
1127
cy_as_hal_print_message(
1128
"%s: add_disk: disk->major=0x%x\n",
1130
bd->user_disk_0->major);
1131
cy_as_hal_print_message(
1133
"disk->first_minor=0x%x\n", __func__,
1134
bd->user_disk_0->first_minor);
1135
cy_as_hal_print_message(
1137
"disk->minors=0x%x\n", __func__,
1138
bd->user_disk_0->minors);
1139
cy_as_hal_print_message(
1141
"disk->disk_name=%s\n",
1143
bd->user_disk_0->disk_name);
1144
cy_as_hal_print_message(
1146
"disk->part_tbl=0x%x\n", __func__,
1148
bd->user_disk_0->part_tbl);
1149
cy_as_hal_print_message(
1151
"disk->queue=0x%x\n", __func__,
1153
bd->user_disk_0->queue);
1154
cy_as_hal_print_message(
1156
"disk->flags=0x%x\n",
1157
__func__, (unsigned int)
1158
bd->user_disk_0->flags);
1159
cy_as_hal_print_message(
1161
"disk->driverfs_dev=0x%x\n",
1162
__func__, (unsigned int)
1163
bd->user_disk_0->driverfs_dev);
1164
cy_as_hal_print_message(
1166
"disk->slave_dir=0x%x\n",
1167
__func__, (unsigned int)
1168
bd->user_disk_0->slave_dir);
1169
cy_as_hal_print_message(
1171
"disk->random=0x%x\n",
1172
__func__, (unsigned int)
1173
bd->user_disk_0->random);
1174
cy_as_hal_print_message(
1176
"disk->node_id=0x%x\n",
1177
__func__, (unsigned int)
1178
bd->user_disk_0->node_id);
1182
add_disk(bd->user_disk_0);
1184
} else if ((bus_num == 1) &&
1185
(total_media_count == 2)) {
1186
bd->user_disk_1_read_only = !dev_data.desc_p.writeable;
1187
bd->user_disk_1_blk_size = dev_data.desc_p.block_size;
1188
bd->user_disk_1_type = dev_data.desc_p.type;
1189
bd->user_disk_1_bus_num = bus_num;
1190
bd->user_disk_1->major = major;
1191
bd->user_disk_1->first_minor = (devidx + 1) << CYASBLKDEV_SHIFT;
1192
bd->user_disk_1->minors = 8;
1193
bd->user_disk_1->fops = &cyasblkdev_bdops;
1194
bd->user_disk_1->events = DISK_EVENT_MEDIA_CHANGE;
1195
bd->user_disk_1->private_data = bd;
1196
bd->user_disk_1->queue = bd->queue.queue;
1197
bd->dbgprn_flags = DBGPRN_RD_RQ;
1198
bd->user_disk_1_unit_no = lcl_unit_no;
1200
sprintf(bd->user_disk_1->disk_name,
1201
"cyasblkdevblk%d", (devidx + 1));
1203
#ifndef WESTBRIDGE_NDEBUG
1204
cy_as_hal_print_message(
1205
"%s: disk unit_sz:%lu "
1211
unit_data.desc_p.unit_size,
1212
unit_data.desc_p.block_size,
1214
unit_data.desc_p.start_block,
1219
/*blk_size should always be a
1220
* multiple of 512, set to the max
1221
* to ensure that all accesses
1222
* aligned to the greatest multiple,
1223
* can adjust request to smaller
1224
* block sizes dynamically*/
1225
if (bd->user_disk_0_blk_size >
1226
bd->user_disk_1_blk_size) {
1227
blk_queue_logical_block_size(bd->queue.queue,
1228
bd->user_disk_0_blk_size);
1229
#ifndef WESTBRIDGE_NDEBUG
1230
cy_as_hal_print_message(
1231
"%s: set hard sect_sz:%d\n",
1233
bd->user_disk_0_blk_size);
1236
blk_queue_logical_block_size(bd->queue.queue,
1237
bd->user_disk_1_blk_size);
1238
#ifndef WESTBRIDGE_NDEBUG
1239
cy_as_hal_print_message(
1240
"%s: set hard sect_sz:%d\n",
1242
bd->user_disk_1_blk_size);
1246
set_capacity(bd->user_disk_1, disk_cap);
1248
bd->user_disk_1_first_sector =
1249
cyasblkdev_get_vfat_offset(
1250
bd->user_disk_1_bus_num,
1251
bd->user_disk_1_unit_no);
1253
bd->user_disk_1_first_sector
1257
add_disk(bd->user_disk_1);
1260
if (lcl_unit_no > 0) {
1261
if (bd->system_disk == NULL) {
1265
if (bd->system_disk == NULL) {
1267
bd = ERR_PTR(-ENOMEM);
1270
disk_cap = (uint64_t)
1271
(private_partition_size);
1273
/* set properties of
1275
bd->system_disk_read_only = !dev_data.desc_p.writeable;
1276
bd->system_disk_blk_size = dev_data.desc_p.block_size;
1277
bd->system_disk_bus_num = bus_num;
1278
bd->system_disk->major = major;
1279
bd->system_disk->first_minor =
1280
(devidx + 2) << CYASBLKDEV_SHIFT;
1281
bd->system_disk->minors = 8;
1282
bd->system_disk->fops = &cyasblkdev_bdops;
1283
bd->system_disk->events = DISK_EVENT_MEDIA_CHANGE;
1284
bd->system_disk->private_data = bd;
1285
bd->system_disk->queue = bd->queue.queue;
1286
/* don't search for vfat
1287
* with system disk */
1288
bd->system_disk_first_sector = 0;
1290
bd->system_disk->disk_name,
1291
"cyasblkdevblk%d", (devidx + 2));
1293
set_capacity(bd->system_disk,
1296
add_disk(bd->system_disk);
1298
#ifndef WESTBRIDGE_NDEBUG
1300
cy_as_hal_print_message(
1301
"%s: system disk already allocated %d\n",
1310
static struct cyasblkdev_blk_data *cyasblkdev_blk_alloc(void)
1312
struct cyasblkdev_blk_data *bd;
1314
cy_as_return_status_t stat = -1;
1316
int total_media_count = 0;
1320
total_media_count = 0;
1321
devidx = find_first_zero_bit(dev_use, CYASBLKDEV_NUM_MINORS);
1322
if (devidx >= CYASBLKDEV_NUM_MINORS)
1323
return ERR_PTR(-ENOSPC);
1325
__set_bit(devidx, dev_use);
1326
__set_bit(devidx + 1, dev_use);
1328
bd = kzalloc(sizeof(struct cyasblkdev_blk_data), GFP_KERNEL);
1332
spin_lock_init(&bd->lock);
1335
/* setup the block_dev_ops pointer*/
1336
bd->blkops = &cyasblkdev_bdops;
1338
/* Get the device handle */
1339
bd->dev_handle = cyasdevice_getdevhandle();
1340
if (0 == bd->dev_handle) {
1341
#ifndef WESTBRIDGE_NDEBUG
1342
cy_as_hal_print_message(
1343
"%s: get device failed\n", __func__);
1349
#ifndef WESTBRIDGE_NDEBUG
1350
cy_as_hal_print_message("%s west bridge device handle:%x\n",
1351
__func__, (uint32_t)bd->dev_handle);
1354
/* start the storage api and get a handle to the
1355
* device we are interested in. */
1357
/* Error code to use if the conditions are not satisfied. */
1360
stat = cy_as_misc_release_resource(bd->dev_handle, cy_as_bus_0);
1361
if ((stat != CY_AS_ERROR_SUCCESS) &&
1362
(stat != CY_AS_ERROR_RESOURCE_NOT_OWNED)) {
1363
#ifndef WESTBRIDGE_NDEBUG
1364
cy_as_hal_print_message("%s: cannot release "
1365
"resource bus 0 - reason code %d\n",
1370
stat = cy_as_misc_release_resource(bd->dev_handle, cy_as_bus_1);
1371
if ((stat != CY_AS_ERROR_SUCCESS) &&
1372
(stat != CY_AS_ERROR_RESOURCE_NOT_OWNED)) {
1373
#ifndef WESTBRIDGE_NDEBUG
1374
cy_as_hal_print_message("%s: cannot release "
1375
"resource bus 0 - reason code %d\n",
1380
/* start storage stack*/
1381
stat = cy_as_storage_start(bd->dev_handle, 0, 0x101);
1382
if (stat != CY_AS_ERROR_SUCCESS) {
1383
#ifndef WESTBRIDGE_NDEBUG
1384
cy_as_hal_print_message("%s: cannot start storage "
1385
"stack - reason code %d\n", __func__, stat);
1390
#ifndef WESTBRIDGE_NDEBUG
1391
cy_as_hal_print_message("%s: storage started:%d ok\n",
1395
stat = cy_as_storage_register_callback(bd->dev_handle,
1396
cyasblkdev_storage_callback);
1397
if (stat != CY_AS_ERROR_SUCCESS) {
1398
#ifndef WESTBRIDGE_NDEBUG
1399
cy_as_hal_print_message("%s: cannot register callback "
1400
"- reason code %d\n", __func__, stat);
1405
for (bus_num = 0; bus_num < 2; bus_num++) {
1406
stat = cy_as_storage_query_bus(bd->dev_handle,
1407
bus_num, &bd->media_count[bus_num], 0, 0);
1408
if (stat == CY_AS_ERROR_SUCCESS) {
1409
total_media_count = total_media_count +
1410
bd->media_count[bus_num];
1412
#ifndef WESTBRIDGE_NDEBUG
1413
cy_as_hal_print_message("%s: cannot query %d, "
1414
"reason code: %d\n",
1415
__func__, bus_num, stat);
1421
if (total_media_count == 0) {
1422
#ifndef WESTBRIDGE_NDEBUG
1423
cy_as_hal_print_message(
1424
"%s: no storage media was found\n", __func__);
1427
} else if (total_media_count >= 1) {
1428
if (bd->user_disk_0 == NULL) {
1432
if (bd->user_disk_0 == NULL) {
1434
bd = ERR_PTR(-ENOMEM);
1438
#ifndef WESTBRIDGE_NDEBUG
1440
cy_as_hal_print_message("%s: no available "
1441
"gen_disk for disk 0, "
1442
"physically inconsistent\n", __func__);
1447
if (total_media_count == 2) {
1448
if (bd->user_disk_1 == NULL) {
1451
if (bd->user_disk_1 == NULL) {
1453
bd = ERR_PTR(-ENOMEM);
1457
#ifndef WESTBRIDGE_NDEBUG
1459
cy_as_hal_print_message("%s: no available "
1460
"gen_disk for media, "
1461
"physically inconsistent\n", __func__);
1465
#ifndef WESTBRIDGE_NDEBUG
1466
else if (total_media_count > 2) {
1467
cy_as_hal_print_message("%s: count corrupted = 0x%d\n",
1468
__func__, total_media_count);
1472
#ifndef WESTBRIDGE_NDEBUG
1473
cy_as_hal_print_message("%s: %d device(s) found\n",
1474
__func__, total_media_count);
1477
for (bus_num = 0; bus_num <= 1; bus_num++) {
1478
/*claim storage for cpu */
1479
stat = cy_as_storage_claim(bd->dev_handle,
1481
if (stat != CY_AS_ERROR_SUCCESS) {
1482
cy_as_hal_print_message("%s: cannot claim "
1483
"%d bus - reason code %d\n",
1484
__func__, bus_num, stat);
1488
dev_data.bus = bus_num;
1489
dev_data.device = 0;
1491
stat = cy_as_storage_query_device(bd->dev_handle,
1493
if (stat == CY_AS_ERROR_SUCCESS) {
1494
cyasblkdev_add_disks(bus_num, bd,
1495
total_media_count, devidx);
1496
} else if (stat == CY_AS_ERROR_NO_SUCH_DEVICE) {
1497
#ifndef WESTBRIDGE_NDEBUG
1498
cy_as_hal_print_message(
1499
"%s: no device on bus %d\n",
1503
#ifndef WESTBRIDGE_NDEBUG
1504
cy_as_hal_print_message(
1505
"%s: cannot query %d device "
1506
"- reason code %d\n",
1507
__func__, bus_num, stat);
1511
} /* end for (bus_num = 0; bus_num <= 1; bus_num++)*/
1516
#ifndef WESTBRIDGE_NDEBUG
1517
cy_as_hal_print_message(
1518
"%s: bd failed to initialize\n", __func__);
1527
/*init west bridge block device */
1528
static int cyasblkdev_blk_initialize(void)
1530
struct cyasblkdev_blk_data *bd;
1535
res = register_blkdev(major, "cyasblkdev");
1538
#ifndef WESTBRIDGE_NDEBUG
1539
cy_as_hal_print_message(KERN_WARNING
1540
"%s unable to get major %d for cyasblkdev media: %d\n",
1541
__func__, major, res);
1549
#ifndef WESTBRIDGE_NDEBUG
1550
cy_as_hal_print_message(
1551
"%s cyasblkdev registered with major number: %d\n",
1555
bd = cyasblkdev_blk_alloc();
1562
/* start block device */
1563
static int __init cyasblkdev_blk_init(void)
1569
/* get the cyasdev handle for future use*/
1570
cyas_dev_handle = cyasdevice_getdevhandle();
1572
if (cyasblkdev_blk_initialize() == 0)
1575
#ifndef WESTBRIDGE_NDEBUG
1576
cy_as_hal_print_message("cyasblkdev init error:%d\n", res);
1582
static void cyasblkdev_blk_deinit(struct cyasblkdev_blk_data *bd)
1589
if (bd->user_disk_0 != NULL) {
1590
del_gendisk(bd->user_disk_0);
1591
devidx = bd->user_disk_0->first_minor
1592
>> CYASBLKDEV_SHIFT;
1593
__clear_bit(devidx, dev_use);
1596
if (bd->user_disk_1 != NULL) {
1597
del_gendisk(bd->user_disk_1);
1598
devidx = bd->user_disk_1->first_minor
1599
>> CYASBLKDEV_SHIFT;
1600
__clear_bit(devidx, dev_use);
1603
if (bd->system_disk != NULL) {
1604
del_gendisk(bd->system_disk);
1605
devidx = bd->system_disk->first_minor
1606
>> CYASBLKDEV_SHIFT;
1607
__clear_bit(devidx, dev_use);
1610
cyasblkdev_blk_put(bd);
1614
/* block device exit */
1615
static void __exit cyasblkdev_blk_exit(void)
1619
cyasblkdev_blk_deinit(gl_bd);
1620
unregister_blkdev(major, "cyasblkdev");
1624
module_init(cyasblkdev_blk_init);
1625
module_exit(cyasblkdev_blk_exit);
1627
MODULE_LICENSE("GPL");
1628
MODULE_DESCRIPTION("antioch (cyasblkdev) block device driver");
1629
MODULE_AUTHOR("cypress semiconductor");