Linux/m68k driver for MNT ZZ9000
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

401 lines
9.7 KiB

  1. /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
  2. #include <linux/blk-mq.h>
  3. #include <linux/console.h>
  4. #include <linux/fs.h>
  5. #include <linux/module.h>
  6. #include <linux/string_helpers.h>
  7. #include <uapi/linux/cdrom.h>
  8. #include <uapi/linux/hdreg.h>
  9. #include <asm/div64.h>
  10. #include <asm/zorro.h>
  11. #include "zz9000.h"
  12. static struct zz9000_platform_data *zz9000_data;
  13. typedef struct {
  14. struct zz9000_platform_data *data;
  15. struct request_queue *queue;
  16. struct gendisk *disk;
  17. atomic_t open_counter;
  18. sector_t capacity;
  19. struct blk_mq_tag_set tag_set;
  20. } zz9000_usb_storage_t;
  21. static int zz9000_usb_open(struct block_device *bdev, fmode_t mode)
  22. {
  23. zz9000_usb_storage_t *dev = bdev->bd_disk->private_data;
  24. if (dev == NULL) {
  25. printk(KERN_WARNING "zz9000: USB: Invalid disk private_data in %s.\n", __func__);
  26. return -ENXIO;
  27. }
  28. atomic_inc(&dev->open_counter);
  29. pr_debug("zz9000: USB: Device was opened.\n");
  30. return 0;
  31. }
  32. static void zz9000_usb_release(struct gendisk *disk, fmode_t mode)
  33. {
  34. zz9000_usb_storage_t *dev = disk->private_data;
  35. if (dev) {
  36. atomic_dec(&dev->open_counter);
  37. pr_debug("zz9000: USB: Device was closed.\n");
  38. } else
  39. printk(KERN_WARNING "zz9000: USB: Invalid disk private_data in %s.\n", __func__);
  40. }
  41. static int zz9000_usb_getgeo(zz9000_usb_storage_t * dev,
  42. struct hd_geometry *geo)
  43. {
  44. sector_t quotient;
  45. geo->start = 0;
  46. if (dev->capacity > 63) {
  47. geo->sectors = 63;
  48. quotient = div_u64((dev->capacity + (63 - 1)), 63);
  49. if (quotient > 255) {
  50. geo->heads = 255;
  51. geo->cylinders = (unsigned short)(div_u64((quotient + (255 - 1)), 255));
  52. } else {
  53. geo->heads = (unsigned char)quotient;
  54. geo->cylinders = 1;
  55. }
  56. } else {
  57. // Is this really needed?
  58. geo->sectors = (unsigned char)dev->capacity;
  59. geo->cylinders = 1;
  60. geo->heads = 1;
  61. }
  62. return 0;
  63. }
  64. static int zz9000_usb_ioctl(struct block_device *bdev, fmode_t mode,
  65. unsigned int cmd, unsigned long arg)
  66. {
  67. int ret = -ENOTTY;
  68. zz9000_usb_storage_t *dev = bdev->bd_disk->private_data;
  69. pr_debug("zz9000: USB: ioctl %x received\n", cmd);
  70. switch (cmd) {
  71. case HDIO_GETGEO:
  72. {
  73. struct hd_geometry geo;
  74. ret = zz9000_usb_getgeo(dev, &geo);
  75. if (copy_to_user
  76. ((void *)arg, &geo, sizeof(struct hd_geometry)))
  77. ret = -EFAULT;
  78. else
  79. ret = 0;
  80. break;
  81. }
  82. case CDROM_GET_CAPABILITY: /* 0x5331 - get capability */
  83. {
  84. struct gendisk *disk = bdev->bd_disk;
  85. if (bdev->bd_disk && (disk->flags & GENHD_FL_CD))
  86. ret = 0;
  87. else
  88. ret = -EINVAL;
  89. break;
  90. }
  91. default:
  92. {
  93. printk(KERN_WARNING
  94. "zz9000: USB: ioctl %x not implemented.\n", cmd);
  95. ret = -EINVAL;
  96. }
  97. }
  98. return ret;
  99. }
  100. #ifdef CONFIG_COMPAT
  101. static int zz9000_usb_compat_ioctl(struct block_device *bdev, fmode_t mode,
  102. unsigned int cmd, unsigned long arg)
  103. {
  104. // CONFIG_COMPAT is to allow running 32-bit userspace code on a 64-bit kernel
  105. return -ENOTTY; // not supported
  106. }
  107. #endif
  108. static const struct block_device_operations zz9000_usb_fops = {
  109. .owner = THIS_MODULE,
  110. .open = zz9000_usb_open,
  111. .release = zz9000_usb_release,
  112. .ioctl = zz9000_usb_ioctl,
  113. #ifdef CONFIG_COMPAT
  114. .compat_ioctl = zz9000_usb_compat_ioctl,
  115. #endif
  116. };
  117. typedef struct {
  118. //nothing
  119. } zz9000_usb_cmd_t;
  120. static int zz9000_usb_read(zz9000_usb_storage_t *dev, void *b_buf, loff_t pos, unsigned long b_len)
  121. {
  122. struct zz9000_platform_data *data = dev->data;
  123. int ret = 0, i;
  124. pr_debug("read pos %lld len %ld\n", pos, b_len);
  125. zz_writew(b_len >> SECTOR_SHIFT, MNTZZ_USB_STATUS); //num_blocks;
  126. zz_writew((pos >> SECTOR_SHIFT) >> 16, MNTZZ_USB_RX_HI);
  127. zz_writew((pos >> SECTOR_SHIFT) & 0xffff, MNTZZ_USB_RX_LO);
  128. if (zz_readw(MNTZZ_USB_STATUS) != (b_len >> SECTOR_SHIFT))
  129. printk(KERN_WARNING "zz9000: USB: unexpected read status=%d(%d)\n",
  130. zz_readw(MNTZZ_USB_STATUS), (uint32_t)(b_len >> SECTOR_SHIFT));
  131. for (i = 0; i < (b_len >> SECTOR_SHIFT); i++) {
  132. zz_writew(i, MNTZZ_USB_BUFSEL);
  133. memcpy(b_buf + (i << SECTOR_SHIFT), data->usb_mem, 512);
  134. }
  135. return ret;
  136. }
  137. static int zz9000_usb_write(zz9000_usb_storage_t *dev, void *b_buf, loff_t pos, unsigned long b_len)
  138. {
  139. struct zz9000_platform_data *data = dev->data;
  140. int ret = 0, i;
  141. pr_debug("write pos %lld len %ld\n", pos, b_len);
  142. for (i = 0; i < (b_len >> SECTOR_SHIFT); i++) {
  143. zz_writew(i, MNTZZ_USB_BUFSEL);
  144. memcpy(data->usb_mem, b_buf + (i << SECTOR_SHIFT), 512);
  145. }
  146. zz_writew(b_len >> SECTOR_SHIFT, MNTZZ_USB_STATUS);
  147. zz_writew((pos >> SECTOR_SHIFT) >> 16, MNTZZ_USB_TX_HI);
  148. zz_writew((pos >> SECTOR_SHIFT) & 0xffff, MNTZZ_USB_TX_LO);
  149. if (zz_readw(MNTZZ_USB_STATUS) != (b_len >> SECTOR_SHIFT))
  150. printk(KERN_WARNING "zz9000: USB: unexpected write status=%d(%d)\n",
  151. zz_readw(MNTZZ_USB_STATUS), (uint32_t)(b_len >> SECTOR_SHIFT));
  152. return ret;
  153. }
  154. static int zz9000_usb_request(struct request *rq, unsigned int *nr_bytes)
  155. {
  156. int ret = 0;
  157. struct bio_vec bvec;
  158. struct req_iterator iter;
  159. zz9000_usb_storage_t *dev = rq->q->queuedata;
  160. loff_t pos = blk_rq_pos(rq) << SECTOR_SHIFT;
  161. loff_t dev_size = (loff_t) (dev->capacity << SECTOR_SHIFT);
  162. pr_debug("zz9000: USB: request start from sector %lld \n",
  163. blk_rq_pos(rq));
  164. rq_for_each_segment(bvec, rq, iter) {
  165. unsigned long b_len;
  166. void *b_buf;
  167. b_len = bvec.bv_len;
  168. b_buf = page_address(bvec.bv_page) + bvec.bv_offset;
  169. if ((pos + b_len) > dev_size)
  170. b_len = (unsigned long)(dev_size - pos);
  171. if (rq_data_dir(rq)) {
  172. pr_debug("zz9000: USB: Write\n");
  173. ret = zz9000_usb_write(dev, b_buf, pos, b_len);
  174. } else {
  175. pr_debug("zz9000: USB: Read\n");
  176. ret = zz9000_usb_read(dev, b_buf, pos, b_len);
  177. }
  178. pos += b_len;
  179. *nr_bytes += b_len;
  180. }
  181. return ret;
  182. }
  183. static blk_status_t zz9000_usb_queue_rq(struct blk_mq_hw_ctx *hctx,
  184. const struct blk_mq_queue_data *bd)
  185. {
  186. blk_status_t status = BLK_STS_OK;
  187. struct request *rq = bd->rq;
  188. blk_mq_start_request(rq);
  189. {
  190. unsigned int nr_bytes = 0;
  191. if (zz9000_usb_request(rq, &nr_bytes) != 0)
  192. status = BLK_STS_IOERR;
  193. pr_debug("zz9000: USB: request process %d bytes\n", nr_bytes);
  194. if (blk_update_request(rq, status, nr_bytes))
  195. BUG();
  196. __blk_mq_end_request(rq, status);
  197. }
  198. return BLK_STS_OK;
  199. }
  200. static struct blk_mq_ops zz9000_mq_ops = {
  201. .queue_rq = zz9000_usb_queue_rq,
  202. };
  203. int zz9000_usb_major = 0;
  204. static struct request_queue *zz9000_usb_queue;
  205. static zz9000_usb_storage_t *zz9000_usb_storage;
  206. int zz9000_usb_init(struct zz9000_platform_data *data)
  207. {
  208. zz9000_usb_storage_t *dev;
  209. int ret = 0;
  210. int usb_block_size = 512;
  211. unsigned int usb_capacity;
  212. char cap_str_2[10], cap_str_10[10];
  213. zz9000_data = data;
  214. usb_capacity = zz_readl(MNTZZ_USB_CAPACITY);
  215. if (usb_capacity == 0) {
  216. printk(KERN_INFO " USB device not found at boot.\n");
  217. return 0;
  218. }
  219. string_get_size(usb_capacity, usb_block_size,
  220. STRING_UNITS_2, cap_str_2, sizeof(cap_str_2));
  221. string_get_size(usb_capacity, usb_block_size,
  222. STRING_UNITS_10, cap_str_10, sizeof(cap_str_10));
  223. printk(KERN_INFO
  224. " USB capacity: %d %d-byte logical blocks: (%s GB/%s GiB)\n",
  225. usb_capacity, usb_block_size, cap_str_10, cap_str_2);
  226. /* Register block device */
  227. if ((zz9000_usb_major = register_blkdev(0, "zzusb")) <= 0)
  228. return -EIO;
  229. dev = kzalloc(sizeof(zz9000_usb_storage_t), GFP_KERNEL);
  230. if (dev == NULL) {
  231. printk(KERN_WARNING
  232. "zz9000: USB: Unable to allocate %zd bytes\n",
  233. sizeof(zz9000_usb_storage_t));
  234. return -ENOMEM;
  235. }
  236. dev->data = data;
  237. zz9000_usb_storage = dev;
  238. /* Remember capacity in blocks */
  239. dev->capacity = usb_capacity;
  240. /* configure tag_set */
  241. dev->tag_set.cmd_size = sizeof(zz9000_usb_cmd_t);
  242. dev->tag_set.driver_data = dev;
  243. zz9000_usb_queue =
  244. blk_mq_init_sq_queue(&dev->tag_set, &zz9000_mq_ops, 128,
  245. BLK_MQ_F_SHOULD_MERGE);
  246. if (IS_ERR(zz9000_usb_queue)) {
  247. ret = PTR_ERR(zz9000_usb_queue);
  248. printk(KERN_WARNING
  249. "zz9000: USB: Unable to allocate and initialize tag set\n");
  250. return -EIO;
  251. }
  252. dev->queue = zz9000_usb_queue;
  253. dev->queue->queuedata = dev;
  254. /* Set the hardware sector size and the max number of sectors */
  255. //blk_queue_hardsect_size(zz9000_usb_queue, usb_block_size);
  256. blk_queue_logical_block_size(zz9000_usb_queue, usb_block_size);
  257. blk_queue_max_hw_sectors(zz9000_usb_queue, 32);
  258. /* Allocate an associated gendisk */
  259. dev->disk = alloc_disk(16);
  260. if (dev->disk == NULL) {
  261. printk(KERN_WARNING "zz9000: USB: Failed to allocate disk\n");
  262. return -ENOMEM;
  263. }
  264. /* Fill in parameters associated with the gendisk */
  265. dev->disk->flags |= GENHD_FL_REMOVABLE;
  266. dev->disk->fops = &zz9000_usb_fops;
  267. dev->disk->queue = zz9000_usb_queue;
  268. dev->disk->major = zz9000_usb_major;
  269. dev->disk->first_minor = 0;
  270. dev->disk->private_data = dev;
  271. sprintf(dev->disk->disk_name, "zzusb");
  272. /* Set the capacity of USB storage media in number of sectors */
  273. set_capacity(dev->disk, usb_capacity);
  274. /* Add disk to the block I/O subsystem */
  275. add_disk(dev->disk);
  276. pr_debug("zz9000: USB block device was initialized.\n");
  277. return 0;
  278. }
  279. int zz9000_usb_remove(struct zz9000_platform_data *data)
  280. {
  281. zz9000_usb_storage_t *dev = zz9000_usb_storage;
  282. if (dev == NULL)
  283. return 0;
  284. if (dev->disk)
  285. del_gendisk(dev->disk);
  286. if (dev->queue) {
  287. blk_cleanup_queue(dev->queue);
  288. dev->queue = NULL;
  289. }
  290. if (dev->tag_set.tags)
  291. blk_mq_free_tag_set(&dev->tag_set);
  292. if (dev->disk) {
  293. put_disk(dev->disk);
  294. dev->disk = NULL;
  295. }
  296. kfree(dev);
  297. zz9000_usb_storage = NULL;
  298. if (zz9000_usb_major > 0)
  299. unregister_blkdev(zz9000_usb_major, "zzusb");
  300. pr_debug("zz9000: USB block device was removed.\n");
  301. return 0;
  302. }
  303. static int __init zz9000_usb_module_init(void)
  304. {
  305. struct zz9000_platform_data *data = get_zz9000_data();
  306. return zz9000_usb_init(data);
  307. }
  308. module_init(zz9000_usb_module_init);
  309. static void __exit zz9000_usb_module_exit(void)
  310. {
  311. struct zz9000_platform_data *data = get_zz9000_data();
  312. zz9000_usb_remove(data);
  313. }
  314. module_exit(zz9000_usb_module_exit);
  315. MODULE_DESCRIPTION("MNT ZZ9000 USB driver");
  316. MODULE_AUTHOR("Stefan Reinauer <stefan.reinauer@coreboot.org>");
  317. MODULE_LICENSE("GPL");