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