Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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