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