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