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 DECLARE_MUTEX(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");