]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/westbridge/astoria/block/cyasblkdev_block.c
staging: Final semaphore cleanup
[net-next-2.6.git] / drivers / staging / westbridge / astoria / block / cyasblkdev_block.c
CommitLineData
81eb669b
DC
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
78static int major;
79module_param(major, int, 0444);
80MODULE_PARM_DESC(major,
81 "specify the major device number for cyasblkdev block driver");
82
83/* parameters passed from the user space */
84static int vfat_search;
85module_param(vfat_search, bool, S_IRUGO | S_IWUSR);
86MODULE_PARM_DESC(vfat_search,
87 "dynamically find the location of the first sector");
88
89static int private_partition_bus = -1;
90module_param(private_partition_bus, int, S_IRUGO | S_IWUSR);
91MODULE_PARM_DESC(private_partition_bus,
92 "bus number for private partition");
93
94static int private_partition_size = -1;
95module_param(private_partition_size, int, S_IRUGO | S_IWUSR);
96MODULE_PARM_DESC(private_partition_size,
97 "size of the private partition");
98
99/*
100 * There is one cyasblkdev_blk_data per slot.
101 */
102struct 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 */
0769c38d 158static struct cyasblkdev_blk_data *gl_bd;
81eb669b 159
45f4d024 160static DEFINE_SEMAPHORE(open_lock);
81eb669b
DC
161
162/* local forwardd declarationss */
163static cy_as_device_handle *cyas_dev_handle;
164static 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
171int 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}
185EXPORT_SYMBOL(blkdev_ctl_dbgprn);
186
187static 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(
0769c38d 206 "cyasblkdev_blk_get: usage = %d\n", bd->usage);
81eb669b
DC
207 #endif
208 }
209 up(&open_lock);
210
211 return bd;
212}
213
214static 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);
0769c38d 235 return;
81eb669b
DC
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(
0769c38d 248 "cyasblkdev: cannot release bus 0\n");
81eb669b
DC
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(
0769c38d 256 "cyasblkdev: cannot release bus 1\n");
81eb669b
DC
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(
0769c38d 264 "cyasblkdev: cannot stop storage stack\n");
81eb669b
DC
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 */
0769c38d 272 cy_as_hal_disable_scatter_list(cyasdevice_gethaltag());
81eb669b
DC
273 #endif
274
275 /*ptr to global struct cyasblkdev_blk_data */
0769c38d 276 gl_bd = NULL;
81eb669b
DC
277 kfree(bd);
278 }
279
280 #ifndef WESTBRIDGE_NDEBUG
281 cy_as_hal_print_message(
282 "cyasblkdev (blk_put): usage = %d\n",
0769c38d 283 bd->usage);
81eb669b
DC
284 #endif
285 up(&open_lock);
286}
287
288static 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
343static 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
356static 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/* Media_changed block_device opp
385 * this one is called by kernel to confirm if the media really changed
386 * as we indicated by issuing check_disk_change() call */
387int cyasblkdev_media_changed(struct gendisk *gd)
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 "1" yes, 0 no */
9bed00f2 406 return 0;
81eb669b
DC
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 */
412int 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 */
429static struct block_device_operations cyasblkdev_bdops = {
430 .open = cyasblkdev_blk_open,
431 .release = cyasblkdev_blk_release,
432 .ioctl = cyasblkdev_blk_ioctl,
433 /* .getgeo = cyasblkdev_blk_getgeo, */
434 /* added to support media removal( real and simulated) media */
435 .media_changed = cyasblkdev_media_changed,
436 /* added to support media removal( real and simulated) media */
437 .revalidate_disk = cyasblkdev_revalidate_disk,
438 .owner = THIS_MODULE,
439};
440
441/* west bridge block device prep request function */
442static 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 */
477static 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",
0769c38d 501 __func__, op, status, block_number);
81eb669b
DC
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,
0769c38d 510 (unsigned int) blk_rq_sectors(gl_bd->queue.req));
81eb669b
DC
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) */
557static int cyasblkdev_blk_issue_rq(
558 struct cyasblkdev_queue *bq,
559 struct request *req
560 )
561{
562 struct cyasblkdev_blk_data *bd = bq->data;
0769c38d 563 int index = 0;
81eb669b
DC
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
0769c38d 651 bq->req = NULL;
81eb669b
DC
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
0769c38d 672 bq->req = NULL;
81eb669b
DC
673 }
674 }
675
676 return ret;
677}
678
679static unsigned long
680dev_use[CYASBLKDEV_NUM_MINORS / (8 * sizeof(unsigned long))];
681
682
683/* storage event callback (note: called in astoria isr context) */
684static 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
714uint32_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(
0769c38d 744 "%s scanning media for vfat partition...\n", __func__);
81eb669b
DC
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
0769c38d 811cy_as_storage_query_device_data dev_data = {0};
81eb669b
DC
812
813static 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;
0769c38d 821 cy_as_storage_query_unit_data unit_data = {0};
81eb669b
DC
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(
0769c38d 846 bd->dev_handle, bus_num, 0, 0, 0);
81eb669b
DC
847 if (ret != CY_AS_ERROR_SUCCESS) {
848 #ifndef WESTBRIDGE_NDEBUG
849 cy_as_hal_print_message("%s cannot release"
0769c38d 850 " storage\n", __func__);
81eb669b
DC
851 #endif
852 goto out;
853 }
854 goto out;
855 }
856
0769c38d
DC
857 unit_data.device = 0;
858 unit_data.unit = 0;
81eb669b
DC
859 unit_data.bus = bus_num;
860 ret = cy_as_storage_query_unit(bd->dev_handle,
0769c38d 861 &unit_data, 0, 0);
81eb669b
DC
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",
0769c38d 866 __func__, bus_num, ret);
81eb669b 867 #endif
0769c38d 868 goto out;
81eb669b
DC
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) {
0769c38d
DC
909 unit_data.bus = bus_num;
910 unit_data.device = 0;
911 unit_data.unit = 1;
81eb669b
DC
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 "
0769c38d 917 "with error %d\n", __func__, ret);
81eb669b
DC
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 */
0769c38d
DC
925 unit_data.bus = bus_num;
926 unit_data.device = 0;
927 unit_data.unit = 0;
81eb669b
DC
928 }
929
930 ret = cy_as_storage_query_unit(
931 bd->dev_handle,
0769c38d 932 &unit_data, 0, 0);
81eb669b
DC
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",
0769c38d 938 __func__, bus_num, ret);
81eb669b 939 #endif
0769c38d 940 goto out;
81eb669b
DC
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
0769c38d
DC
955 unit_data.bus = bus_num;
956 unit_data.device = 0;
957 unit_data.unit = 1;
81eb669b
DC
958
959 ret = cy_as_storage_query_unit(
0769c38d 960 bd->dev_handle, &unit_data, 0, 0);
81eb669b
DC
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__,
0769c38d 967 bus_num, ret);
81eb669b 968 #endif
0769c38d 969 goto out;
81eb669b
DC
970 }
971
972 disk_cap = (uint64_t)
973 (unit_data.desc_p.unit_size);
974 lcl_unit_no =
0769c38d 975 unit_data.unit;
81eb669b
DC
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*/
0769c38d
DC
986 unit_data.bus = bus_num;
987 unit_data.device = 0;
988 unit_data.unit = 1;
81eb669b
DC
989
990 ret = cy_as_storage_query_unit(
0769c38d 991 bd->dev_handle, &unit_data, 0, 0);
81eb669b
DC
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",
0769c38d 998 __func__, bus_num, ret);
81eb669b 999 #endif
0769c38d 1000 goto out;
81eb669b
DC
1001 } else {
1002 disk_cap = (uint64_t)
1003 (unit_data.desc_p.unit_size);
0769c38d 1004 lcl_unit_no = unit_data.unit;
81eb669b
DC
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(
0769c38d 1070 &bd->queue, &bd->lock);
81eb669b
DC
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->private_data = bd;
1094 bd->user_disk_0->queue = bd->queue.queue;
1095 bd->dbgprn_flags = DBGPRN_RD_RQ;
1096 bd->user_disk_0_unit_no = lcl_unit_no;
1097
1098 blk_queue_logical_block_size(bd->queue.queue,
1099 bd->user_disk_0_blk_size);
1100
1101 set_capacity(bd->user_disk_0,
1102 disk_cap);
1103
1104 #ifndef WESTBRIDGE_NDEBUG
1105 cy_as_hal_print_message(
1106 "%s: returned from set_capacity %d\n",
1107 __func__, (int) disk_cap);
1108 #endif
1109
1110 /* need to start search from
1111 * public partition beginning */
1112 if (vfat_search) {
1113 bd->user_disk_0_first_sector =
9bed00f2
DC
1114 cyasblkdev_get_vfat_offset(
1115 bd->user_disk_0_bus_num,
81eb669b
DC
1116 bd->user_disk_0_unit_no);
1117 } else {
1118 bd->user_disk_0_first_sector = 0;
1119 }
1120
1121 #ifndef WESTBRIDGE_NDEBUG
1122 cy_as_hal_print_message(
1123 "%s: set user_disk_0_first "
1124 "sector to %d\n", __func__,
1125 bd->user_disk_0_first_sector);
1126 cy_as_hal_print_message(
1127 "%s: add_disk: disk->major=0x%x\n",
1128 __func__,
1129 bd->user_disk_0->major);
1130 cy_as_hal_print_message(
1131 "%s: add_disk: "
1132 "disk->first_minor=0x%x\n", __func__,
1133 bd->user_disk_0->first_minor);
1134 cy_as_hal_print_message(
1135 "%s: add_disk: "
1136 "disk->minors=0x%x\n", __func__,
1137 bd->user_disk_0->minors);
1138 cy_as_hal_print_message(
1139 "%s: add_disk: "
1140 "disk->disk_name=%s\n",
1141 __func__,
1142 bd->user_disk_0->disk_name);
1143 cy_as_hal_print_message(
1144 "%s: add_disk: "
1145 "disk->part_tbl=0x%x\n", __func__,
1146 (unsigned int)
1147 bd->user_disk_0->part_tbl);
1148 cy_as_hal_print_message(
1149 "%s: add_disk: "
1150 "disk->queue=0x%x\n", __func__,
1151 (unsigned int)
1152 bd->user_disk_0->queue);
1153 cy_as_hal_print_message(
1154 "%s: add_disk: "
1155 "disk->flags=0x%x\n",
1156 __func__, (unsigned int)
1157 bd->user_disk_0->flags);
1158 cy_as_hal_print_message(
1159 "%s: add_disk: "
1160 "disk->driverfs_dev=0x%x\n",
1161 __func__, (unsigned int)
1162 bd->user_disk_0->driverfs_dev);
1163 cy_as_hal_print_message(
1164 "%s: add_disk: "
1165 "disk->slave_dir=0x%x\n",
1166 __func__, (unsigned int)
1167 bd->user_disk_0->slave_dir);
1168 cy_as_hal_print_message(
1169 "%s: add_disk: "
1170 "disk->random=0x%x\n",
1171 __func__, (unsigned int)
1172 bd->user_disk_0->random);
1173 cy_as_hal_print_message(
1174 "%s: add_disk: "
1175 "disk->node_id=0x%x\n",
1176 __func__, (unsigned int)
1177 bd->user_disk_0->node_id);
1178
1179 #endif
1180
1181 add_disk(bd->user_disk_0);
1182
1183 } else if ((bus_num == 1) &&
1184 (total_media_count == 2)) {
1185 bd->user_disk_1_read_only = !dev_data.desc_p.writeable;
1186 bd->user_disk_1_blk_size = dev_data.desc_p.block_size;
1187 bd->user_disk_1_type = dev_data.desc_p.type;
1188 bd->user_disk_1_bus_num = bus_num;
1189 bd->user_disk_1->major = major;
1190 bd->user_disk_1->first_minor = (devidx + 1) << CYASBLKDEV_SHIFT;
1191 bd->user_disk_1->minors = 8;
1192 bd->user_disk_1->fops = &cyasblkdev_bdops;
1193 bd->user_disk_1->private_data = bd;
1194 bd->user_disk_1->queue = bd->queue.queue;
1195 bd->dbgprn_flags = DBGPRN_RD_RQ;
1196 bd->user_disk_1_unit_no = lcl_unit_no;
1197
1198 sprintf(bd->user_disk_1->disk_name,
1199 "cyasblkdevblk%d", (devidx + 1));
1200
1201 #ifndef WESTBRIDGE_NDEBUG
1202 cy_as_hal_print_message(
1203 "%s: disk unit_sz:%lu "
1204 "blk_sz:%d, "
1205 "start_blk:%lu, "
1206 "capacity:%llu\n",
1207 __func__,
1208 (unsigned long)
1209 unit_data.desc_p.unit_size,
1210 unit_data.desc_p.block_size,
1211 (unsigned long)
1212 unit_data.desc_p.start_block,
1213 (uint64_t)disk_cap
1214 );
1215 #endif
1216
1217 /*blk_size should always be a
1218 * multiple of 512, set to the max
1219 * to ensure that all accesses
1220 * aligned to the greatest multiple,
1221 * can adjust request to smaller
1222 * block sizes dynamically*/
1223 if (bd->user_disk_0_blk_size >
1224 bd->user_disk_1_blk_size) {
1225 blk_queue_logical_block_size(bd->queue.queue,
1226 bd->user_disk_0_blk_size);
1227 #ifndef WESTBRIDGE_NDEBUG
1228 cy_as_hal_print_message(
1229 "%s: set hard sect_sz:%d\n",
1230 __func__,
1231 bd->user_disk_0_blk_size);
1232 #endif
1233 } else {
1234 blk_queue_logical_block_size(bd->queue.queue,
1235 bd->user_disk_1_blk_size);
1236 #ifndef WESTBRIDGE_NDEBUG
1237 cy_as_hal_print_message(
1238 "%s: set hard sect_sz:%d\n",
1239 __func__,
1240 bd->user_disk_1_blk_size);
1241 #endif
1242 }
1243
1244 set_capacity(bd->user_disk_1, disk_cap);
1245 if (vfat_search) {
1246 bd->user_disk_1_first_sector =
1247 cyasblkdev_get_vfat_offset(
9bed00f2
DC
1248 bd->user_disk_1_bus_num,
1249 bd->user_disk_1_unit_no);
81eb669b
DC
1250 } else {
1251 bd->user_disk_1_first_sector
1252 = 0;
1253 }
1254
1255 add_disk(bd->user_disk_1);
1256 }
1257
1258 if (lcl_unit_no > 0) {
1259 if (bd->system_disk == NULL) {
1260 bd->system_disk =
9bed00f2
DC
1261 alloc_disk(8);
1262
81eb669b
DC
1263 if (bd->system_disk == NULL) {
1264 kfree(bd);
1265 bd = ERR_PTR(-ENOMEM);
0769c38d 1266 return bd;
81eb669b
DC
1267 }
1268 disk_cap = (uint64_t)
1269 (private_partition_size);
1270
1271 /* set properties of
1272 * system disk */
1273 bd->system_disk_read_only = !dev_data.desc_p.writeable;
1274 bd->system_disk_blk_size = dev_data.desc_p.block_size;
1275 bd->system_disk_bus_num = bus_num;
1276 bd->system_disk->major = major;
1277 bd->system_disk->first_minor =
1278 (devidx + 2) << CYASBLKDEV_SHIFT;
1279 bd->system_disk->minors = 8;
1280 bd->system_disk->fops = &cyasblkdev_bdops;
1281 bd->system_disk->private_data = bd;
1282 bd->system_disk->queue = bd->queue.queue;
1283 /* don't search for vfat
1284 * with system disk */
1285 bd->system_disk_first_sector = 0;
1286 sprintf(
1287 bd->system_disk->disk_name,
1288 "cyasblkdevblk%d", (devidx + 2));
1289
1290 set_capacity(bd->system_disk,
1291 disk_cap);
1292
1293 add_disk(bd->system_disk);
1294 }
1295 #ifndef WESTBRIDGE_NDEBUG
1296 else {
1297 cy_as_hal_print_message(
1298 "%s: system disk already allocated %d\n",
0769c38d 1299 __func__, bus_num);
81eb669b
DC
1300 }
1301 #endif
1302 }
1303out:
1304 return ret;
1305}
1306
1307static struct cyasblkdev_blk_data *cyasblkdev_blk_alloc(void)
1308{
1309 struct cyasblkdev_blk_data *bd;
0769c38d
DC
1310 int ret = 0;
1311 cy_as_return_status_t stat = -1;
81eb669b
DC
1312 int bus_num = 0;
1313 int total_media_count = 0;
1314 int devidx = 0;
1315 DBGPRN_FUNC_NAME;
1316
1317 total_media_count = 0;
1318 devidx = find_first_zero_bit(dev_use, CYASBLKDEV_NUM_MINORS);
1319 if (devidx >= CYASBLKDEV_NUM_MINORS)
1320 return ERR_PTR(-ENOSPC);
1321
1322 __set_bit(devidx, dev_use);
1323 __set_bit(devidx + 1, dev_use);
1324
1325 bd = kzalloc(sizeof(struct cyasblkdev_blk_data), GFP_KERNEL);
1326 if (bd) {
0769c38d 1327 gl_bd = bd;
81eb669b
DC
1328
1329 spin_lock_init(&bd->lock);
1330 bd->usage = 1;
1331
1332 /* setup the block_dev_ops pointer*/
1333 bd->blkops = &cyasblkdev_bdops;
1334
1335 /* Get the device handle */
0769c38d 1336 bd->dev_handle = cyasdevice_getdevhandle();
81eb669b
DC
1337 if (0 == bd->dev_handle) {
1338 #ifndef WESTBRIDGE_NDEBUG
1339 cy_as_hal_print_message(
0769c38d 1340 "%s: get device failed\n", __func__);
81eb669b 1341 #endif
0769c38d
DC
1342 ret = ENODEV;
1343 goto out;
81eb669b
DC
1344 }
1345
1346 #ifndef WESTBRIDGE_NDEBUG
1347 cy_as_hal_print_message("%s west bridge device handle:%x\n",
1348 __func__, (uint32_t)bd->dev_handle);
1349 #endif
1350
1351 /* start the storage api and get a handle to the
1352 * device we are interested in. */
1353
1354 /* Error code to use if the conditions are not satisfied. */
0769c38d 1355 ret = ENOMEDIUM;
81eb669b
DC
1356
1357 stat = cy_as_misc_release_resource(bd->dev_handle, cy_as_bus_0);
1358 if ((stat != CY_AS_ERROR_SUCCESS) &&
1359 (stat != CY_AS_ERROR_RESOURCE_NOT_OWNED)) {
1360 #ifndef WESTBRIDGE_NDEBUG
1361 cy_as_hal_print_message("%s: cannot release "
1362 "resource bus 0 - reason code %d\n",
0769c38d 1363 __func__, stat);
81eb669b
DC
1364 #endif
1365 }
1366
1367 stat = cy_as_misc_release_resource(bd->dev_handle, cy_as_bus_1);
1368 if ((stat != CY_AS_ERROR_SUCCESS) &&
1369 (stat != CY_AS_ERROR_RESOURCE_NOT_OWNED)) {
1370 #ifndef WESTBRIDGE_NDEBUG
1371 cy_as_hal_print_message("%s: cannot release "
1372 "resource bus 0 - reason code %d\n",
0769c38d 1373 __func__, stat);
81eb669b
DC
1374 #endif
1375 }
1376
1377 /* start storage stack*/
0769c38d 1378 stat = cy_as_storage_start(bd->dev_handle, 0, 0x101);
81eb669b
DC
1379 if (stat != CY_AS_ERROR_SUCCESS) {
1380 #ifndef WESTBRIDGE_NDEBUG
1381 cy_as_hal_print_message("%s: cannot start storage "
0769c38d 1382 "stack - reason code %d\n", __func__, stat);
81eb669b
DC
1383 #endif
1384 goto out;
1385 }
1386
1387 #ifndef WESTBRIDGE_NDEBUG
1388 cy_as_hal_print_message("%s: storage started:%d ok\n",
1389 __func__, stat);
1390 #endif
1391
1392 stat = cy_as_storage_register_callback(bd->dev_handle,
1393 cyasblkdev_storage_callback);
1394 if (stat != CY_AS_ERROR_SUCCESS) {
1395 #ifndef WESTBRIDGE_NDEBUG
1396 cy_as_hal_print_message("%s: cannot register callback "
0769c38d 1397 "- reason code %d\n", __func__, stat);
81eb669b
DC
1398 #endif
1399 goto out;
1400 }
1401
1402 for (bus_num = 0; bus_num < 2; bus_num++) {
1403 stat = cy_as_storage_query_bus(bd->dev_handle,
0769c38d 1404 bus_num, &bd->media_count[bus_num], 0, 0);
81eb669b
DC
1405 if (stat == CY_AS_ERROR_SUCCESS) {
1406 total_media_count = total_media_count +
1407 bd->media_count[bus_num];
1408 } else {
1409 #ifndef WESTBRIDGE_NDEBUG
1410 cy_as_hal_print_message("%s: cannot query %d, "
1411 "reason code: %d\n",
0769c38d 1412 __func__, bus_num, stat);
81eb669b
DC
1413 #endif
1414 goto out;
1415 }
1416 }
1417
1418 if (total_media_count == 0) {
1419 #ifndef WESTBRIDGE_NDEBUG
1420 cy_as_hal_print_message(
0769c38d 1421 "%s: no storage media was found\n", __func__);
81eb669b 1422 #endif
0769c38d 1423 goto out;
81eb669b
DC
1424 } else if (total_media_count >= 1) {
1425 if (bd->user_disk_0 == NULL) {
1426
1427 bd->user_disk_0 =
9bed00f2 1428 alloc_disk(8);
81eb669b
DC
1429 if (bd->user_disk_0 == NULL) {
1430 kfree(bd);
1431 bd = ERR_PTR(-ENOMEM);
0769c38d 1432 return bd;
81eb669b
DC
1433 }
1434 }
1435 #ifndef WESTBRIDGE_NDEBUG
1436 else {
1437 cy_as_hal_print_message("%s: no available "
1438 "gen_disk for disk 0, "
1439 "physically inconsistent\n", __func__);
1440 }
1441 #endif
1442 }
1443
1444 if (total_media_count == 2) {
1445 if (bd->user_disk_1 == NULL) {
1446 bd->user_disk_1 =
9bed00f2 1447 alloc_disk(8);
81eb669b
DC
1448 if (bd->user_disk_1 == NULL) {
1449 kfree(bd);
1450 bd = ERR_PTR(-ENOMEM);
0769c38d 1451 return bd;
81eb669b
DC
1452 }
1453 }
1454 #ifndef WESTBRIDGE_NDEBUG
1455 else {
1456 cy_as_hal_print_message("%s: no available "
1457 "gen_disk for media, "
1458 "physically inconsistent\n", __func__);
1459 }
1460 #endif
1461 }
1462 #ifndef WESTBRIDGE_NDEBUG
1463 else if (total_media_count > 2) {
1464 cy_as_hal_print_message("%s: count corrupted = 0x%d\n",
1465 __func__, total_media_count);
1466 }
1467 #endif
1468
1469 #ifndef WESTBRIDGE_NDEBUG
1470 cy_as_hal_print_message("%s: %d device(s) found\n",
0769c38d 1471 __func__, total_media_count);
81eb669b
DC
1472 #endif
1473
1474 for (bus_num = 0; bus_num <= 1; bus_num++) {
1475 /*claim storage for cpu */
1476 stat = cy_as_storage_claim(bd->dev_handle,
0769c38d 1477 bus_num, 0, 0, 0);
81eb669b
DC
1478 if (stat != CY_AS_ERROR_SUCCESS) {
1479 cy_as_hal_print_message("%s: cannot claim "
1480 "%d bus - reason code %d\n",
0769c38d 1481 __func__, bus_num, stat);
81eb669b
DC
1482 goto out;
1483 }
1484
0769c38d
DC
1485 dev_data.bus = bus_num;
1486 dev_data.device = 0;
81eb669b
DC
1487
1488 stat = cy_as_storage_query_device(bd->dev_handle,
0769c38d 1489 &dev_data, 0, 0);
81eb669b
DC
1490 if (stat == CY_AS_ERROR_SUCCESS) {
1491 cyasblkdev_add_disks(bus_num, bd,
1492 total_media_count, devidx);
1493 } else if (stat == CY_AS_ERROR_NO_SUCH_DEVICE) {
1494 #ifndef WESTBRIDGE_NDEBUG
1495 cy_as_hal_print_message(
1496 "%s: no device on bus %d\n",
0769c38d 1497 __func__, bus_num);
81eb669b
DC
1498 #endif
1499 } else {
1500 #ifndef WESTBRIDGE_NDEBUG
1501 cy_as_hal_print_message(
1502 "%s: cannot query %d device "
1503 "- reason code %d\n",
0769c38d 1504 __func__, bus_num, stat);
81eb669b 1505 #endif
0769c38d 1506 goto out;
81eb669b
DC
1507 }
1508 } /* end for (bus_num = 0; bus_num <= 1; bus_num++)*/
1509
0769c38d 1510 return bd;
81eb669b
DC
1511 }
1512out:
1513 #ifndef WESTBRIDGE_NDEBUG
1514 cy_as_hal_print_message(
1515 "%s: bd failed to initialize\n", __func__);
1516 #endif
1517
1518 kfree(bd);
1519 bd = ERR_PTR(-ret);
1520 return bd;
1521}
1522
1523
1524/*init west bridge block device */
1525static int cyasblkdev_blk_initialize(void)
1526{
1527 struct cyasblkdev_blk_data *bd;
1528 int res;
1529
1530 DBGPRN_FUNC_NAME;
1531
1532 res = register_blkdev(major, "cyasblkdev");
1533
1534 if (res < 0) {
1535 #ifndef WESTBRIDGE_NDEBUG
1536 cy_as_hal_print_message(KERN_WARNING
1537 "%s unable to get major %d for cyasblkdev media: %d\n",
1538 __func__, major, res);
1539 #endif
1540 return res;
1541 }
1542
1543 if (major == 0)
1544 major = res;
1545
1546 #ifndef WESTBRIDGE_NDEBUG
1547 cy_as_hal_print_message(
1548 "%s cyasblkdev registered with major number: %d\n",
0769c38d 1549 __func__, major);
81eb669b
DC
1550 #endif
1551
1552 bd = cyasblkdev_blk_alloc();
1553 if (IS_ERR(bd))
1554 return PTR_ERR(bd);
1555
1556 return 0;
1557}
1558
1559/* start block device */
1560static int __init cyasblkdev_blk_init(void)
1561{
1562 int res = -ENOMEM;
1563
1564 DBGPRN_FUNC_NAME;
1565
1566 /* get the cyasdev handle for future use*/
1567 cyas_dev_handle = cyasdevice_getdevhandle();
1568
1569 if (cyasblkdev_blk_initialize() == 0)
1570 return 0;
1571
1572 #ifndef WESTBRIDGE_NDEBUG
1573 cy_as_hal_print_message("cyasblkdev init error:%d\n", res);
1574 #endif
1575 return res;
1576}
1577
1578
1579static void cyasblkdev_blk_deinit(struct cyasblkdev_blk_data *bd)
1580{
1581 DBGPRN_FUNC_NAME;
1582
1583 if (bd) {
1584 int devidx;
1585
1586 if (bd->user_disk_0 != NULL) {
1587 del_gendisk(bd->user_disk_0);
1588 devidx = bd->user_disk_0->first_minor
1589 >> CYASBLKDEV_SHIFT;
1590 __clear_bit(devidx, dev_use);
1591 }
1592
1593 if (bd->user_disk_1 != NULL) {
1594 del_gendisk(bd->user_disk_1);
1595 devidx = bd->user_disk_1->first_minor
1596 >> CYASBLKDEV_SHIFT;
1597 __clear_bit(devidx, dev_use);
1598 }
1599
1600 if (bd->system_disk != NULL) {
1601 del_gendisk(bd->system_disk);
1602 devidx = bd->system_disk->first_minor
1603 >> CYASBLKDEV_SHIFT;
1604 __clear_bit(devidx, dev_use);
1605 }
1606
1607 cyasblkdev_blk_put(bd);
1608 }
1609}
1610
1611/* block device exit */
1612static void __exit cyasblkdev_blk_exit(void)
1613{
1614 DBGPRN_FUNC_NAME;
1615
1616 cyasblkdev_blk_deinit(gl_bd);
1617 unregister_blkdev(major, "cyasblkdev");
1618
1619}
1620
1621module_init(cyasblkdev_blk_init);
1622module_exit(cyasblkdev_blk_exit);
1623
1624MODULE_LICENSE("GPL");
1625MODULE_DESCRIPTION("antioch (cyasblkdev) block device driver");
1626MODULE_AUTHOR("cypress semiconductor");
1627
1628/*[]*/