viodasd.c
上传用户:ajay2009
上传日期:2009-05-22
资源大小:495k
文件大小:22k
源码类别:

驱动编程

开发平台:

Unix_Linux

  1. /* -*- linux-c -*-
  2.  * viodasd.c
  3.  *  Authors: Dave Boutcher <boutcher@us.ibm.com>
  4.  *           Ryan Arnold <ryanarn@us.ibm.com>
  5.  *           Colin Devilbiss <devilbis@us.ibm.com>
  6.  *           Stephen Rothwell <sfr@au1.ibm.com>
  7.  *
  8.  * (C) Copyright 2000-2004 IBM Corporation
  9.  *
  10.  * This program is free software; you can redistribute it and/or
  11.  * modify it under the terms of the GNU General Public License as
  12.  * published by the Free Software Foundation; either version 2 of the
  13.  * License, or (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23.  *
  24.  * This routine provides access to disk space (termed "DASD" in historical
  25.  * IBM terms) owned and managed by an OS/400 partition running on the
  26.  * same box as this Linux partition.
  27.  *
  28.  * All disk operations are performed by sending messages back and forth to
  29.  * the OS/400 partition.
  30.  */
  31. #include <linux/major.h>
  32. #include <linux/fs.h>
  33. #include <linux/module.h>
  34. #include <linux/kernel.h>
  35. #include <linux/blkdev.h>
  36. #include <linux/genhd.h>
  37. #include <linux/hdreg.h>
  38. #include <linux/errno.h>
  39. #include <linux/init.h>
  40. #include <linux/string.h>
  41. #include <linux/dma-mapping.h>
  42. #include <linux/completion.h>
  43. #include <linux/device.h>
  44. #include <linux/kernel.h>
  45. #include <asm/uaccess.h>
  46. #include <asm/vio.h>
  47. #include <asm/iSeries/HvTypes.h>
  48. #include <asm/iSeries/HvLpEvent.h>
  49. #include <asm/iSeries/HvLpConfig.h>
  50. #include <asm/iSeries/vio.h>
  51. MODULE_DESCRIPTION("iSeries Virtual DASD");
  52. MODULE_AUTHOR("Dave Boutcher");
  53. MODULE_LICENSE("GPL");
  54. /*
  55.  * We only support 7 partitions per physical disk....so with minor
  56.  * numbers 0-255 we get a maximum of 32 disks.
  57.  */
  58. #define VIOD_GENHD_NAME "iseries/vd"
  59. #define VIOD_GENHD_DEVFS_NAME "iseries/disc"
  60. #define VIOD_VERS "1.64"
  61. #define VIOD_KERN_WARNING KERN_WARNING "viod: "
  62. #define VIOD_KERN_INFO KERN_INFO "viod: "
  63. enum {
  64. PARTITION_SHIFT = 3,
  65. MAX_DISKNO = HVMAXARCHITECTEDVIRTUALDISKS,
  66. MAX_DISK_NAME = sizeof(((struct gendisk *)0)->disk_name)
  67. };
  68. static DEFINE_SPINLOCK(viodasd_spinlock);
  69. #define VIOMAXREQ 16
  70. #define VIOMAXBLOCKDMA 12
  71. #define DEVICE_NO(cell) ((struct viodasd_device *)(cell) - &viodasd_devices[0])
  72. struct open_data {
  73. u64 disk_size;
  74. u16 max_disk;
  75. u16 cylinders;
  76. u16 tracks;
  77. u16 sectors;
  78. u16 bytes_per_sector;
  79. };
  80. struct rw_data {
  81. u64 offset;
  82. struct {
  83. u32 token;
  84. u32 reserved;
  85. u64 len;
  86. } dma_info[VIOMAXBLOCKDMA];
  87. };
  88. struct vioblocklpevent {
  89. struct HvLpEvent event;
  90. u32 reserved;
  91. u16 version;
  92. u16 sub_result;
  93. u16 disk;
  94. u16 flags;
  95. union {
  96. struct open_data open_data;
  97. struct rw_data rw_data;
  98. u64 changed;
  99. } u;
  100. };
  101. #define vioblockflags_ro   0x0001
  102. enum vioblocksubtype {
  103. vioblockopen = 0x0001,
  104. vioblockclose = 0x0002,
  105. vioblockread = 0x0003,
  106. vioblockwrite = 0x0004,
  107. vioblockflush = 0x0005,
  108. vioblockcheck = 0x0007
  109. };
  110. struct viodasd_waitevent {
  111. struct completion com;
  112. int rc;
  113. u16 sub_result;
  114. int max_disk; /* open */
  115. };
  116. static const struct vio_error_entry viodasd_err_table[] = {
  117. { 0x0201, EINVAL, "Invalid Range" },
  118. { 0x0202, EINVAL, "Invalid Token" },
  119. { 0x0203, EIO, "DMA Error" },
  120. { 0x0204, EIO, "Use Error" },
  121. { 0x0205, EIO, "Release Error" },
  122. { 0x0206, EINVAL, "Invalid Disk" },
  123. { 0x0207, EBUSY, "Cant Lock" },
  124. { 0x0208, EIO, "Already Locked" },
  125. { 0x0209, EIO, "Already Unlocked" },
  126. { 0x020A, EIO, "Invalid Arg" },
  127. { 0x020B, EIO, "Bad IFS File" },
  128. { 0x020C, EROFS, "Read Only Device" },
  129. { 0x02FF, EIO, "Internal Error" },
  130. { 0x0000, 0, NULL },
  131. };
  132. /*
  133.  * Figure out the biggest I/O request (in sectors) we can accept
  134.  */
  135. #define VIODASD_MAXSECTORS (4096 / 512 * VIOMAXBLOCKDMA)
  136. /*
  137.  * Number of disk I/O requests we've sent to OS/400
  138.  */
  139. static int num_req_outstanding;
  140. /*
  141.  * This is our internal structure for keeping track of disk devices
  142.  */
  143. struct viodasd_device {
  144. u16 cylinders;
  145. u16 tracks;
  146. u16 sectors;
  147. u16 bytes_per_sector;
  148. u64 size;
  149. int read_only;
  150. spinlock_t q_lock;
  151. struct gendisk *disk;
  152. struct device *dev;
  153. } viodasd_devices[MAX_DISKNO];
  154. /*
  155.  * External open entry point.
  156.  */
  157. static int viodasd_open(struct inode *ino, struct file *fil)
  158. {
  159. struct viodasd_device *d = ino->i_bdev->bd_disk->private_data;
  160. HvLpEvent_Rc hvrc;
  161. struct viodasd_waitevent we;
  162. u16 flags = 0;
  163. if (d->read_only) {
  164. if ((fil != NULL) && (fil->f_mode & FMODE_WRITE))
  165. return -EROFS;
  166. flags = vioblockflags_ro;
  167. }
  168. init_completion(&we.com);
  169. /* Send the open event to OS/400 */
  170. hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
  171. HvLpEvent_Type_VirtualIo,
  172. viomajorsubtype_blockio | vioblockopen,
  173. HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
  174. viopath_sourceinst(viopath_hostLp),
  175. viopath_targetinst(viopath_hostLp),
  176. (u64)(unsigned long)&we, VIOVERSION << 16,
  177. ((u64)DEVICE_NO(d) << 48) | ((u64)flags << 32),
  178. 0, 0, 0);
  179. if (hvrc != 0) {
  180. printk(VIOD_KERN_WARNING "HV open failed %dn", (int)hvrc);
  181. return -EIO;
  182. }
  183. wait_for_completion(&we.com);
  184. /* Check the return code */
  185. if (we.rc != 0) {
  186. const struct vio_error_entry *err =
  187. vio_lookup_rc(viodasd_err_table, we.sub_result);
  188. printk(VIOD_KERN_WARNING
  189. "bad rc opening disk: %d:0x%04x (%s)n",
  190. (int)we.rc, we.sub_result, err->msg);
  191. return -EIO;
  192. }
  193. return 0;
  194. }
  195. /*
  196.  * External release entry point.
  197.  */
  198. static int viodasd_release(struct inode *ino, struct file *fil)
  199. {
  200. struct viodasd_device *d = ino->i_bdev->bd_disk->private_data;
  201. HvLpEvent_Rc hvrc;
  202. /* Send the event to OS/400.  We DON'T expect a response */
  203. hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
  204. HvLpEvent_Type_VirtualIo,
  205. viomajorsubtype_blockio | vioblockclose,
  206. HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
  207. viopath_sourceinst(viopath_hostLp),
  208. viopath_targetinst(viopath_hostLp),
  209. 0, VIOVERSION << 16,
  210. ((u64)DEVICE_NO(d) << 48) /* | ((u64)flags << 32) */,
  211. 0, 0, 0);
  212. if (hvrc != 0)
  213. printk(VIOD_KERN_WARNING "HV close call failed %dn",
  214. (int)hvrc);
  215. return 0;
  216. }
  217. /* External ioctl entry point.
  218.  */
  219. static int viodasd_ioctl(struct inode *ino, struct file *fil,
  220.  unsigned int cmd, unsigned long arg)
  221. {
  222. unsigned char sectors;
  223. unsigned char heads;
  224. unsigned short cylinders;
  225. struct hd_geometry *geo;
  226. struct gendisk *gendisk;
  227. struct viodasd_device *d;
  228. switch (cmd) {
  229. case HDIO_GETGEO:
  230. geo = (struct hd_geometry *)arg;
  231. if (geo == NULL)
  232. return -EINVAL;
  233. if (!access_ok(VERIFY_WRITE, geo, sizeof(*geo)))
  234. return -EFAULT;
  235. gendisk = ino->i_bdev->bd_disk;
  236. d = gendisk->private_data;
  237. sectors = d->sectors;
  238. if (sectors == 0)
  239. sectors = 32;
  240. heads = d->tracks;
  241. if (heads == 0)
  242. heads = 64;
  243. cylinders = d->cylinders;
  244. if (cylinders == 0)
  245. cylinders = get_capacity(gendisk) / (sectors * heads);
  246. if (__put_user(sectors, &geo->sectors) ||
  247.     __put_user(heads, &geo->heads) ||
  248.     __put_user(cylinders, &geo->cylinders) ||
  249.     __put_user(get_start_sect(ino->i_bdev), &geo->start))
  250. return -EFAULT;
  251. return 0;
  252. }
  253. return -EINVAL;
  254. }
  255. /*
  256.  * Our file operations table
  257.  */
  258. static struct block_device_operations viodasd_fops = {
  259. .owner = THIS_MODULE,
  260. .open = viodasd_open,
  261. .release = viodasd_release,
  262. .ioctl = viodasd_ioctl,
  263. };
  264. /*
  265.  * End a request
  266.  */
  267. static void viodasd_end_request(struct request *req, int uptodate,
  268. int num_sectors)
  269. {
  270. if (end_that_request_first(req, uptodate, num_sectors))
  271. return;
  272. add_disk_randomness(req->rq_disk);
  273. end_that_request_last(req);
  274. }
  275. /*
  276.  * Send an actual I/O request to OS/400
  277.  */
  278. static int send_request(struct request *req)
  279. {
  280. u64 start;
  281. int direction;
  282. int nsg;
  283. u16 viocmd;
  284. HvLpEvent_Rc hvrc;
  285. struct vioblocklpevent *bevent;
  286. struct scatterlist sg[VIOMAXBLOCKDMA];
  287. int sgindex;
  288. int statindex;
  289. struct viodasd_device *d;
  290. unsigned long flags;
  291. start = (u64)req->sector << 9;
  292. if (rq_data_dir(req) == READ) {
  293. direction = DMA_FROM_DEVICE;
  294. viocmd = viomajorsubtype_blockio | vioblockread;
  295. statindex = 0;
  296. } else {
  297. direction = DMA_TO_DEVICE;
  298. viocmd = viomajorsubtype_blockio | vioblockwrite;
  299. statindex = 1;
  300. }
  301.         d = req->rq_disk->private_data;
  302. /* Now build the scatter-gather list */
  303. nsg = blk_rq_map_sg(req->q, req, sg);
  304. nsg = dma_map_sg(d->dev, sg, nsg, direction);
  305. spin_lock_irqsave(&viodasd_spinlock, flags);
  306. num_req_outstanding++;
  307. /* This optimization handles a single DMA block */
  308. if (nsg == 1)
  309. hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
  310. HvLpEvent_Type_VirtualIo, viocmd,
  311. HvLpEvent_AckInd_DoAck,
  312. HvLpEvent_AckType_ImmediateAck,
  313. viopath_sourceinst(viopath_hostLp),
  314. viopath_targetinst(viopath_hostLp),
  315. (u64)(unsigned long)req, VIOVERSION << 16,
  316. ((u64)DEVICE_NO(d) << 48), start,
  317. ((u64)sg_dma_address(&sg[0])) << 32,
  318. sg_dma_len(&sg[0]));
  319. else {
  320. bevent = (struct vioblocklpevent *)
  321. vio_get_event_buffer(viomajorsubtype_blockio);
  322. if (bevent == NULL) {
  323. printk(VIOD_KERN_WARNING
  324.        "error allocating disk event buffern");
  325. goto error_ret;
  326. }
  327. /*
  328.  * Now build up the actual request.  Note that we store
  329.  * the pointer to the request in the correlation
  330.  * token so we can match the response up later
  331.  */
  332. memset(bevent, 0, sizeof(struct vioblocklpevent));
  333. bevent->event.xFlags.xValid = 1;
  334. bevent->event.xFlags.xFunction = HvLpEvent_Function_Int;
  335. bevent->event.xFlags.xAckInd = HvLpEvent_AckInd_DoAck;
  336. bevent->event.xFlags.xAckType = HvLpEvent_AckType_ImmediateAck;
  337. bevent->event.xType = HvLpEvent_Type_VirtualIo;
  338. bevent->event.xSubtype = viocmd;
  339. bevent->event.xSourceLp = HvLpConfig_getLpIndex();
  340. bevent->event.xTargetLp = viopath_hostLp;
  341. bevent->event.xSizeMinus1 =
  342. offsetof(struct vioblocklpevent, u.rw_data.dma_info) +
  343. (sizeof(bevent->u.rw_data.dma_info[0]) * nsg) - 1;
  344. bevent->event.xSourceInstanceId =
  345. viopath_sourceinst(viopath_hostLp);
  346. bevent->event.xTargetInstanceId =
  347. viopath_targetinst(viopath_hostLp);
  348. bevent->event.xCorrelationToken = (u64)req;
  349. bevent->version = VIOVERSION;
  350. bevent->disk = DEVICE_NO(d);
  351. bevent->u.rw_data.offset = start;
  352. /*
  353.  * Copy just the dma information from the sg list
  354.  * into the request
  355.  */
  356. for (sgindex = 0; sgindex < nsg; sgindex++) {
  357. bevent->u.rw_data.dma_info[sgindex].token =
  358. sg_dma_address(&sg[sgindex]);
  359. bevent->u.rw_data.dma_info[sgindex].len =
  360. sg_dma_len(&sg[sgindex]);
  361. }
  362. /* Send the request */
  363. hvrc = HvCallEvent_signalLpEvent(&bevent->event);
  364. vio_free_event_buffer(viomajorsubtype_blockio, bevent);
  365. }
  366. if (hvrc != HvLpEvent_Rc_Good) {
  367. printk(VIOD_KERN_WARNING
  368.        "error sending disk event to OS/400 (rc %d)n",
  369.        (int)hvrc);
  370. goto error_ret;
  371. }
  372. spin_unlock_irqrestore(&viodasd_spinlock, flags);
  373. return 0;
  374. error_ret:
  375. num_req_outstanding--;
  376. spin_unlock_irqrestore(&viodasd_spinlock, flags);
  377. dma_unmap_sg(d->dev, sg, nsg, direction);
  378. return -1;
  379. }
  380. /*
  381.  * This is the external request processing routine
  382.  */
  383. static void do_viodasd_request(request_queue_t *q)
  384. {
  385. struct request *req;
  386. /*
  387.  * If we already have the maximum number of requests
  388.  * outstanding to OS/400 just bail out. We'll come
  389.  * back later.
  390.  */
  391. while (num_req_outstanding < VIOMAXREQ) {
  392. req = elv_next_request(q);
  393. if (req == NULL)
  394. return;
  395. /* dequeue the current request from the queue */
  396. blkdev_dequeue_request(req);
  397. /* check that request contains a valid command */
  398. if (!blk_fs_request(req)) {
  399. viodasd_end_request(req, 0, req->hard_nr_sectors);
  400. continue;
  401. }
  402. /* Try sending the request */
  403. if (send_request(req) != 0)
  404. viodasd_end_request(req, 0, req->hard_nr_sectors);
  405. }
  406. }
  407. /*
  408.  * Probe a single disk and fill in the viodasd_device structure
  409.  * for it.
  410.  */
  411. static void probe_disk(struct viodasd_device *d)
  412. {
  413. HvLpEvent_Rc hvrc;
  414. struct viodasd_waitevent we;
  415. int dev_no = DEVICE_NO(d);
  416. struct gendisk *g;
  417. struct request_queue *q;
  418. u16 flags = 0;
  419. retry:
  420. init_completion(&we.com);
  421. /* Send the open event to OS/400 */
  422. hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
  423. HvLpEvent_Type_VirtualIo,
  424. viomajorsubtype_blockio | vioblockopen,
  425. HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
  426. viopath_sourceinst(viopath_hostLp),
  427. viopath_targetinst(viopath_hostLp),
  428. (u64)(unsigned long)&we, VIOVERSION << 16,
  429. ((u64)dev_no << 48) | ((u64)flags<< 32),
  430. 0, 0, 0);
  431. if (hvrc != 0) {
  432. printk(VIOD_KERN_WARNING "bad rc on HV open %dn", (int)hvrc);
  433. return;
  434. }
  435. wait_for_completion(&we.com);
  436. if (we.rc != 0) {
  437. if (flags != 0)
  438. return;
  439. /* try again with read only flag set */
  440. flags = vioblockflags_ro;
  441. goto retry;
  442. }
  443. if (we.max_disk > (MAX_DISKNO - 1)) {
  444. static int warned;
  445. if (warned == 0) {
  446. warned++;
  447. printk(VIOD_KERN_INFO
  448. "Only examining the first %d "
  449. "of %d disks connectedn",
  450. MAX_DISKNO, we.max_disk + 1);
  451. }
  452. }
  453. /* Send the close event to OS/400.  We DON'T expect a response */
  454. hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
  455. HvLpEvent_Type_VirtualIo,
  456. viomajorsubtype_blockio | vioblockclose,
  457. HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
  458. viopath_sourceinst(viopath_hostLp),
  459. viopath_targetinst(viopath_hostLp),
  460. 0, VIOVERSION << 16,
  461. ((u64)dev_no << 48) | ((u64)flags << 32),
  462. 0, 0, 0);
  463. if (hvrc != 0) {
  464. printk(VIOD_KERN_WARNING
  465.        "bad rc sending event to OS/400 %dn", (int)hvrc);
  466. return;
  467. }
  468. /* create the request queue for the disk */
  469. spin_lock_init(&d->q_lock);
  470. q = blk_init_queue(do_viodasd_request, &d->q_lock);
  471. if (q == NULL) {
  472. printk(VIOD_KERN_WARNING "cannot allocate queue for disk %dn",
  473. dev_no);
  474. return;
  475. }
  476. g = alloc_disk(1 << PARTITION_SHIFT);
  477. if (g == NULL) {
  478. printk(VIOD_KERN_WARNING
  479. "cannot allocate disk structure for disk %dn",
  480. dev_no);
  481. blk_cleanup_queue(q);
  482. return;
  483. }
  484. d->disk = g;
  485. blk_queue_max_hw_segments(q, VIOMAXBLOCKDMA);
  486. blk_queue_max_phys_segments(q, VIOMAXBLOCKDMA);
  487. blk_queue_max_sectors(q, VIODASD_MAXSECTORS);
  488. g->major = VIODASD_MAJOR;
  489. g->first_minor = dev_no << PARTITION_SHIFT;
  490. if (dev_no >= 26)
  491. snprintf(g->disk_name, sizeof(g->disk_name),
  492. VIOD_GENHD_NAME "%c%c",
  493. 'a' + (dev_no / 26) - 1, 'a' + (dev_no % 26));
  494. else
  495. snprintf(g->disk_name, sizeof(g->disk_name),
  496. VIOD_GENHD_NAME "%c", 'a' + (dev_no % 26));
  497. snprintf(g->devfs_name, sizeof(g->devfs_name),
  498. "%s%d", VIOD_GENHD_DEVFS_NAME, dev_no);
  499. g->fops = &viodasd_fops;
  500. g->queue = q;
  501. g->private_data = d;
  502. g->driverfs_dev = d->dev;
  503. set_capacity(g, d->size >> 9);
  504. printk(VIOD_KERN_INFO "disk %d: %lu sectors (%lu MB) "
  505. "CHS=%d/%d/%d sector size %d%sn",
  506. dev_no, (unsigned long)(d->size >> 9),
  507. (unsigned long)(d->size >> 20),
  508. (int)d->cylinders, (int)d->tracks,
  509. (int)d->sectors, (int)d->bytes_per_sector,
  510. d->read_only ? " (RO)" : "");
  511. /* register us in the global list */
  512. add_disk(g);
  513. }
  514. /* returns the total number of scatterlist elements converted */
  515. static int block_event_to_scatterlist(const struct vioblocklpevent *bevent,
  516. struct scatterlist *sg, int *total_len)
  517. {
  518. int i, numsg;
  519. const struct rw_data *rw_data = &bevent->u.rw_data;
  520. static const int offset =
  521. offsetof(struct vioblocklpevent, u.rw_data.dma_info);
  522. static const int element_size = sizeof(rw_data->dma_info[0]);
  523. numsg = ((bevent->event.xSizeMinus1 + 1) - offset) / element_size;
  524. if (numsg > VIOMAXBLOCKDMA)
  525. numsg = VIOMAXBLOCKDMA;
  526. *total_len = 0;
  527. memset(sg, 0, sizeof(sg[0]) * VIOMAXBLOCKDMA);
  528. for (i = 0; (i < numsg) && (rw_data->dma_info[i].len > 0); ++i) {
  529. sg_dma_address(&sg[i]) = rw_data->dma_info[i].token;
  530. sg_dma_len(&sg[i]) = rw_data->dma_info[i].len;
  531. *total_len += rw_data->dma_info[i].len;
  532. }
  533. return i;
  534. }
  535. /*
  536.  * Restart all queues, starting with the one _after_ the disk given,
  537.  * thus reducing the chance of starvation of higher numbered disks.
  538.  */
  539. static void viodasd_restart_all_queues_starting_from(int first_index)
  540. {
  541. int i;
  542. for (i = first_index + 1; i < MAX_DISKNO; ++i)
  543. if (viodasd_devices[i].disk)
  544. blk_run_queue(viodasd_devices[i].disk->queue);
  545. for (i = 0; i <= first_index; ++i)
  546. if (viodasd_devices[i].disk)
  547. blk_run_queue(viodasd_devices[i].disk->queue);
  548. }
  549. /*
  550.  * For read and write requests, decrement the number of outstanding requests,
  551.  * Free the DMA buffers we allocated.
  552.  */
  553. static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
  554. {
  555. int num_sg, num_sect, pci_direction, total_len;
  556. struct request *req;
  557. struct scatterlist sg[VIOMAXBLOCKDMA];
  558. struct HvLpEvent *event = &bevent->event;
  559. unsigned long irq_flags;
  560. struct viodasd_device *d;
  561. int error;
  562. spinlock_t *qlock;
  563. num_sg = block_event_to_scatterlist(bevent, sg, &total_len);
  564. num_sect = total_len >> 9;
  565. if (event->xSubtype == (viomajorsubtype_blockio | vioblockread))
  566. pci_direction = DMA_FROM_DEVICE;
  567. else
  568. pci_direction = DMA_TO_DEVICE;
  569. req = (struct request *)bevent->event.xCorrelationToken;
  570. d = req->rq_disk->private_data;
  571. dma_unmap_sg(d->dev, sg, num_sg, pci_direction);
  572. /*
  573.  * Since this is running in interrupt mode, we need to make sure
  574.  * we're not stepping on any global I/O operations
  575.  */
  576. spin_lock_irqsave(&viodasd_spinlock, irq_flags);
  577. num_req_outstanding--;
  578. spin_unlock_irqrestore(&viodasd_spinlock, irq_flags);
  579. error = event->xRc != HvLpEvent_Rc_Good;
  580. if (error) {
  581. const struct vio_error_entry *err;
  582. err = vio_lookup_rc(viodasd_err_table, bevent->sub_result);
  583. printk(VIOD_KERN_WARNING "read/write error %d:0x%04x (%s)n",
  584. event->xRc, bevent->sub_result, err->msg);
  585. num_sect = req->hard_nr_sectors;
  586. }
  587. qlock = req->q->queue_lock;
  588. spin_lock_irqsave(qlock, irq_flags);
  589. viodasd_end_request(req, !error, num_sect);
  590. spin_unlock_irqrestore(qlock, irq_flags);
  591. /* Finally, try to get more requests off of this device's queue */
  592. viodasd_restart_all_queues_starting_from(DEVICE_NO(d));
  593. return 0;
  594. }
  595. /* This routine handles incoming block LP events */
  596. static void handle_block_event(struct HvLpEvent *event)
  597. {
  598. struct vioblocklpevent *bevent = (struct vioblocklpevent *)event;
  599. struct viodasd_waitevent *pwe;
  600. if (event == NULL)
  601. /* Notification that a partition went away! */
  602. return;
  603. /* First, we should NEVER get an int here...only acks */
  604. if (event->xFlags.xFunction == HvLpEvent_Function_Int) {
  605. printk(VIOD_KERN_WARNING
  606.        "Yikes! got an int in viodasd event handler!n");
  607. if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck) {
  608. event->xRc = HvLpEvent_Rc_InvalidSubtype;
  609. HvCallEvent_ackLpEvent(event);
  610. }
  611. }
  612. switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
  613. case vioblockopen:
  614. /*
  615.  * Handle a response to an open request.  We get all the
  616.  * disk information in the response, so update it.  The
  617.  * correlation token contains a pointer to a waitevent
  618.  * structure that has a completion in it.  update the
  619.  * return code in the waitevent structure and post the
  620.  * completion to wake up the guy who sent the request
  621.  */
  622. pwe = (struct viodasd_waitevent *)event->xCorrelationToken;
  623. pwe->rc = event->xRc;
  624. pwe->sub_result = bevent->sub_result;
  625. if (event->xRc == HvLpEvent_Rc_Good) {
  626. const struct open_data *data = &bevent->u.open_data;
  627. struct viodasd_device *device =
  628. &viodasd_devices[bevent->disk];
  629. device->read_only =
  630. bevent->flags & vioblockflags_ro;
  631. device->size = data->disk_size;
  632. device->cylinders = data->cylinders;
  633. device->tracks = data->tracks;
  634. device->sectors = data->sectors;
  635. device->bytes_per_sector = data->bytes_per_sector;
  636. pwe->max_disk = data->max_disk;
  637. }
  638. complete(&pwe->com);
  639. break;
  640. case vioblockclose:
  641. break;
  642. case vioblockread:
  643. case vioblockwrite:
  644. viodasd_handle_read_write(bevent);
  645. break;
  646. default:
  647. printk(VIOD_KERN_WARNING "invalid subtype!");
  648. if (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck) {
  649. event->xRc = HvLpEvent_Rc_InvalidSubtype;
  650. HvCallEvent_ackLpEvent(event);
  651. }
  652. }
  653. }
  654. /*
  655.  * Get the driver to reprobe for more disks.
  656.  */
  657. static ssize_t probe_disks(struct device_driver *drv, const char *buf,
  658. size_t count)
  659. {
  660. struct viodasd_device *d;
  661. for (d = viodasd_devices; d < &viodasd_devices[MAX_DISKNO]; d++) {
  662. if (d->disk == NULL)
  663. probe_disk(d);
  664. }
  665. return count;
  666. }
  667. static DRIVER_ATTR(probe, S_IWUSR, NULL, probe_disks);
  668. static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
  669. {
  670. struct viodasd_device *d = &viodasd_devices[vdev->unit_address];
  671. d->dev = &vdev->dev;
  672. probe_disk(d);
  673. if (d->disk == NULL)
  674. return -ENODEV;
  675. return 0;
  676. }
  677. static int viodasd_remove(struct vio_dev *vdev)
  678. {
  679. struct viodasd_device *d;
  680. d = &viodasd_devices[vdev->unit_address];
  681. if (d->disk) {
  682. del_gendisk(d->disk);
  683. blk_cleanup_queue(d->disk->queue);
  684. put_disk(d->disk);
  685. d->disk = NULL;
  686. }
  687. d->dev = NULL;
  688. return 0;
  689. }
  690. /**
  691.  * viodasd_device_table: Used by vio.c to match devices that we
  692.  * support.
  693.  */
  694. static struct vio_device_id viodasd_device_table[] __devinitdata = {
  695. { "viodasd", "" },
  696. { "", "" }
  697. };
  698. MODULE_DEVICE_TABLE(vio, viodasd_device_table);
  699. static struct vio_driver viodasd_driver = {
  700. .name = "viodasd",
  701. .id_table = viodasd_device_table,
  702. .probe = viodasd_probe,
  703. .remove = viodasd_remove
  704. };
  705. /*
  706.  * Initialize the whole device driver.  Handle module and non-module
  707.  * versions
  708.  */
  709. static int __init viodasd_init(void)
  710. {
  711. int rc;
  712. /* Try to open to our host lp */
  713. if (viopath_hostLp == HvLpIndexInvalid)
  714. vio_set_hostlp();
  715. if (viopath_hostLp == HvLpIndexInvalid) {
  716. printk(VIOD_KERN_WARNING "invalid hosting partitionn");
  717. return -EIO;
  718. }
  719. printk(VIOD_KERN_INFO "vers " VIOD_VERS ", hosting partition %dn",
  720. viopath_hostLp);
  721.         /* register the block device */
  722. if (register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME)) {
  723. printk(VIOD_KERN_WARNING
  724. "Unable to get major number %d for %sn",
  725. VIODASD_MAJOR, VIOD_GENHD_NAME);
  726. return -EIO;
  727. }
  728. /* Actually open the path to the hosting partition */
  729. if (viopath_open(viopath_hostLp, viomajorsubtype_blockio,
  730. VIOMAXREQ + 2)) {
  731. printk(VIOD_KERN_WARNING
  732.        "error opening path to host partition %dn",
  733.        viopath_hostLp);
  734. unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
  735. return -EIO;
  736. }
  737. /* Initialize our request handler */
  738. vio_setHandler(viomajorsubtype_blockio, handle_block_event);
  739. rc = vio_register_driver(&viodasd_driver);
  740. if (rc == 0)
  741. driver_create_file(&viodasd_driver.driver, &driver_attr_probe);
  742. return rc;
  743. }
  744. module_init(viodasd_init);
  745. void viodasd_exit(void)
  746. {
  747. driver_remove_file(&viodasd_driver.driver, &driver_attr_probe);
  748. vio_unregister_driver(&viodasd_driver);
  749. vio_clearHandler(viomajorsubtype_blockio);
  750. unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
  751. viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2);
  752. }
  753. module_exit(viodasd_exit);