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#include <asm/firmware.h> 53 54MODULE_DESCRIPTION("iSeries Virtual DASD"); 55MODULE_AUTHOR("Dave Boutcher"); 56MODULE_LICENSE("GPL"); 57 58/* 59 * We only support 7 partitions per physical disk....so with minor 60 * numbers 0-255 we get a maximum of 32 disks. 61 */ 62#define VIOD_GENHD_NAME "iseries/vd" 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_getgeo(struct block_device *bdev, struct hd_geometry *geo) 251{ 252 struct gendisk *disk = bdev->bd_disk; 253 struct viodasd_device *d = disk->private_data; 254 255 geo->sectors = d->sectors ? d->sectors : 0; 256 geo->heads = d->tracks ? d->tracks : 64; 257 geo->cylinders = d->cylinders ? d->cylinders : 258 get_capacity(disk) / (geo->cylinders * geo->heads); 259 260 return 0; 261} 262 263/* 264 * Our file operations table 265 */ 266static struct block_device_operations viodasd_fops = { 267 .owner = THIS_MODULE, 268 .open = viodasd_open, 269 .release = viodasd_release, 270 .getgeo = viodasd_getgeo, 271}; 272 273/* 274 * End a request 275 */ 276static void viodasd_end_request(struct request *req, int uptodate, 277 int num_sectors) 278{ 279 if (end_that_request_first(req, uptodate, num_sectors)) 280 return; 281 add_disk_randomness(req->rq_disk); 282 end_that_request_last(req, uptodate); 283} 284 285/* 286 * Send an actual I/O request to OS/400 287 */ 288static int send_request(struct request *req) 289{ 290 u64 start; 291 int direction; 292 int nsg; 293 u16 viocmd; 294 HvLpEvent_Rc hvrc; 295 struct vioblocklpevent *bevent; 296 struct HvLpEvent *hev; 297 struct scatterlist sg[VIOMAXBLOCKDMA]; 298 int sgindex; 299 int statindex; 300 struct viodasd_device *d; 301 unsigned long flags; 302 303 start = (u64)req->sector << 9; 304 305 if (rq_data_dir(req) == READ) { 306 direction = DMA_FROM_DEVICE; 307 viocmd = viomajorsubtype_blockio | vioblockread; 308 statindex = 0; 309 } else { 310 direction = DMA_TO_DEVICE; 311 viocmd = viomajorsubtype_blockio | vioblockwrite; 312 statindex = 1; 313 } 314 315 d = req->rq_disk->private_data; 316 317 /* Now build the scatter-gather list */ 318 nsg = blk_rq_map_sg(req->q, req, sg); 319 nsg = dma_map_sg(d->dev, sg, nsg, direction); 320 321 spin_lock_irqsave(&viodasd_spinlock, flags); 322 num_req_outstanding++; 323 324 /* This optimization handles a single DMA block */ 325 if (nsg == 1) 326 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, 327 HvLpEvent_Type_VirtualIo, viocmd, 328 HvLpEvent_AckInd_DoAck, 329 HvLpEvent_AckType_ImmediateAck, 330 viopath_sourceinst(viopath_hostLp), 331 viopath_targetinst(viopath_hostLp), 332 (u64)(unsigned long)req, VIOVERSION << 16, 333 ((u64)DEVICE_NO(d) << 48), start, 334 ((u64)sg_dma_address(&sg[0])) << 32, 335 sg_dma_len(&sg[0])); 336 else { 337 bevent = (struct vioblocklpevent *) 338 vio_get_event_buffer(viomajorsubtype_blockio); 339 if (bevent == NULL) { 340 printk(VIOD_KERN_WARNING 341 "error allocating disk event buffer\n"); 342 goto error_ret; 343 } 344 345 /* 346 * Now build up the actual request. Note that we store 347 * the pointer to the request in the correlation 348 * token so we can match the response up later 349 */ 350 memset(bevent, 0, sizeof(struct vioblocklpevent)); 351 hev = &bevent->event; 352 hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK | 353 HV_LP_EVENT_INT; 354 hev->xType = HvLpEvent_Type_VirtualIo; 355 hev->xSubtype = viocmd; 356 hev->xSourceLp = HvLpConfig_getLpIndex(); 357 hev->xTargetLp = viopath_hostLp; 358 hev->xSizeMinus1 = 359 offsetof(struct vioblocklpevent, u.rw_data.dma_info) + 360 (sizeof(bevent->u.rw_data.dma_info[0]) * nsg) - 1; 361 hev->xSourceInstanceId = viopath_sourceinst(viopath_hostLp); 362 hev->xTargetInstanceId = viopath_targetinst(viopath_hostLp); 363 hev->xCorrelationToken = (u64)req; 364 bevent->version = VIOVERSION; 365 bevent->disk = DEVICE_NO(d); 366 bevent->u.rw_data.offset = start; 367 368 /* 369 * Copy just the dma information from the sg list 370 * into the request 371 */ 372 for (sgindex = 0; sgindex < nsg; sgindex++) { 373 bevent->u.rw_data.dma_info[sgindex].token = 374 sg_dma_address(&sg[sgindex]); 375 bevent->u.rw_data.dma_info[sgindex].len = 376 sg_dma_len(&sg[sgindex]); 377 } 378 379 /* Send the request */ 380 hvrc = HvCallEvent_signalLpEvent(&bevent->event); 381 vio_free_event_buffer(viomajorsubtype_blockio, bevent); 382 } 383 384 if (hvrc != HvLpEvent_Rc_Good) { 385 printk(VIOD_KERN_WARNING 386 "error sending disk event to OS/400 (rc %d)\n", 387 (int)hvrc); 388 goto error_ret; 389 } 390 spin_unlock_irqrestore(&viodasd_spinlock, flags); 391 return 0; 392 393error_ret: 394 num_req_outstanding--; 395 spin_unlock_irqrestore(&viodasd_spinlock, flags); 396 dma_unmap_sg(d->dev, sg, nsg, direction); 397 return -1; 398} 399 400/* 401 * This is the external request processing routine 402 */ 403static void do_viodasd_request(request_queue_t *q) 404{ 405 struct request *req; 406 407 /* 408 * If we already have the maximum number of requests 409 * outstanding to OS/400 just bail out. We'll come 410 * back later. 411 */ 412 while (num_req_outstanding < VIOMAXREQ) { 413 req = elv_next_request(q); 414 if (req == NULL) 415 return; 416 /* dequeue the current request from the queue */ 417 blkdev_dequeue_request(req); 418 /* check that request contains a valid command */ 419 if (!blk_fs_request(req)) { 420 viodasd_end_request(req, 0, req->hard_nr_sectors); 421 continue; 422 } 423 /* Try sending the request */ 424 if (send_request(req) != 0) 425 viodasd_end_request(req, 0, req->hard_nr_sectors); 426 } 427} 428 429/* 430 * Probe a single disk and fill in the viodasd_device structure 431 * for it. 432 */ 433static void probe_disk(struct viodasd_device *d) 434{ 435 HvLpEvent_Rc hvrc; 436 struct viodasd_waitevent we; 437 int dev_no = DEVICE_NO(d); 438 struct gendisk *g; 439 struct request_queue *q; 440 u16 flags = 0; 441 442retry: 443 init_completion(&we.com); 444 445 /* Send the open event to OS/400 */ 446 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, 447 HvLpEvent_Type_VirtualIo, 448 viomajorsubtype_blockio | vioblockopen, 449 HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, 450 viopath_sourceinst(viopath_hostLp), 451 viopath_targetinst(viopath_hostLp), 452 (u64)(unsigned long)&we, VIOVERSION << 16, 453 ((u64)dev_no << 48) | ((u64)flags<< 32), 454 0, 0, 0); 455 if (hvrc != 0) { 456 printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc); 457 return; 458 } 459 460 wait_for_completion(&we.com); 461 462 if (we.rc != 0) { 463 if (flags != 0) 464 return; 465 /* try again with read only flag set */ 466 flags = vioblockflags_ro; 467 goto retry; 468 } 469 if (we.max_disk > (MAX_DISKNO - 1)) { 470 static int warned; 471 472 if (warned == 0) { 473 warned++; 474 printk(VIOD_KERN_INFO 475 "Only examining the first %d " 476 "of %d disks connected\n", 477 MAX_DISKNO, we.max_disk + 1); 478 } 479 } 480 481 /* Send the close event to OS/400. We DON'T expect a response */ 482 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, 483 HvLpEvent_Type_VirtualIo, 484 viomajorsubtype_blockio | vioblockclose, 485 HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, 486 viopath_sourceinst(viopath_hostLp), 487 viopath_targetinst(viopath_hostLp), 488 0, VIOVERSION << 16, 489 ((u64)dev_no << 48) | ((u64)flags << 32), 490 0, 0, 0); 491 if (hvrc != 0) { 492 printk(VIOD_KERN_WARNING 493 "bad rc sending event to OS/400 %d\n", (int)hvrc); 494 return; 495 } 496 /* create the request queue for the disk */ 497 spin_lock_init(&d->q_lock); 498 q = blk_init_queue(do_viodasd_request, &d->q_lock); 499 if (q == NULL) { 500 printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n", 501 dev_no); 502 return; 503 } 504 g = alloc_disk(1 << PARTITION_SHIFT); 505 if (g == NULL) { 506 printk(VIOD_KERN_WARNING 507 "cannot allocate disk structure for disk %d\n", 508 dev_no); 509 blk_cleanup_queue(q); 510 return; 511 } 512 513 d->disk = g; 514 blk_queue_max_hw_segments(q, VIOMAXBLOCKDMA); 515 blk_queue_max_phys_segments(q, VIOMAXBLOCKDMA); 516 blk_queue_max_sectors(q, VIODASD_MAXSECTORS); 517 g->major = VIODASD_MAJOR; 518 g->first_minor = dev_no << PARTITION_SHIFT; 519 if (dev_no >= 26) 520 snprintf(g->disk_name, sizeof(g->disk_name), 521 VIOD_GENHD_NAME "%c%c", 522 'a' + (dev_no / 26) - 1, 'a' + (dev_no % 26)); 523 else 524 snprintf(g->disk_name, sizeof(g->disk_name), 525 VIOD_GENHD_NAME "%c", 'a' + (dev_no % 26)); 526 g->fops = &viodasd_fops; 527 g->queue = q; 528 g->private_data = d; 529 g->driverfs_dev = d->dev; 530 set_capacity(g, d->size >> 9); 531 532 printk(VIOD_KERN_INFO "disk %d: %lu sectors (%lu MB) " 533 "CHS=%d/%d/%d sector size %d%s\n", 534 dev_no, (unsigned long)(d->size >> 9), 535 (unsigned long)(d->size >> 20), 536 (int)d->cylinders, (int)d->tracks, 537 (int)d->sectors, (int)d->bytes_per_sector, 538 d->read_only ? " (RO)" : ""); 539 540 /* register us in the global list */ 541 add_disk(g); 542} 543 544/* returns the total number of scatterlist elements converted */ 545static int block_event_to_scatterlist(const struct vioblocklpevent *bevent, 546 struct scatterlist *sg, int *total_len) 547{ 548 int i, numsg; 549 const struct rw_data *rw_data = &bevent->u.rw_data; 550 static const int offset = 551 offsetof(struct vioblocklpevent, u.rw_data.dma_info); 552 static const int element_size = sizeof(rw_data->dma_info[0]); 553 554 numsg = ((bevent->event.xSizeMinus1 + 1) - offset) / element_size; 555 if (numsg > VIOMAXBLOCKDMA) 556 numsg = VIOMAXBLOCKDMA; 557 558 *total_len = 0; 559 memset(sg, 0, sizeof(sg[0]) * VIOMAXBLOCKDMA); 560 561 for (i = 0; (i < numsg) && (rw_data->dma_info[i].len > 0); ++i) { 562 sg_dma_address(&sg[i]) = rw_data->dma_info[i].token; 563 sg_dma_len(&sg[i]) = rw_data->dma_info[i].len; 564 *total_len += rw_data->dma_info[i].len; 565 } 566 return i; 567} 568 569/* 570 * Restart all queues, starting with the one _after_ the disk given, 571 * thus reducing the chance of starvation of higher numbered disks. 572 */ 573static void viodasd_restart_all_queues_starting_from(int first_index) 574{ 575 int i; 576 577 for (i = first_index + 1; i < MAX_DISKNO; ++i) 578 if (viodasd_devices[i].disk) 579 blk_run_queue(viodasd_devices[i].disk->queue); 580 for (i = 0; i <= first_index; ++i) 581 if (viodasd_devices[i].disk) 582 blk_run_queue(viodasd_devices[i].disk->queue); 583} 584 585/* 586 * For read and write requests, decrement the number of outstanding requests, 587 * Free the DMA buffers we allocated. 588 */ 589static int viodasd_handle_read_write(struct vioblocklpevent *bevent) 590{ 591 int num_sg, num_sect, pci_direction, total_len; 592 struct request *req; 593 struct scatterlist sg[VIOMAXBLOCKDMA]; 594 struct HvLpEvent *event = &bevent->event; 595 unsigned long irq_flags; 596 struct viodasd_device *d; 597 int error; 598 spinlock_t *qlock; 599 600 num_sg = block_event_to_scatterlist(bevent, sg, &total_len); 601 num_sect = total_len >> 9; 602 if (event->xSubtype == (viomajorsubtype_blockio | vioblockread)) 603 pci_direction = DMA_FROM_DEVICE; 604 else 605 pci_direction = DMA_TO_DEVICE; 606 req = (struct request *)bevent->event.xCorrelationToken; 607 d = req->rq_disk->private_data; 608 609 dma_unmap_sg(d->dev, sg, num_sg, pci_direction); 610 611 /* 612 * Since this is running in interrupt mode, we need to make sure 613 * we're not stepping on any global I/O operations 614 */ 615 spin_lock_irqsave(&viodasd_spinlock, irq_flags); 616 num_req_outstanding--; 617 spin_unlock_irqrestore(&viodasd_spinlock, irq_flags); 618 619 error = event->xRc != HvLpEvent_Rc_Good; 620 if (error) { 621 const struct vio_error_entry *err; 622 err = vio_lookup_rc(viodasd_err_table, bevent->sub_result); 623 printk(VIOD_KERN_WARNING "read/write error %d:0x%04x (%s)\n", 624 event->xRc, bevent->sub_result, err->msg); 625 num_sect = req->hard_nr_sectors; 626 } 627 qlock = req->q->queue_lock; 628 spin_lock_irqsave(qlock, irq_flags); 629 viodasd_end_request(req, !error, num_sect); 630 spin_unlock_irqrestore(qlock, irq_flags); 631 632 /* Finally, try to get more requests off of this device's queue */ 633 viodasd_restart_all_queues_starting_from(DEVICE_NO(d)); 634 635 return 0; 636} 637 638/* This routine handles incoming block LP events */ 639static void handle_block_event(struct HvLpEvent *event) 640{ 641 struct vioblocklpevent *bevent = (struct vioblocklpevent *)event; 642 struct viodasd_waitevent *pwe; 643 644 if (event == NULL) 645 /* Notification that a partition went away! */ 646 return; 647 /* First, we should NEVER get an int here...only acks */ 648 if (hvlpevent_is_int(event)) { 649 printk(VIOD_KERN_WARNING 650 "Yikes! got an int in viodasd event handler!\n"); 651 if (hvlpevent_need_ack(event)) { 652 event->xRc = HvLpEvent_Rc_InvalidSubtype; 653 HvCallEvent_ackLpEvent(event); 654 } 655 } 656 657 switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { 658 case vioblockopen: 659 /* 660 * Handle a response to an open request. We get all the 661 * disk information in the response, so update it. The 662 * correlation token contains a pointer to a waitevent 663 * structure that has a completion in it. update the 664 * return code in the waitevent structure and post the 665 * completion to wake up the guy who sent the request 666 */ 667 pwe = (struct viodasd_waitevent *)event->xCorrelationToken; 668 pwe->rc = event->xRc; 669 pwe->sub_result = bevent->sub_result; 670 if (event->xRc == HvLpEvent_Rc_Good) { 671 const struct open_data *data = &bevent->u.open_data; 672 struct viodasd_device *device = 673 &viodasd_devices[bevent->disk]; 674 device->read_only = 675 bevent->flags & vioblockflags_ro; 676 device->size = data->disk_size; 677 device->cylinders = data->cylinders; 678 device->tracks = data->tracks; 679 device->sectors = data->sectors; 680 device->bytes_per_sector = data->bytes_per_sector; 681 pwe->max_disk = data->max_disk; 682 } 683 complete(&pwe->com); 684 break; 685 case vioblockclose: 686 break; 687 case vioblockread: 688 case vioblockwrite: 689 viodasd_handle_read_write(bevent); 690 break; 691 692 default: 693 printk(VIOD_KERN_WARNING "invalid subtype!"); 694 if (hvlpevent_need_ack(event)) { 695 event->xRc = HvLpEvent_Rc_InvalidSubtype; 696 HvCallEvent_ackLpEvent(event); 697 } 698 } 699} 700 701/* 702 * Get the driver to reprobe for more disks. 703 */ 704static ssize_t probe_disks(struct device_driver *drv, const char *buf, 705 size_t count) 706{ 707 struct viodasd_device *d; 708 709 for (d = viodasd_devices; d < &viodasd_devices[MAX_DISKNO]; d++) { 710 if (d->disk == NULL) 711 probe_disk(d); 712 } 713 return count; 714} 715static DRIVER_ATTR(probe, S_IWUSR, NULL, probe_disks); 716 717static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id) 718{ 719 struct viodasd_device *d = &viodasd_devices[vdev->unit_address]; 720 721 d->dev = &vdev->dev; 722 probe_disk(d); 723 if (d->disk == NULL) 724 return -ENODEV; 725 return 0; 726} 727 728static int viodasd_remove(struct vio_dev *vdev) 729{ 730 struct viodasd_device *d; 731 732 d = &viodasd_devices[vdev->unit_address]; 733 if (d->disk) { 734 del_gendisk(d->disk); 735 blk_cleanup_queue(d->disk->queue); 736 put_disk(d->disk); 737 d->disk = NULL; 738 } 739 d->dev = NULL; 740 return 0; 741} 742 743/** 744 * viodasd_device_table: Used by vio.c to match devices that we 745 * support. 746 */ 747static struct vio_device_id viodasd_device_table[] __devinitdata = { 748 { "block", "IBM,iSeries-viodasd" }, 749 { "", "" } 750}; 751MODULE_DEVICE_TABLE(vio, viodasd_device_table); 752 753static struct vio_driver viodasd_driver = { 754 .id_table = viodasd_device_table, 755 .probe = viodasd_probe, 756 .remove = viodasd_remove, 757 .driver = { 758 .name = "viodasd", 759 .owner = THIS_MODULE, 760 } 761}; 762 763static int need_delete_probe; 764 765/* 766 * Initialize the whole device driver. Handle module and non-module 767 * versions 768 */ 769static int __init viodasd_init(void) 770{ 771 int rc; 772 773 if (!firmware_has_feature(FW_FEATURE_ISERIES)) { 774 rc = -ENODEV; 775 goto early_fail; 776 } 777 778 /* Try to open to our host lp */ 779 if (viopath_hostLp == HvLpIndexInvalid) 780 vio_set_hostlp(); 781 782 if (viopath_hostLp == HvLpIndexInvalid) { 783 printk(VIOD_KERN_WARNING "invalid hosting partition\n"); 784 rc = -EIO; 785 goto early_fail; 786 } 787 788 printk(VIOD_KERN_INFO "vers " VIOD_VERS ", hosting partition %d\n", 789 viopath_hostLp); 790 791 /* register the block device */ 792 rc = register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME); 793 if (rc) { 794 printk(VIOD_KERN_WARNING 795 "Unable to get major number %d for %s\n", 796 VIODASD_MAJOR, VIOD_GENHD_NAME); 797 goto early_fail; 798 } 799 /* Actually open the path to the hosting partition */ 800 rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, 801 VIOMAXREQ + 2); 802 if (rc) { 803 printk(VIOD_KERN_WARNING 804 "error opening path to host partition %d\n", 805 viopath_hostLp); 806 goto unregister_blk; 807 } 808 809 /* Initialize our request handler */ 810 vio_setHandler(viomajorsubtype_blockio, handle_block_event); 811 812 rc = vio_register_driver(&viodasd_driver); 813 if (rc) { 814 printk(VIOD_KERN_WARNING "vio_register_driver failed\n"); 815 goto unset_handler; 816 } 817 818 /* 819 * If this call fails, it just means that we cannot dynamically 820 * add virtual disks, but the driver will still work fine for 821 * all existing disk, so ignore the failure. 822 */ 823 if (!driver_create_file(&viodasd_driver.driver, &driver_attr_probe)) 824 need_delete_probe = 1; 825 826 return 0; 827 828unset_handler: 829 vio_clearHandler(viomajorsubtype_blockio); 830 viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2); 831unregister_blk: 832 unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME); 833early_fail: 834 return rc; 835} 836module_init(viodasd_init); 837 838void __exit viodasd_exit(void) 839{ 840 if (need_delete_probe) 841 driver_remove_file(&viodasd_driver.driver, &driver_attr_probe); 842 vio_unregister_driver(&viodasd_driver); 843 vio_clearHandler(viomajorsubtype_blockio); 844 viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2); 845 unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME); 846} 847module_exit(viodasd_exit); 848