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 /* 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 */
387 int cyasblkdev_media_changed(struct gendisk
*gd
)
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 "1" 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 .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
,
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
->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
;
1098 blk_queue_logical_block_size(bd
->queue
.queue
,
1099 bd
->user_disk_0_blk_size
);
1101 set_capacity(bd
->user_disk_0
,
1104 #ifndef WESTBRIDGE_NDEBUG
1105 cy_as_hal_print_message(
1106 "%s: returned from set_capacity %d\n",
1107 __func__
, (int) disk_cap
);
1110 /* need to start search from
1111 * public partition beginning */
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
);
1118 bd
->user_disk_0_first_sector
= 0;
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",
1129 bd
->user_disk_0
->major
);
1130 cy_as_hal_print_message(
1132 "disk->first_minor=0x%x\n", __func__
,
1133 bd
->user_disk_0
->first_minor
);
1134 cy_as_hal_print_message(
1136 "disk->minors=0x%x\n", __func__
,
1137 bd
->user_disk_0
->minors
);
1138 cy_as_hal_print_message(
1140 "disk->disk_name=%s\n",
1142 bd
->user_disk_0
->disk_name
);
1143 cy_as_hal_print_message(
1145 "disk->part_tbl=0x%x\n", __func__
,
1147 bd
->user_disk_0
->part_tbl
);
1148 cy_as_hal_print_message(
1150 "disk->queue=0x%x\n", __func__
,
1152 bd
->user_disk_0
->queue
);
1153 cy_as_hal_print_message(
1155 "disk->flags=0x%x\n",
1156 __func__
, (unsigned int)
1157 bd
->user_disk_0
->flags
);
1158 cy_as_hal_print_message(
1160 "disk->driverfs_dev=0x%x\n",
1161 __func__
, (unsigned int)
1162 bd
->user_disk_0
->driverfs_dev
);
1163 cy_as_hal_print_message(
1165 "disk->slave_dir=0x%x\n",
1166 __func__
, (unsigned int)
1167 bd
->user_disk_0
->slave_dir
);
1168 cy_as_hal_print_message(
1170 "disk->random=0x%x\n",
1171 __func__
, (unsigned int)
1172 bd
->user_disk_0
->random
);
1173 cy_as_hal_print_message(
1175 "disk->node_id=0x%x\n",
1176 __func__
, (unsigned int)
1177 bd
->user_disk_0
->node_id
);
1181 add_disk(bd
->user_disk_0
);
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
;
1198 sprintf(bd
->user_disk_1
->disk_name
,
1199 "cyasblkdevblk%d", (devidx
+ 1));
1201 #ifndef WESTBRIDGE_NDEBUG
1202 cy_as_hal_print_message(
1203 "%s: disk unit_sz:%lu "
1209 unit_data
.desc_p
.unit_size
,
1210 unit_data
.desc_p
.block_size
,
1212 unit_data
.desc_p
.start_block
,
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",
1231 bd
->user_disk_0_blk_size
);
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",
1240 bd
->user_disk_1_blk_size
);
1244 set_capacity(bd
->user_disk_1
, disk_cap
);
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
);
1251 bd
->user_disk_1_first_sector
1255 add_disk(bd
->user_disk_1
);
1258 if (lcl_unit_no
> 0) {
1259 if (bd
->system_disk
== NULL
) {
1263 if (bd
->system_disk
== NULL
) {
1265 bd
= ERR_PTR(-ENOMEM
);
1268 disk_cap
= (uint64_t)
1269 (private_partition_size
);
1271 /* set properties of
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;
1287 bd
->system_disk
->disk_name
,
1288 "cyasblkdevblk%d", (devidx
+ 2));
1290 set_capacity(bd
->system_disk
,
1293 add_disk(bd
->system_disk
);
1295 #ifndef WESTBRIDGE_NDEBUG
1297 cy_as_hal_print_message(
1298 "%s: system disk already allocated %d\n",
1307 static struct cyasblkdev_blk_data
*cyasblkdev_blk_alloc(void)
1309 struct cyasblkdev_blk_data
*bd
;
1311 cy_as_return_status_t stat
= -1;
1313 int total_media_count
= 0;
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
);
1322 __set_bit(devidx
, dev_use
);
1323 __set_bit(devidx
+ 1, dev_use
);
1325 bd
= kzalloc(sizeof(struct cyasblkdev_blk_data
), GFP_KERNEL
);
1329 spin_lock_init(&bd
->lock
);
1332 /* setup the block_dev_ops pointer*/
1333 bd
->blkops
= &cyasblkdev_bdops
;
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__
);
1346 #ifndef WESTBRIDGE_NDEBUG
1347 cy_as_hal_print_message("%s west bridge device handle:%x\n",
1348 __func__
, (uint32_t)bd
->dev_handle
);
1351 /* start the storage api and get a handle to the
1352 * device we are interested in. */
1354 /* Error code to use if the conditions are not satisfied. */
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",
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",
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
);
1387 #ifndef WESTBRIDGE_NDEBUG
1388 cy_as_hal_print_message("%s: storage started:%d ok\n",
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
);
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
];
1409 #ifndef WESTBRIDGE_NDEBUG
1410 cy_as_hal_print_message("%s: cannot query %d, "
1411 "reason code: %d\n",
1412 __func__
, bus_num
, stat
);
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__
);
1424 } else if (total_media_count
>= 1) {
1425 if (bd
->user_disk_0
== NULL
) {
1429 if (bd
->user_disk_0
== NULL
) {
1431 bd
= ERR_PTR(-ENOMEM
);
1435 #ifndef WESTBRIDGE_NDEBUG
1437 cy_as_hal_print_message("%s: no available "
1438 "gen_disk for disk 0, "
1439 "physically inconsistent\n", __func__
);
1444 if (total_media_count
== 2) {
1445 if (bd
->user_disk_1
== NULL
) {
1448 if (bd
->user_disk_1
== NULL
) {
1450 bd
= ERR_PTR(-ENOMEM
);
1454 #ifndef WESTBRIDGE_NDEBUG
1456 cy_as_hal_print_message("%s: no available "
1457 "gen_disk for media, "
1458 "physically inconsistent\n", __func__
);
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
);
1469 #ifndef WESTBRIDGE_NDEBUG
1470 cy_as_hal_print_message("%s: %d device(s) found\n",
1471 __func__
, total_media_count
);
1474 for (bus_num
= 0; bus_num
<= 1; bus_num
++) {
1475 /*claim storage for cpu */
1476 stat
= cy_as_storage_claim(bd
->dev_handle
,
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
);
1485 dev_data
.bus
= bus_num
;
1486 dev_data
.device
= 0;
1488 stat
= cy_as_storage_query_device(bd
->dev_handle
,
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",
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
);
1508 } /* end for (bus_num = 0; bus_num <= 1; bus_num++)*/
1513 #ifndef WESTBRIDGE_NDEBUG
1514 cy_as_hal_print_message(
1515 "%s: bd failed to initialize\n", __func__
);
1524 /*init west bridge block device */
1525 static int cyasblkdev_blk_initialize(void)
1527 struct cyasblkdev_blk_data
*bd
;
1532 res
= register_blkdev(major
, "cyasblkdev");
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
);
1546 #ifndef WESTBRIDGE_NDEBUG
1547 cy_as_hal_print_message(
1548 "%s cyasblkdev registered with major number: %d\n",
1552 bd
= cyasblkdev_blk_alloc();
1559 /* start block device */
1560 static int __init
cyasblkdev_blk_init(void)
1566 /* get the cyasdev handle for future use*/
1567 cyas_dev_handle
= cyasdevice_getdevhandle();
1569 if (cyasblkdev_blk_initialize() == 0)
1572 #ifndef WESTBRIDGE_NDEBUG
1573 cy_as_hal_print_message("cyasblkdev init error:%d\n", res
);
1579 static void cyasblkdev_blk_deinit(struct cyasblkdev_blk_data
*bd
)
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
);
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
);
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
);
1607 cyasblkdev_blk_put(bd
);
1611 /* block device exit */
1612 static void __exit
cyasblkdev_blk_exit(void)
1616 cyasblkdev_blk_deinit(gl_bd
);
1617 unregister_blkdev(major
, "cyasblkdev");
1621 module_init(cyasblkdev_blk_init
);
1622 module_exit(cyasblkdev_blk_exit
);
1624 MODULE_LICENSE("GPL");
1625 MODULE_DESCRIPTION("antioch (cyasblkdev) block device driver");
1626 MODULE_AUTHOR("cypress semiconductor");