linux/drivers/staging/unisys/virthba/virthba.c
<<
>>
Prefs
   1/* virthba.c
   2 *
   3 * Copyright (C) 2010 - 2013 UNISYS CORPORATION
   4 * All rights reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or (at
   9 * your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful, but
  12 * WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  14 * NON INFRINGEMENT.  See the GNU General Public License for more
  15 * details.
  16 */
  17
  18#define EXPORT_SYMTAB
  19
  20/* if you want to turn on some debugging of write device data or read
  21 * device data, define these two undefs.  You will probably want to
  22 * customize the code which is here since it was written assuming
  23 * reading and writing a specific data file df.64M.txt which is a
  24 * 64Megabyte file created by Art Nilson using a scritp I wrote called
  25 * cr_test_data.pl.  The data file consists of 256 byte lines of text
  26 * which start with an 8 digit sequence number, a colon, and then
  27 * letters after that */
  28
  29#undef DBGINF
  30
  31#include <linux/kernel.h>
  32#ifdef CONFIG_MODVERSIONS
  33#include <config/modversions.h>
  34#endif
  35
  36#include "uniklog.h"
  37#include "diagnostics/appos_subsystems.h"
  38#include "uisutils.h"
  39#include "uisqueue.h"
  40#include "uisthread.h"
  41
  42#include <linux/module.h>
  43#include <linux/init.h>
  44#include <linux/pci.h>
  45#include <linux/spinlock.h>
  46#include <linux/device.h>
  47#include <linux/slab.h>
  48#include <scsi/scsi.h>
  49#include <scsi/scsi_host.h>
  50#include <scsi/scsi_cmnd.h>
  51#include <scsi/scsi_device.h>
  52#include <asm/param.h>
  53#include <linux/debugfs.h>
  54#include <linux/types.h>
  55
  56#include "virthba.h"
  57#include "virtpci.h"
  58#include "visorchipset.h"
  59#include "version.h"
  60#include "guestlinuxdebug.h"
  61/* this is shorter than using __FILE__ (full path name) in
  62 * debug/info/error messages
  63 */
  64#define CURRENT_FILE_PC VIRT_HBA_PC_virthba_c
  65#define __MYFILE__ "virthba.c"
  66
  67/* NOTE:  L1_CACHE_BYTES >=128 */
  68#define DEVICE_ATTRIBUTE struct device_attribute
  69
  70 /* MAX_BUF = 6 lines x 10 MAXVHBA x 80 characters
  71 *         = 4800 bytes ~ 2^13 = 8192 bytes
  72 */
  73#define MAX_BUF 8192
  74
  75/*****************************************************/
  76/* Forward declarations                              */
  77/*****************************************************/
  78static int virthba_probe(struct virtpci_dev *dev,
  79                         const struct pci_device_id *id);
  80static void virthba_remove(struct virtpci_dev *dev);
  81static int virthba_abort_handler(struct scsi_cmnd *scsicmd);
  82static int virthba_bus_reset_handler(struct scsi_cmnd *scsicmd);
  83static int virthba_device_reset_handler(struct scsi_cmnd *scsicmd);
  84static int virthba_host_reset_handler(struct scsi_cmnd *scsicmd);
  85static const char *virthba_get_info(struct Scsi_Host *shp);
  86static int virthba_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
  87static int virthba_queue_command_lck(struct scsi_cmnd *scsicmd,
  88                                     void (*virthba_cmnd_done)(struct scsi_cmnd *));
  89
  90static const struct x86_cpu_id unisys_spar_ids[] = {
  91        { X86_VENDOR_INTEL, 6, 62, X86_FEATURE_ANY },
  92        {}
  93};
  94
  95/* Autoload */
  96MODULE_DEVICE_TABLE(x86cpu, unisys_spar_ids);
  97
  98#ifdef DEF_SCSI_QCMD
  99static DEF_SCSI_QCMD(virthba_queue_command)
 100#else
 101#define virthba_queue_command virthba_queue_command_lck
 102#endif
 103
 104static int virthba_slave_alloc(struct scsi_device *scsidev);
 105static int virthba_slave_configure(struct scsi_device *scsidev);
 106static void virthba_slave_destroy(struct scsi_device *scsidev);
 107static int process_incoming_rsps(void *);
 108static int virthba_serverup(struct virtpci_dev *virtpcidev);
 109static int virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state);
 110static void doDiskAddRemove(struct work_struct *work);
 111static void virthba_serverdown_complete(struct work_struct *work);
 112static ssize_t info_debugfs_read(struct file *file, char __user *buf,
 113                        size_t len, loff_t *offset);
 114static ssize_t enable_ints_write(struct file *file,
 115                        const char __user *buffer, size_t count, loff_t *ppos);
 116
 117/*****************************************************/
 118/* Globals                                           */
 119/*****************************************************/
 120
 121static int rsltq_wait_usecs = 4000;     /* Default 4ms */
 122static unsigned int MaxBuffLen;
 123
 124/* Module options */
 125static char *virthba_options = "NONE";
 126
 127static const struct pci_device_id virthba_id_table[] = {
 128        {PCI_DEVICE(PCI_VENDOR_ID_UNISYS, PCI_DEVICE_ID_VIRTHBA)},
 129        {0},
 130};
 131
 132/* export virthba_id_table */
 133MODULE_DEVICE_TABLE(pci, virthba_id_table);
 134
 135static struct workqueue_struct *virthba_serverdown_workqueue;
 136
 137static struct virtpci_driver virthba_driver = {
 138        .name = "uisvirthba",
 139        .version = VERSION,
 140        .vertag = NULL,
 141        .id_table = virthba_id_table,
 142        .probe = virthba_probe,
 143        .remove = virthba_remove,
 144        .resume = virthba_serverup,
 145        .suspend = virthba_serverdown
 146};
 147
 148/* The Send and Recive Buffers of the IO Queue may both be full */
 149#define MAX_PENDING_REQUESTS (MIN_NUMSIGNALS*2)
 150#define INTERRUPT_VECTOR_MASK 0x3F
 151
 152struct scsipending {
 153        char cmdtype;           /* Type of pointer that is being stored */
 154        void *sent;             /* The Data being tracked */
 155        /* struct scsi_cmnd *type for virthba_queue_command */
 156        /* struct uiscmdrsp *type for management commands */
 157};
 158
 159#define VIRTHBA_ERROR_COUNT 30
 160#define IOS_ERROR_THRESHOLD 1000
 161struct virtdisk_info {
 162        u32 valid;
 163        u32 channel, id, lun;   /* Disk Path */
 164        atomic_t ios_threshold;
 165        atomic_t error_count;
 166        struct virtdisk_info *next;
 167};
 168/* Each Scsi_Host has a host_data area that contains this struct. */
 169struct virthba_info {
 170        struct Scsi_Host *scsihost;
 171        struct virtpci_dev *virtpcidev;
 172        struct list_head dev_info_list;
 173        struct chaninfo chinfo;
 174        struct irq_info intr;           /* use recvInterrupt info to receive
 175                                           interrupts when IOs complete */
 176        int interrupt_vector;
 177        struct scsipending pending[MAX_PENDING_REQUESTS]; /* Tracks the requests
 178                                                             that have been */
 179        /* forwarded to the IOVM and haven't returned yet */
 180        unsigned int nextinsert;        /* Start search for next pending
 181                                           free slot here */
 182        spinlock_t privlock;
 183        bool serverdown;
 184        bool serverchangingstate;
 185        unsigned long long acquire_failed_cnt;
 186        unsigned long long interrupts_rcvd;
 187        unsigned long long interrupts_notme;
 188        unsigned long long interrupts_disabled;
 189        struct work_struct serverdown_completion;
 190        u64 __iomem *flags_addr;
 191        atomic_t interrupt_rcvd;
 192        wait_queue_head_t rsp_queue;
 193        struct virtdisk_info head;
 194};
 195
 196/* Work Data for DARWorkQ */
 197struct diskaddremove {
 198        u8 add;                 /* 0-remove, 1-add */
 199        struct Scsi_Host *shost; /* Scsi Host for this virthba instance */
 200        u32 channel, id, lun;   /* Disk Path */
 201        struct diskaddremove *next;
 202};
 203
 204#define virtpci_dev_to_virthba_virthba_get_info(d) \
 205        container_of(d, struct virthba_info, virtpcidev)
 206
 207static DEVICE_ATTRIBUTE *virthba_shost_attrs[];
 208static struct scsi_host_template virthba_driver_template = {
 209        .name = "Unisys Virtual HBA",
 210        .info = virthba_get_info,
 211        .ioctl = virthba_ioctl,
 212        .queuecommand = virthba_queue_command,
 213        .eh_abort_handler = virthba_abort_handler,
 214        .eh_device_reset_handler = virthba_device_reset_handler,
 215        .eh_bus_reset_handler = virthba_bus_reset_handler,
 216        .eh_host_reset_handler = virthba_host_reset_handler,
 217        .shost_attrs = virthba_shost_attrs,
 218
 219#define VIRTHBA_MAX_CMNDS 128
 220        .can_queue = VIRTHBA_MAX_CMNDS,
 221        .sg_tablesize = 64,     /* largest number of address/length pairs */
 222        .this_id = -1,
 223        .slave_alloc = virthba_slave_alloc,
 224        .slave_configure = virthba_slave_configure,
 225        .slave_destroy = virthba_slave_destroy,
 226        .use_clustering = ENABLE_CLUSTERING,
 227};
 228
 229struct virthba_devices_open {
 230        struct virthba_info *virthbainfo;
 231};
 232
 233static const struct file_operations debugfs_info_fops = {
 234        .read = info_debugfs_read,
 235};
 236
 237static const struct file_operations debugfs_enable_ints_fops = {
 238        .write = enable_ints_write,
 239};
 240
 241/*****************************************************/
 242/* Structs                                           */
 243/*****************************************************/
 244
 245#define VIRTHBASOPENMAX 1
 246/* array of open devices maintained by open() and close(); */
 247static struct virthba_devices_open VirtHbasOpen[VIRTHBASOPENMAX];
 248static struct dentry *virthba_debugfs_dir;
 249
 250/*****************************************************/
 251/* Local Functions                                   */
 252/*****************************************************/
 253static int
 254add_scsipending_entry(struct virthba_info *vhbainfo, char cmdtype, void *new)
 255{
 256        unsigned long flags;
 257        int insert_location;
 258
 259        spin_lock_irqsave(&vhbainfo->privlock, flags);
 260        insert_location = vhbainfo->nextinsert;
 261        while (vhbainfo->pending[insert_location].sent != NULL) {
 262                insert_location = (insert_location + 1) % MAX_PENDING_REQUESTS;
 263                if (insert_location == (int) vhbainfo->nextinsert) {
 264                        LOGERR("Queue should be full. insert_location<<%d>>  Unable to find open slot for pending commands.\n",
 265                             insert_location);
 266                        spin_unlock_irqrestore(&vhbainfo->privlock, flags);
 267                        return -1;
 268                }
 269        }
 270
 271        vhbainfo->pending[insert_location].cmdtype = cmdtype;
 272        vhbainfo->pending[insert_location].sent = new;
 273        vhbainfo->nextinsert = (insert_location + 1) % MAX_PENDING_REQUESTS;
 274        spin_unlock_irqrestore(&vhbainfo->privlock, flags);
 275
 276        return insert_location;
 277}
 278
 279static unsigned int
 280add_scsipending_entry_with_wait(struct virthba_info *vhbainfo, char cmdtype,
 281                                void *new)
 282{
 283        int insert_location = add_scsipending_entry(vhbainfo, cmdtype, new);
 284
 285        while (insert_location == -1) {
 286                LOGERR("Failed to find empty queue slot.  Waiting to try again\n");
 287                set_current_state(TASK_INTERRUPTIBLE);
 288                schedule_timeout(msecs_to_jiffies(10));
 289                insert_location = add_scsipending_entry(vhbainfo, cmdtype, new);
 290        }
 291
 292        return (unsigned int) insert_location;
 293}
 294
 295static void *
 296del_scsipending_entry(struct virthba_info *vhbainfo, uintptr_t del)
 297{
 298        unsigned long flags;
 299        void *sent = NULL;
 300
 301        if (del >= MAX_PENDING_REQUESTS) {
 302                LOGERR("Invalid queue position <<%lu>> given to delete. MAX_PENDING_REQUESTS <<%d>>\n",
 303                     (unsigned long) del, MAX_PENDING_REQUESTS);
 304        } else {
 305                spin_lock_irqsave(&vhbainfo->privlock, flags);
 306
 307                if (vhbainfo->pending[del].sent == NULL)
 308                        LOGERR("Deleting already cleared queue entry at <<%lu>>.\n",
 309                             (unsigned long) del);
 310
 311                sent = vhbainfo->pending[del].sent;
 312
 313                vhbainfo->pending[del].cmdtype = 0;
 314                vhbainfo->pending[del].sent = NULL;
 315                spin_unlock_irqrestore(&vhbainfo->privlock, flags);
 316        }
 317
 318        return sent;
 319}
 320
 321/* DARWorkQ (Disk Add/Remove) */
 322static struct work_struct DARWorkQ;
 323static struct diskaddremove *DARWorkQHead;
 324static spinlock_t DARWorkQLock;
 325static unsigned short DARWorkQSched;
 326#define QUEUE_DISKADDREMOVE(dar) { \
 327        spin_lock_irqsave(&DARWorkQLock, flags); \
 328        if (!DARWorkQHead) { \
 329                DARWorkQHead = dar; \
 330                dar->next = NULL; \
 331        } \
 332        else { \
 333                dar->next = DARWorkQHead; \
 334                DARWorkQHead = dar; \
 335        } \
 336        if (!DARWorkQSched) { \
 337                schedule_work(&DARWorkQ); \
 338                DARWorkQSched = 1; \
 339        } \
 340        spin_unlock_irqrestore(&DARWorkQLock, flags); \
 341}
 342
 343static inline void
 344SendDiskAddRemove(struct diskaddremove *dar)
 345{
 346        struct scsi_device *sdev;
 347        int error;
 348
 349        sdev = scsi_device_lookup(dar->shost, dar->channel, dar->id, dar->lun);
 350        if (sdev) {
 351                if (!(dar->add))
 352                        scsi_remove_device(sdev);
 353        } else if (dar->add) {
 354                error =
 355                    scsi_add_device(dar->shost, dar->channel, dar->id,
 356                                    dar->lun);
 357                if (error)
 358                        LOGERR("Failed scsi_add_device: host_no=%d[chan=%d:id=%d:lun=%d]\n",
 359                             dar->shost->host_no, dar->channel, dar->id,
 360                             dar->lun);
 361        } else
 362                LOGERR("Failed scsi_device_lookup:[chan=%d:id=%d:lun=%d]\n",
 363                       dar->channel, dar->id, dar->lun);
 364        kfree(dar);
 365}
 366
 367/*****************************************************/
 368/* DARWorkQ Handler Thread                           */
 369/*****************************************************/
 370static void
 371doDiskAddRemove(struct work_struct *work)
 372{
 373        struct diskaddremove *dar;
 374        struct diskaddremove *tmphead;
 375        int i = 0;
 376        unsigned long flags;
 377
 378        spin_lock_irqsave(&DARWorkQLock, flags);
 379        tmphead = DARWorkQHead;
 380        DARWorkQHead = NULL;
 381        DARWorkQSched = 0;
 382        spin_unlock_irqrestore(&DARWorkQLock, flags);
 383        while (tmphead) {
 384                dar = tmphead;
 385                tmphead = dar->next;
 386                SendDiskAddRemove(dar);
 387                i++;
 388        }
 389}
 390
 391/*****************************************************/
 392/* Routine to add entry to DARWorkQ                  */
 393/*****************************************************/
 394static void
 395process_disk_notify(struct Scsi_Host *shost, struct uiscmdrsp *cmdrsp)
 396{
 397        struct diskaddremove *dar;
 398        unsigned long flags;
 399
 400        dar = kzalloc(sizeof(struct diskaddremove), GFP_ATOMIC);
 401        if (dar) {
 402                dar->add = cmdrsp->disknotify.add;
 403                dar->shost = shost;
 404                dar->channel = cmdrsp->disknotify.channel;
 405                dar->id = cmdrsp->disknotify.id;
 406                dar->lun = cmdrsp->disknotify.lun;
 407                QUEUE_DISKADDREMOVE(dar);
 408        } else {
 409                LOGERR("kmalloc failed for dar. host_no=%d[chan=%d:id=%d:lun=%d]\n",
 410                     shost->host_no, cmdrsp->disknotify.channel,
 411                     cmdrsp->disknotify.id, cmdrsp->disknotify.lun);
 412        }
 413}
 414
 415/*****************************************************/
 416/* Probe Remove Functions                            */
 417/*****************************************************/
 418static irqreturn_t
 419virthba_ISR(int irq, void *dev_id)
 420{
 421        struct virthba_info *virthbainfo = (struct virthba_info *) dev_id;
 422        struct channel_header __iomem *pChannelHeader;
 423        struct signal_queue_header __iomem *pqhdr;
 424        u64 mask;
 425        unsigned long long rc1;
 426
 427        if (virthbainfo == NULL)
 428                return IRQ_NONE;
 429        virthbainfo->interrupts_rcvd++;
 430        pChannelHeader = virthbainfo->chinfo.queueinfo->chan;
 431        if (((readq(&pChannelHeader->features)
 432              & ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS) != 0)
 433            && ((readq(&pChannelHeader->features) &
 434                 ULTRA_IO_DRIVER_DISABLES_INTS) !=
 435                0)) {
 436                virthbainfo->interrupts_disabled++;
 437                mask = ~ULTRA_CHANNEL_ENABLE_INTS;
 438                rc1 = uisqueue_interlocked_and(virthbainfo->flags_addr, mask);
 439        }
 440        if (spar_signalqueue_empty(pChannelHeader, IOCHAN_FROM_IOPART)) {
 441                virthbainfo->interrupts_notme++;
 442                return IRQ_NONE;
 443        }
 444        pqhdr = (struct signal_queue_header __iomem *)
 445                ((char __iomem *) pChannelHeader +
 446                 readq(&pChannelHeader->ch_space_offset)) + IOCHAN_FROM_IOPART;
 447        writeq(readq(&pqhdr->num_irq_received) + 1,
 448               &pqhdr->num_irq_received);
 449        atomic_set(&virthbainfo->interrupt_rcvd, 1);
 450        wake_up_interruptible(&virthbainfo->rsp_queue);
 451        return IRQ_HANDLED;
 452}
 453
 454static int
 455virthba_probe(struct virtpci_dev *virtpcidev, const struct pci_device_id *id)
 456{
 457        int error;
 458        struct Scsi_Host *scsihost;
 459        struct virthba_info *virthbainfo;
 460        int rsp;
 461        int i;
 462        irq_handler_t handler = virthba_ISR;
 463        struct channel_header __iomem *pChannelHeader;
 464        struct signal_queue_header __iomem *pqhdr;
 465        u64 mask;
 466
 467        LOGVER("entering virthba_probe...\n");
 468        LOGVER("virtpcidev bus_no<<%d>>devNo<<%d>>", virtpcidev->bus_no,
 469               virtpcidev->device_no);
 470
 471        LOGINF("entering virthba_probe...\n");
 472        LOGINF("virtpcidev bus_no<<%d>>devNo<<%d>>", virtpcidev->bus_no,
 473               virtpcidev->device_no);
 474        POSTCODE_LINUX_2(VHBA_PROBE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
 475        /* call scsi_host_alloc to register a scsi host adapter
 476         * instance - this virthba that has just been created is an
 477         * instance of a scsi host adapter. This scsi_host_alloc
 478         * function allocates a new Scsi_Host struct & performs basic
 479         * initializatoin.  The host is not published to the scsi
 480         * midlayer until scsi_add_host is called.
 481         */
 482        DBGINF("calling scsi_host_alloc.\n");
 483
 484        /* arg 2 passed in length of extra space we want allocated
 485         * with scsi_host struct for our own use scsi_host_alloc
 486         * assign host_no
 487         */
 488        scsihost = scsi_host_alloc(&virthba_driver_template,
 489                                   sizeof(struct virthba_info));
 490        if (scsihost == NULL)
 491                return -ENODEV;
 492
 493        DBGINF("scsihost: 0x%p, scsihost->this_id: %d, host_no: %d.\n",
 494               scsihost, scsihost->this_id, scsihost->host_no);
 495
 496        scsihost->this_id = UIS_MAGIC_VHBA;
 497        /* linux treats max-channel differently than max-id & max-lun.
 498         * In the latter cases, those two values result in 0 to max-1
 499         * (inclusive) being scanned. But in the case of channels, the
 500         * scan is 0 to max (inclusive); so we will subtract one from
 501         * the max-channel value.
 502         */
 503        LOGINF("virtpcidev->scsi.max.max_channel=%u, max_id=%u, max_lun=%u, cmd_per_lun=%u, max_io_size=%u\n",
 504             (unsigned) virtpcidev->scsi.max.max_channel - 1,
 505             (unsigned) virtpcidev->scsi.max.max_id,
 506             (unsigned) virtpcidev->scsi.max.max_lun,
 507             (unsigned) virtpcidev->scsi.max.cmd_per_lun,
 508             (unsigned) virtpcidev->scsi.max.max_io_size);
 509        scsihost->max_channel = (unsigned) virtpcidev->scsi.max.max_channel;
 510        scsihost->max_id = (unsigned) virtpcidev->scsi.max.max_id;
 511        scsihost->max_lun = (unsigned) virtpcidev->scsi.max.max_lun;
 512        scsihost->cmd_per_lun = (unsigned) virtpcidev->scsi.max.cmd_per_lun;
 513        scsihost->max_sectors =
 514            (unsigned short) (virtpcidev->scsi.max.max_io_size >> 9);
 515        scsihost->sg_tablesize =
 516            (unsigned short) (virtpcidev->scsi.max.max_io_size / PAGE_SIZE);
 517        if (scsihost->sg_tablesize > MAX_PHYS_INFO)
 518                scsihost->sg_tablesize = MAX_PHYS_INFO;
 519        LOGINF("scsihost->max_channel=%u, max_id=%u, max_lun=%llu, cmd_per_lun=%u, max_sectors=%hu, sg_tablesize=%hu\n",
 520             scsihost->max_channel, scsihost->max_id, scsihost->max_lun,
 521             scsihost->cmd_per_lun, scsihost->max_sectors,
 522             scsihost->sg_tablesize);
 523        LOGINF("scsihost->can_queue=%u, scsihost->cmd_per_lun=%u, max_sectors=%hu, sg_tablesize=%hu\n",
 524             scsihost->can_queue, scsihost->cmd_per_lun, scsihost->max_sectors,
 525             scsihost->sg_tablesize);
 526
 527        DBGINF("calling scsi_add_host\n");
 528
 529        /* this creates "host%d" in sysfs.  If 2nd argument is NULL,
 530         * then this generic /sys/devices/platform/host?  device is
 531         * created and /sys/scsi_host/host? ->
 532         * /sys/devices/platform/host?  If 2nd argument is not NULL,
 533         * then this generic /sys/devices/<path>/host? is created and
 534         * host? points to that device instead.
 535         */
 536        error = scsi_add_host(scsihost, &virtpcidev->generic_dev);
 537        if (error) {
 538                LOGERR("scsi_add_host ****FAILED 0x%x  TBD - RECOVER\n", error);
 539                POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
 540                /* decr refcount on scsihost which was incremented by
 541                 * scsi_add_host so the scsi_host gets deleted
 542                 */
 543                scsi_host_put(scsihost);
 544                return -ENODEV;
 545        }
 546
 547        virthbainfo = (struct virthba_info *) scsihost->hostdata;
 548        memset(virthbainfo, 0, sizeof(struct virthba_info));
 549        for (i = 0; i < VIRTHBASOPENMAX; i++) {
 550                if (VirtHbasOpen[i].virthbainfo == NULL) {
 551                        VirtHbasOpen[i].virthbainfo = virthbainfo;
 552                        break;
 553                }
 554        }
 555        virthbainfo->interrupt_vector = -1;
 556        virthbainfo->chinfo.queueinfo = &virtpcidev->queueinfo;
 557        virthbainfo->virtpcidev = virtpcidev;
 558        spin_lock_init(&virthbainfo->chinfo.insertlock);
 559
 560        DBGINF("generic_dev: 0x%p, queueinfo: 0x%p.\n",
 561               &virtpcidev->generic_dev, &virtpcidev->queueinfo);
 562
 563        init_waitqueue_head(&virthbainfo->rsp_queue);
 564        spin_lock_init(&virthbainfo->privlock);
 565        memset(&virthbainfo->pending, 0, sizeof(virthbainfo->pending));
 566        virthbainfo->serverdown = false;
 567        virthbainfo->serverchangingstate = false;
 568
 569        virthbainfo->intr = virtpcidev->intr;
 570        /* save of host within virthba_info */
 571        virthbainfo->scsihost = scsihost;
 572
 573        /* save of host within virtpci_dev */
 574        virtpcidev->scsi.scsihost = scsihost;
 575
 576        /* Setup workqueue for serverdown messages */
 577        INIT_WORK(&virthbainfo->serverdown_completion,
 578                  virthba_serverdown_complete);
 579
 580        writeq(readq(&virthbainfo->chinfo.queueinfo->chan->features) |
 581               ULTRA_IO_CHANNEL_IS_POLLING,
 582               &virthbainfo->chinfo.queueinfo->chan->features);
 583        /* start thread that will receive scsicmnd responses */
 584        DBGINF("starting rsp thread -- queueinfo: 0x%p, threadinfo: 0x%p.\n",
 585               virthbainfo->chinfo.queueinfo, &virthbainfo->chinfo.threadinfo);
 586
 587        pChannelHeader = virthbainfo->chinfo.queueinfo->chan;
 588        pqhdr = (struct signal_queue_header __iomem *)
 589                ((char __iomem *)pChannelHeader +
 590                 readq(&pChannelHeader->ch_space_offset)) + IOCHAN_FROM_IOPART;
 591        virthbainfo->flags_addr = &pqhdr->features;
 592
 593        if (!uisthread_start(&virthbainfo->chinfo.threadinfo,
 594                             process_incoming_rsps,
 595                             virthbainfo, "vhba_incoming")) {
 596                LOGERR("uisthread_start rsp ****FAILED\n");
 597                /* decr refcount on scsihost which was incremented by
 598                 * scsi_add_host so the scsi_host gets deleted
 599                 */
 600                POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
 601                scsi_host_put(scsihost);
 602                return -ENODEV;
 603        }
 604        LOGINF("sendInterruptHandle=0x%16llX",
 605               virthbainfo->intr.send_irq_handle);
 606        LOGINF("recvInterruptHandle=0x%16llX",
 607               virthbainfo->intr.recv_irq_handle);
 608        LOGINF("recvInterruptVector=0x%8X",
 609               virthbainfo->intr.recv_irq_vector);
 610        LOGINF("recvInterruptShared=0x%2X",
 611               virthbainfo->intr.recv_irq_shared);
 612        LOGINF("scsihost.hostt->name=%s", scsihost->hostt->name);
 613        virthbainfo->interrupt_vector =
 614            virthbainfo->intr.recv_irq_handle & INTERRUPT_VECTOR_MASK;
 615        rsp = request_irq(virthbainfo->interrupt_vector, handler, IRQF_SHARED,
 616                          scsihost->hostt->name, virthbainfo);
 617        if (rsp != 0) {
 618                LOGERR("request_irq(%d) uislib_virthba_ISR request failed with rsp=%d\n",
 619                       virthbainfo->interrupt_vector, rsp);
 620                virthbainfo->interrupt_vector = -1;
 621                POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
 622        } else {
 623                u64 __iomem *Features_addr =
 624                    &virthbainfo->chinfo.queueinfo->chan->features;
 625                LOGERR("request_irq(%d) uislib_virthba_ISR request succeeded\n",
 626                       virthbainfo->interrupt_vector);
 627                mask = ~(ULTRA_IO_CHANNEL_IS_POLLING |
 628                         ULTRA_IO_DRIVER_DISABLES_INTS);
 629                uisqueue_interlocked_and(Features_addr, mask);
 630                mask = ULTRA_IO_DRIVER_ENABLES_INTS;
 631                uisqueue_interlocked_or(Features_addr, mask);
 632                rsltq_wait_usecs = 4000000;
 633        }
 634
 635        DBGINF("calling scsi_scan_host.\n");
 636        scsi_scan_host(scsihost);
 637        DBGINF("return from scsi_scan_host.\n");
 638
 639        LOGINF("virthba added scsihost:0x%p\n", scsihost);
 640        POSTCODE_LINUX_2(VHBA_PROBE_EXIT_PC, POSTCODE_SEVERITY_INFO);
 641        return 0;
 642}
 643
 644static void
 645virthba_remove(struct virtpci_dev *virtpcidev)
 646{
 647        struct virthba_info *virthbainfo;
 648        struct Scsi_Host *scsihost =
 649            (struct Scsi_Host *) virtpcidev->scsi.scsihost;
 650
 651        LOGINF("virtpcidev bus_no<<%d>>devNo<<%d>>", virtpcidev->bus_no,
 652               virtpcidev->device_no);
 653        virthbainfo = (struct virthba_info *) scsihost->hostdata;
 654        if (virthbainfo->interrupt_vector != -1)
 655                free_irq(virthbainfo->interrupt_vector, virthbainfo);
 656        LOGINF("Removing virtpcidev: 0x%p, virthbainfo: 0x%p\n", virtpcidev,
 657               virthbainfo);
 658
 659        DBGINF("removing scsihost: 0x%p, scsihost->this_id: %d\n", scsihost,
 660               scsihost->this_id);
 661        scsi_remove_host(scsihost);
 662
 663        DBGINF("stopping thread.\n");
 664        uisthread_stop(&virthbainfo->chinfo.threadinfo);
 665
 666        DBGINF("calling scsi_host_put\n");
 667
 668        /* decr refcount on scsihost which was incremented by
 669         * scsi_add_host so the scsi_host gets deleted
 670         */
 671        scsi_host_put(scsihost);
 672        LOGINF("virthba removed scsi_host.\n");
 673}
 674
 675static int
 676forward_vdiskmgmt_command(enum vdisk_mgmt_types vdiskcmdtype,
 677                          struct Scsi_Host *scsihost,
 678                          struct uisscsi_dest *vdest)
 679{
 680        struct uiscmdrsp *cmdrsp;
 681        struct virthba_info *virthbainfo =
 682            (struct virthba_info *) scsihost->hostdata;
 683        int notifyresult = 0xffff;
 684        wait_queue_head_t notifyevent;
 685
 686        LOGINF("vDiskMgmt:%d %d:%d:%d\n", vdiskcmdtype,
 687               vdest->channel, vdest->id, vdest->lun);
 688
 689        if (virthbainfo->serverdown || virthbainfo->serverchangingstate) {
 690                DBGINF("Server is down/changing state. Returning Failure.\n");
 691                return FAILED;
 692        }
 693
 694        cmdrsp = kzalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
 695        if (cmdrsp == NULL) {
 696                LOGERR("kmalloc of cmdrsp failed.\n");
 697                return FAILED;  /* reject */
 698        }
 699
 700        init_waitqueue_head(&notifyevent);
 701
 702        /* issue VDISK_MGMT_CMD
 703         * set type to command - as opposed to task mgmt
 704         */
 705        cmdrsp->cmdtype = CMD_VDISKMGMT_TYPE;
 706        /* specify the event that has to be triggered when this cmd is
 707         * complete
 708         */
 709        cmdrsp->vdiskmgmt.notify = (void *) &notifyevent;
 710        cmdrsp->vdiskmgmt.notifyresult = (void *) &notifyresult;
 711
 712        /* save destination */
 713        cmdrsp->vdiskmgmt.vdisktype = vdiskcmdtype;
 714        cmdrsp->vdiskmgmt.vdest.channel = vdest->channel;
 715        cmdrsp->vdiskmgmt.vdest.id = vdest->id;
 716        cmdrsp->vdiskmgmt.vdest.lun = vdest->lun;
 717        cmdrsp->vdiskmgmt.scsicmd =
 718            (void *) (uintptr_t)
 719                add_scsipending_entry_with_wait(virthbainfo, CMD_VDISKMGMT_TYPE,
 720                                                (void *) cmdrsp);
 721
 722        uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
 723                                             cmdrsp, IOCHAN_TO_IOPART,
 724                                             &virthbainfo->chinfo.insertlock,
 725                                             DONT_ISSUE_INTERRUPT, (u64) NULL,
 726                                             OK_TO_WAIT, "vhba");
 727        LOGINF("VdiskMgmt waiting on event notifyevent=0x%p\n",
 728               cmdrsp->scsitaskmgmt.notify);
 729        wait_event(notifyevent, notifyresult != 0xffff);
 730        LOGINF("VdiskMgmt complete; result:%d\n", cmdrsp->vdiskmgmt.result);
 731        kfree(cmdrsp);
 732        return SUCCESS;
 733}
 734
 735/*****************************************************/
 736/* Scsi Host support functions                       */
 737/*****************************************************/
 738
 739static int
 740forward_taskmgmt_command(enum task_mgmt_types tasktype,
 741                         struct scsi_device *scsidev)
 742{
 743        struct uiscmdrsp *cmdrsp;
 744        struct virthba_info *virthbainfo =
 745            (struct virthba_info *) scsidev->host->hostdata;
 746        int notifyresult = 0xffff;
 747        wait_queue_head_t notifyevent;
 748
 749        LOGINF("TaskMgmt:%d %d:%d:%llu\n", tasktype,
 750               scsidev->channel, scsidev->id, scsidev->lun);
 751
 752        if (virthbainfo->serverdown || virthbainfo->serverchangingstate) {
 753                DBGINF("Server is down/changing state. Returning Failure.\n");
 754                return FAILED;
 755        }
 756
 757        cmdrsp = kzalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
 758        if (cmdrsp == NULL) {
 759                LOGERR("kmalloc of cmdrsp failed.\n");
 760                return FAILED;  /* reject */
 761        }
 762
 763        init_waitqueue_head(&notifyevent);
 764
 765        /* issue TASK_MGMT_ABORT_TASK */
 766        /* set type to command - as opposed to task mgmt */
 767        cmdrsp->cmdtype = CMD_SCSITASKMGMT_TYPE;
 768        /* specify the event that has to be triggered when this */
 769        /* cmd is complete */
 770        cmdrsp->scsitaskmgmt.notify = (void *) &notifyevent;
 771        cmdrsp->scsitaskmgmt.notifyresult = (void *) &notifyresult;
 772
 773        /* save destination */
 774        cmdrsp->scsitaskmgmt.tasktype = tasktype;
 775        cmdrsp->scsitaskmgmt.vdest.channel = scsidev->channel;
 776        cmdrsp->scsitaskmgmt.vdest.id = scsidev->id;
 777        cmdrsp->scsitaskmgmt.vdest.lun = scsidev->lun;
 778        cmdrsp->scsitaskmgmt.scsicmd =
 779            (void *) (uintptr_t)
 780                add_scsipending_entry_with_wait(virthbainfo,
 781                                                CMD_SCSITASKMGMT_TYPE,
 782                                                (void *) cmdrsp);
 783
 784        uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
 785                                             cmdrsp, IOCHAN_TO_IOPART,
 786                                             &virthbainfo->chinfo.insertlock,
 787                                             DONT_ISSUE_INTERRUPT, (u64) NULL,
 788                                             OK_TO_WAIT, "vhba");
 789        LOGINF("TaskMgmt waiting on event notifyevent=0x%p\n",
 790               cmdrsp->scsitaskmgmt.notify);
 791        wait_event(notifyevent, notifyresult != 0xffff);
 792        LOGINF("TaskMgmt complete; result:%d\n", cmdrsp->scsitaskmgmt.result);
 793        kfree(cmdrsp);
 794        return SUCCESS;
 795}
 796
 797/* The abort handler returns SUCCESS if it has succeeded to make LLDD
 798 * and all related hardware forget about the scmd.
 799 */
 800static int
 801virthba_abort_handler(struct scsi_cmnd *scsicmd)
 802{
 803        /* issue TASK_MGMT_ABORT_TASK */
 804        struct scsi_device *scsidev;
 805        struct virtdisk_info *vdisk;
 806
 807        scsidev = scsicmd->device;
 808        for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
 809             vdisk->next; vdisk = vdisk->next) {
 810                if ((scsidev->channel == vdisk->channel)
 811                    && (scsidev->id == vdisk->id)
 812                    && (scsidev->lun == vdisk->lun)) {
 813                        if (atomic_read(&vdisk->error_count) <
 814                            VIRTHBA_ERROR_COUNT) {
 815                                atomic_inc(&vdisk->error_count);
 816                                POSTCODE_LINUX_2(VHBA_COMMAND_HANDLER_PC,
 817                                                 POSTCODE_SEVERITY_INFO);
 818                        } else
 819                                atomic_set(&vdisk->ios_threshold,
 820                                           IOS_ERROR_THRESHOLD);
 821                }
 822        }
 823        return forward_taskmgmt_command(TASK_MGMT_ABORT_TASK, scsicmd->device);
 824}
 825
 826static int
 827virthba_bus_reset_handler(struct scsi_cmnd *scsicmd)
 828{
 829        /* issue TASK_MGMT_TARGET_RESET for each target on the bus */
 830        struct scsi_device *scsidev;
 831        struct virtdisk_info *vdisk;
 832
 833        scsidev = scsicmd->device;
 834        for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
 835             vdisk->next; vdisk = vdisk->next) {
 836                if ((scsidev->channel == vdisk->channel)
 837                    && (scsidev->id == vdisk->id)
 838                    && (scsidev->lun == vdisk->lun)) {
 839                        if (atomic_read(&vdisk->error_count) <
 840                            VIRTHBA_ERROR_COUNT) {
 841                                atomic_inc(&vdisk->error_count);
 842                                POSTCODE_LINUX_2(VHBA_COMMAND_HANDLER_PC,
 843                                                 POSTCODE_SEVERITY_INFO);
 844                        } else
 845                                atomic_set(&vdisk->ios_threshold,
 846                                           IOS_ERROR_THRESHOLD);
 847                }
 848        }
 849        return forward_taskmgmt_command(TASK_MGMT_BUS_RESET, scsicmd->device);
 850}
 851
 852static int
 853virthba_device_reset_handler(struct scsi_cmnd *scsicmd)
 854{
 855        /* issue TASK_MGMT_LUN_RESET */
 856        struct scsi_device *scsidev;
 857        struct virtdisk_info *vdisk;
 858
 859        scsidev = scsicmd->device;
 860        for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
 861             vdisk->next; vdisk = vdisk->next) {
 862                if ((scsidev->channel == vdisk->channel)
 863                    && (scsidev->id == vdisk->id)
 864                    && (scsidev->lun == vdisk->lun)) {
 865                        if (atomic_read(&vdisk->error_count) <
 866                            VIRTHBA_ERROR_COUNT) {
 867                                atomic_inc(&vdisk->error_count);
 868                                POSTCODE_LINUX_2(VHBA_COMMAND_HANDLER_PC,
 869                                                 POSTCODE_SEVERITY_INFO);
 870                        } else
 871                                atomic_set(&vdisk->ios_threshold,
 872                                           IOS_ERROR_THRESHOLD);
 873                }
 874        }
 875        return forward_taskmgmt_command(TASK_MGMT_LUN_RESET, scsicmd->device);
 876}
 877
 878static int
 879virthba_host_reset_handler(struct scsi_cmnd *scsicmd)
 880{
 881        /* issue TASK_MGMT_TARGET_RESET for each target on each bus for host */
 882        LOGERR("virthba_host_reset_handler Not yet implemented\n");
 883        return SUCCESS;
 884}
 885
 886static char virthba_get_info_str[256];
 887
 888static const char *
 889virthba_get_info(struct Scsi_Host *shp)
 890{
 891        /* Return version string */
 892        sprintf(virthba_get_info_str, "virthba, version %s\n", VIRTHBA_VERSION);
 893        return virthba_get_info_str;
 894}
 895
 896static int
 897virthba_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
 898{
 899        DBGINF("In virthba_ioctl: ioctl: cmd=0x%x\n", cmd);
 900        return -EINVAL;
 901}
 902
 903/* This returns SCSI_MLQUEUE_DEVICE_BUSY if the signal queue to IOpart
 904 * is full.
 905 */
 906static int
 907virthba_queue_command_lck(struct scsi_cmnd *scsicmd,
 908                          void (*virthba_cmnd_done)(struct scsi_cmnd *))
 909{
 910        struct scsi_device *scsidev = scsicmd->device;
 911        int insert_location;
 912        unsigned char op;
 913        unsigned char *cdb = scsicmd->cmnd;
 914        struct Scsi_Host *scsihost = scsidev->host;
 915        struct uiscmdrsp *cmdrsp;
 916        unsigned int i;
 917        struct virthba_info *virthbainfo =
 918            (struct virthba_info *) scsihost->hostdata;
 919        struct scatterlist *sg = NULL;
 920        struct scatterlist *sgl = NULL;
 921        int sg_failed = 0;
 922
 923        if (virthbainfo->serverdown || virthbainfo->serverchangingstate) {
 924                DBGINF("Server is down/changing state. Returning SCSI_MLQUEUE_DEVICE_BUSY.\n");
 925                return SCSI_MLQUEUE_DEVICE_BUSY;
 926        }
 927
 928        cmdrsp = kzalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
 929        if (cmdrsp == NULL) {
 930                LOGERR("kmalloc of cmdrsp failed.\n");
 931                return 1;       /* reject the command */
 932        }
 933
 934        /* now saving everything we need from scsi_cmd into cmdrsp
 935         * before we queue cmdrsp set type to command - as opposed to
 936         * task mgmt
 937         */
 938        cmdrsp->cmdtype = CMD_SCSI_TYPE;
 939        /* save the pending insertion location.  Deletion from pending
 940         * will return the scsicmd pointer for completion
 941         */
 942        insert_location =
 943            add_scsipending_entry(virthbainfo, CMD_SCSI_TYPE, (void *) scsicmd);
 944        if (insert_location != -1) {
 945                cmdrsp->scsi.scsicmd = (void *) (uintptr_t) insert_location;
 946        } else {
 947                LOGERR("Queue is full. Returning busy.\n");
 948                kfree(cmdrsp);
 949                return SCSI_MLQUEUE_DEVICE_BUSY;
 950        }
 951        /* save done function that we have call when cmd is complete */
 952        scsicmd->scsi_done = virthba_cmnd_done;
 953        /* save destination */
 954        cmdrsp->scsi.vdest.channel = scsidev->channel;
 955        cmdrsp->scsi.vdest.id = scsidev->id;
 956        cmdrsp->scsi.vdest.lun = scsidev->lun;
 957        /* save datadir */
 958        cmdrsp->scsi.data_dir = scsicmd->sc_data_direction;
 959        memcpy(cmdrsp->scsi.cmnd, cdb, MAX_CMND_SIZE);
 960
 961        cmdrsp->scsi.bufflen = scsi_bufflen(scsicmd);
 962
 963        /* keep track of the max buffer length so far. */
 964        if (cmdrsp->scsi.bufflen > MaxBuffLen)
 965                MaxBuffLen = cmdrsp->scsi.bufflen;
 966
 967        if (scsi_sg_count(scsicmd) > MAX_PHYS_INFO) {
 968                LOGERR("scsicmd use_sg:%d greater than MAX:%d\n",
 969                       scsi_sg_count(scsicmd), MAX_PHYS_INFO);
 970                del_scsipending_entry(virthbainfo, (uintptr_t) insert_location);
 971                kfree(cmdrsp);
 972                return 1;       /* reject the command */
 973        }
 974
 975        /* This is what we USED to do when we assumed we were running */
 976        /* uissd & virthba on the same Linux system. */
 977        /* cmdrsp->scsi.buffer = scsicmd->request_buffer; */
 978        /* The following code does NOT make that assumption. */
 979        /* convert buffer to phys information */
 980        if (scsi_sg_count(scsicmd) == 0) {
 981                if (scsi_bufflen(scsicmd) > 0) {
 982                        LOGERR("**** FAILED No scatter list for bufflen > 0\n");
 983                        BUG_ON(scsi_sg_count(scsicmd) == 0);
 984                }
 985                DBGINF("No sg; buffer:0x%p bufflen:%d\n",
 986                       scsi_sglist(scsicmd), scsi_bufflen(scsicmd));
 987        } else {
 988                /* buffer is scatterlist - copy it out */
 989                sgl = scsi_sglist(scsicmd);
 990
 991                for_each_sg(sgl, sg, scsi_sg_count(scsicmd), i) {
 992
 993                        cmdrsp->scsi.gpi_list[i].address = sg_phys(sg);
 994                        cmdrsp->scsi.gpi_list[i].length = sg->length;
 995                        if ((i != 0) && (sg->offset != 0))
 996                                LOGINF("Offset on a sg_entry other than zero =<<%d>>.\n",
 997                                     sg->offset);
 998                }
 999
1000                if (sg_failed) {
1001                        LOGERR("Start sg_list dump (entries %d, bufflen %d)...\n",
1002                             scsi_sg_count(scsicmd), cmdrsp->scsi.bufflen);
1003                        for_each_sg(sgl, sg, scsi_sg_count(scsicmd), i) {
1004                                LOGERR("   Entry(%d): page->[0x%p], phys->[0x%Lx], off(%d), len(%d)\n",
1005                                     i, sg_page(sg),
1006                                     (unsigned long long) sg_phys(sg),
1007                                     sg->offset, sg->length);
1008                        }
1009                        LOGERR("Done sg_list dump.\n");
1010                        /* BUG(); ***** For now, let it fail in uissd
1011                         * if it is a problem, as it might just
1012                         * work
1013                         */
1014                }
1015
1016                cmdrsp->scsi.guest_phys_entries = scsi_sg_count(scsicmd);
1017        }
1018
1019        op = cdb[0];
1020        i = uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
1021                                                 cmdrsp, IOCHAN_TO_IOPART,
1022                                                 &virthbainfo->chinfo.
1023                                                 insertlock,
1024                                                 DONT_ISSUE_INTERRUPT,
1025                                                 (u64) NULL, DONT_WAIT, "vhba");
1026        if (i == 0) {
1027                /* queue must be full - and we said don't wait - return busy */
1028                LOGERR("uisqueue_put_cmdrsp_with_lock ****FAILED\n");
1029                kfree(cmdrsp);
1030                del_scsipending_entry(virthbainfo, (uintptr_t) insert_location);
1031                return SCSI_MLQUEUE_DEVICE_BUSY;
1032        }
1033
1034        /* we're done with cmdrsp space - data from it has been copied
1035         * into channel - free it now.
1036         */
1037        kfree(cmdrsp);
1038        return 0;               /* non-zero implies host/device is busy */
1039}
1040
1041static int
1042virthba_slave_alloc(struct scsi_device *scsidev)
1043{
1044        /* this called by the midlayer before scan for new devices -
1045         * LLD can alloc any struct & do init if needed.
1046         */
1047        struct virtdisk_info *vdisk;
1048        struct virtdisk_info *tmpvdisk;
1049        struct virthba_info *virthbainfo;
1050        struct Scsi_Host *scsihost = (struct Scsi_Host *) scsidev->host;
1051
1052        virthbainfo = (struct virthba_info *) scsihost->hostdata;
1053        if (!virthbainfo) {
1054                LOGERR("Could not find virthba_info for scsihost\n");
1055                return 0;       /* even though we errored, treat as success */
1056        }
1057        for (vdisk = &virthbainfo->head; vdisk->next; vdisk = vdisk->next) {
1058                if (vdisk->next->valid &&
1059                    (vdisk->next->channel == scsidev->channel) &&
1060                    (vdisk->next->id == scsidev->id) &&
1061                    (vdisk->next->lun == scsidev->lun))
1062                        return 0;
1063        }
1064        tmpvdisk = kzalloc(sizeof(struct virtdisk_info), GFP_ATOMIC);
1065        if (!tmpvdisk) {        /* error allocating */
1066                LOGERR("Could not allocate memory for disk\n");
1067                return 0;
1068        }
1069
1070        tmpvdisk->channel = scsidev->channel;
1071        tmpvdisk->id = scsidev->id;
1072        tmpvdisk->lun = scsidev->lun;
1073        tmpvdisk->valid = 1;
1074        vdisk->next = tmpvdisk;
1075        return 0;               /* success */
1076}
1077
1078static int
1079virthba_slave_configure(struct scsi_device *scsidev)
1080{
1081        return 0;               /* success */
1082}
1083
1084static void
1085virthba_slave_destroy(struct scsi_device *scsidev)
1086{
1087        /* midlevel calls this after device has been quiesced and
1088         * before it is to be deleted.
1089         */
1090        struct virtdisk_info *vdisk, *delvdisk;
1091        struct virthba_info *virthbainfo;
1092        struct Scsi_Host *scsihost = (struct Scsi_Host *) scsidev->host;
1093
1094        virthbainfo = (struct virthba_info *) scsihost->hostdata;
1095        if (!virthbainfo)
1096                LOGERR("Could not find virthba_info for scsihost\n");
1097        for (vdisk = &virthbainfo->head; vdisk->next; vdisk = vdisk->next) {
1098                if (vdisk->next->valid &&
1099                    (vdisk->next->channel == scsidev->channel) &&
1100                    (vdisk->next->id == scsidev->id) &&
1101                    (vdisk->next->lun == scsidev->lun)) {
1102                        delvdisk = vdisk->next;
1103                        vdisk->next = vdisk->next->next;
1104                        kfree(delvdisk);
1105                        return;
1106                }
1107        }
1108}
1109
1110/*****************************************************/
1111/* Scsi Cmnd support thread                          */
1112/*****************************************************/
1113
1114static void
1115do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
1116{
1117        struct virtdisk_info *vdisk;
1118        struct scsi_device *scsidev;
1119        struct sense_data *sd;
1120
1121        scsidev = scsicmd->device;
1122        memcpy(scsicmd->sense_buffer, cmdrsp->scsi.sensebuf, MAX_SENSE_SIZE);
1123        sd = (struct sense_data *) scsicmd->sense_buffer;
1124
1125        /* Do not log errors for disk-not-present inquiries */
1126        if ((cmdrsp->scsi.cmnd[0] == INQUIRY) &&
1127            (host_byte(cmdrsp->scsi.linuxstat) == DID_NO_CONNECT) &&
1128            (cmdrsp->scsi.addlstat == ADDL_SEL_TIMEOUT))
1129                return;
1130
1131        /* Okay see what our error_count is here.... */
1132        for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
1133             vdisk->next; vdisk = vdisk->next) {
1134                if ((scsidev->channel != vdisk->channel)
1135                    || (scsidev->id != vdisk->id)
1136                    || (scsidev->lun != vdisk->lun))
1137                        continue;
1138
1139                if (atomic_read(&vdisk->error_count) < VIRTHBA_ERROR_COUNT) {
1140                        atomic_inc(&vdisk->error_count);
1141                        LOGERR("SCSICMD ****FAILED scsicmd:0x%p op:0x%x <%d:%d:%d:%llu> 0x%x-0x%x-0x%x-0x%x-0x%x.\n",
1142                               scsicmd, cmdrsp->scsi.cmnd[0],
1143                               scsidev->host->host_no, scsidev->id,
1144                               scsidev->channel, scsidev->lun,
1145                               cmdrsp->scsi.linuxstat, sd->valid, sd->sense_key,
1146                               sd->additional_sense_code,
1147                               sd->additional_sense_code_qualifier);
1148                        if (atomic_read(&vdisk->error_count) ==
1149                            VIRTHBA_ERROR_COUNT) {
1150                                LOGERR("Throtling SCSICMD errors disk <%d:%d:%d:%llu>\n",
1151                                     scsidev->host->host_no, scsidev->id,
1152                                     scsidev->channel, scsidev->lun);
1153                        }
1154                        atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD);
1155                }
1156        }
1157}
1158
1159static void
1160do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
1161{
1162        struct scsi_device *scsidev;
1163        unsigned char buf[36];
1164        struct scatterlist *sg;
1165        unsigned int i;
1166        char *thispage;
1167        char *thispage_orig;
1168        int bufind = 0;
1169        struct virtdisk_info *vdisk;
1170
1171        scsidev = scsicmd->device;
1172        if ((cmdrsp->scsi.cmnd[0] == INQUIRY)
1173            && (cmdrsp->scsi.bufflen >= MIN_INQUIRY_RESULT_LEN)) {
1174                if (cmdrsp->scsi.no_disk_result == 0)
1175                        return;
1176
1177                /* Linux scsi code is weird; it wants
1178                 * a device at Lun 0 to issue report
1179                 * luns, but we don't want a disk
1180                 * there so we'll present a processor
1181                 * there. */
1182                SET_NO_DISK_INQUIRY_RESULT(buf, cmdrsp->scsi.bufflen,
1183                                           scsidev->lun,
1184                                           DEV_DISK_CAPABLE_NOT_PRESENT,
1185                                           DEV_NOT_CAPABLE);
1186
1187                if (scsi_sg_count(scsicmd) == 0) {
1188                        if (scsi_bufflen(scsicmd) > 0) {
1189                                LOGERR("**** FAILED No scatter list for bufflen > 0\n");
1190                                BUG_ON(scsi_sg_count(scsicmd) ==
1191                                       0);
1192                        }
1193                        memcpy(scsi_sglist(scsicmd), buf,
1194                               cmdrsp->scsi.bufflen);
1195                        return;
1196                }
1197
1198                sg = scsi_sglist(scsicmd);
1199                for (i = 0; i < scsi_sg_count(scsicmd); i++) {
1200                        DBGVER("copying OUT OF buf into 0x%p %d\n",
1201                             sg_page(sg + i), sg[i].length);
1202                        thispage_orig = kmap_atomic(sg_page(sg + i));
1203                        thispage = (void *) ((unsigned long)thispage_orig |
1204                                             sg[i].offset);
1205                        memcpy(thispage, buf + bufind, sg[i].length);
1206                        kunmap_atomic(thispage_orig);
1207                        bufind += sg[i].length;
1208                }
1209        } else {
1210
1211                vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
1212                for ( ; vdisk->next; vdisk = vdisk->next) {
1213                        if ((scsidev->channel != vdisk->channel)
1214                            || (scsidev->id != vdisk->id)
1215                            || (scsidev->lun != vdisk->lun))
1216                                continue;
1217
1218                        if (atomic_read(&vdisk->ios_threshold) > 0) {
1219                                atomic_dec(&vdisk->ios_threshold);
1220                                if (atomic_read(&vdisk->ios_threshold) == 0) {
1221                                        LOGERR("Resetting error count for disk\n");
1222                                        atomic_set(&vdisk->error_count, 0);
1223                                }
1224                        }
1225                }
1226        }
1227}
1228
1229static void
1230complete_scsi_command(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
1231{
1232        DBGINF("cmdrsp: 0x%p, scsistat:0x%x.\n", cmdrsp, cmdrsp->scsi.scsistat);
1233
1234        /* take what we need out of cmdrsp and complete the scsicmd */
1235        scsicmd->result = cmdrsp->scsi.linuxstat;
1236        if (cmdrsp->scsi.linuxstat)
1237                do_scsi_linuxstat(cmdrsp, scsicmd);
1238        else
1239                do_scsi_nolinuxstat(cmdrsp, scsicmd);
1240
1241        if (scsicmd->scsi_done) {
1242                DBGVER("Scsi_DONE\n");
1243                scsicmd->scsi_done(scsicmd);
1244        }
1245}
1246
1247static inline void
1248complete_vdiskmgmt_command(struct uiscmdrsp *cmdrsp)
1249{
1250        /* copy the result of the taskmgmt and */
1251        /* wake up the error handler that is waiting for this */
1252        *(int *) cmdrsp->vdiskmgmt.notifyresult = cmdrsp->vdiskmgmt.result;
1253        wake_up_all((wait_queue_head_t *) cmdrsp->vdiskmgmt.notify);
1254        LOGINF("set notify result to %d\n", cmdrsp->vdiskmgmt.result);
1255}
1256
1257static inline void
1258complete_taskmgmt_command(struct uiscmdrsp *cmdrsp)
1259{
1260        /* copy the result of the taskmgmt and */
1261        /* wake up the error handler that is waiting for this */
1262        *(int *) cmdrsp->scsitaskmgmt.notifyresult =
1263            cmdrsp->scsitaskmgmt.result;
1264        wake_up_all((wait_queue_head_t *) cmdrsp->scsitaskmgmt.notify);
1265        LOGINF("set notify result to %d\n", cmdrsp->scsitaskmgmt.result);
1266}
1267
1268static void
1269drain_queue(struct virthba_info *virthbainfo, struct chaninfo *dc,
1270                struct uiscmdrsp *cmdrsp)
1271{
1272        unsigned long flags;
1273        int qrslt = 0;
1274        struct scsi_cmnd *scsicmd;
1275        struct Scsi_Host *shost = virthbainfo->scsihost;
1276
1277        while (1) {
1278                spin_lock_irqsave(&virthbainfo->chinfo.insertlock, flags);
1279                if (!spar_channel_client_acquire_os(dc->queueinfo->chan,
1280                                                     "vhba")) {
1281                        spin_unlock_irqrestore(&virthbainfo->chinfo.insertlock,
1282                                               flags);
1283                        virthbainfo->acquire_failed_cnt++;
1284                        break;
1285                }
1286                qrslt = uisqueue_get_cmdrsp(dc->queueinfo, cmdrsp,
1287                                            IOCHAN_FROM_IOPART);
1288                spar_channel_client_release_os(dc->queueinfo->chan, "vhba");
1289                spin_unlock_irqrestore(&virthbainfo->chinfo.insertlock, flags);
1290                if (qrslt == 0)
1291                        break;
1292                if (cmdrsp->cmdtype == CMD_SCSI_TYPE) {
1293                        /* scsicmd location is returned by the
1294                         * deletion
1295                         */
1296                        scsicmd = del_scsipending_entry(virthbainfo,
1297                                        (uintptr_t) cmdrsp->scsi.scsicmd);
1298                        if (!scsicmd)
1299                                break;
1300                        /* complete the orig cmd */
1301                        complete_scsi_command(cmdrsp, scsicmd);
1302                } else if (cmdrsp->cmdtype == CMD_SCSITASKMGMT_TYPE) {
1303                        if (!del_scsipending_entry(virthbainfo,
1304                                   (uintptr_t) cmdrsp->scsitaskmgmt.scsicmd))
1305                                break;
1306                        complete_taskmgmt_command(cmdrsp);
1307                } else if (cmdrsp->cmdtype == CMD_NOTIFYGUEST_TYPE) {
1308                        /* The vHba pointer has no meaning in
1309                         * a Client/Guest Partition. Let's be
1310                         * safe and set it to NULL now.  Do
1311                         * not use it here! */
1312                        cmdrsp->disknotify.v_hba = NULL;
1313                        process_disk_notify(shost, cmdrsp);
1314                } else if (cmdrsp->cmdtype == CMD_VDISKMGMT_TYPE) {
1315                        if (!del_scsipending_entry(virthbainfo,
1316                                   (uintptr_t) cmdrsp->vdiskmgmt.scsicmd))
1317                                break;
1318                        complete_vdiskmgmt_command(cmdrsp);
1319                } else
1320                        LOGERR("Invalid cmdtype %d\n", cmdrsp->cmdtype);
1321                /* cmdrsp is now available for reuse */
1322        }
1323}
1324
1325/* main function for the thread that waits for scsi commands to arrive
1326 * in a specified queue
1327 */
1328static int
1329process_incoming_rsps(void *v)
1330{
1331        struct virthba_info *virthbainfo = v;
1332        struct chaninfo *dc = &virthbainfo->chinfo;
1333        struct uiscmdrsp *cmdrsp = NULL;
1334        const int SZ = sizeof(struct uiscmdrsp);
1335        u64 mask;
1336        unsigned long long rc1;
1337
1338        UIS_DAEMONIZE("vhba_incoming");
1339        /* alloc once and reuse */
1340        cmdrsp = kmalloc(SZ, GFP_ATOMIC);
1341        if (cmdrsp == NULL) {
1342                LOGERR("process_incoming_rsps ****FAILED to malloc - thread exiting\n");
1343                complete_and_exit(&dc->threadinfo.has_stopped, 0);
1344                return 0;
1345        }
1346        mask = ULTRA_CHANNEL_ENABLE_INTS;
1347        while (1) {
1348                wait_event_interruptible_timeout(virthbainfo->rsp_queue,
1349                         (atomic_read(&virthbainfo->interrupt_rcvd) == 1),
1350                                         usecs_to_jiffies(rsltq_wait_usecs));
1351                atomic_set(&virthbainfo->interrupt_rcvd, 0);
1352                /* drain queue */
1353                drain_queue(virthbainfo, dc, cmdrsp);
1354                rc1 = uisqueue_interlocked_or(virthbainfo->flags_addr, mask);
1355                if (dc->threadinfo.should_stop)
1356                        break;
1357        }
1358
1359        kfree(cmdrsp);
1360
1361        DBGINF("exiting processing incoming rsps.\n");
1362        complete_and_exit(&dc->threadinfo.has_stopped, 0);
1363}
1364
1365/*****************************************************/
1366/* Debugfs filesystem functions                      */
1367/*****************************************************/
1368
1369static ssize_t info_debugfs_read(struct file *file,
1370                        char __user *buf, size_t len, loff_t *offset)
1371{
1372        ssize_t bytes_read = 0;
1373        int str_pos = 0;
1374        u64 phys_flags_addr;
1375        int i;
1376        struct virthba_info *virthbainfo;
1377        char *vbuf;
1378
1379        if (len > MAX_BUF)
1380                len = MAX_BUF;
1381        vbuf = kzalloc(len, GFP_KERNEL);
1382        if (!vbuf)
1383                return -ENOMEM;
1384
1385        for (i = 0; i < VIRTHBASOPENMAX; i++) {
1386                if (VirtHbasOpen[i].virthbainfo == NULL)
1387                        continue;
1388
1389                virthbainfo = VirtHbasOpen[i].virthbainfo;
1390
1391                str_pos += scnprintf(vbuf + str_pos,
1392                                len - str_pos, "MaxBuffLen:%u\n", MaxBuffLen);
1393
1394                str_pos += scnprintf(vbuf + str_pos, len - str_pos,
1395                                "\nvirthba result queue poll wait:%d usecs.\n",
1396                                rsltq_wait_usecs);
1397                str_pos += scnprintf(vbuf + str_pos, len - str_pos,
1398                                "\ninterrupts_rcvd = %llu, interrupts_disabled = %llu\n",
1399                                virthbainfo->interrupts_rcvd,
1400                                virthbainfo->interrupts_disabled);
1401                str_pos += scnprintf(vbuf + str_pos,
1402                                len - str_pos, "\ninterrupts_notme = %llu,\n",
1403                                virthbainfo->interrupts_notme);
1404                phys_flags_addr = virt_to_phys((__force  void *)
1405                                               virthbainfo->flags_addr);
1406                str_pos += scnprintf(vbuf + str_pos, len - str_pos,
1407                                "flags_addr = %p, phys_flags_addr=0x%016llx, FeatureFlags=%llu\n",
1408                                virthbainfo->flags_addr, phys_flags_addr,
1409                                (__le64)readq(virthbainfo->flags_addr));
1410                str_pos += scnprintf(vbuf + str_pos,
1411                        len - str_pos, "acquire_failed_cnt:%llu\n",
1412                        virthbainfo->acquire_failed_cnt);
1413                str_pos += scnprintf(vbuf + str_pos, len - str_pos, "\n");
1414        }
1415
1416        bytes_read = simple_read_from_buffer(buf, len, offset, vbuf, str_pos);
1417        kfree(vbuf);
1418        return bytes_read;
1419}
1420
1421static ssize_t enable_ints_write(struct file *file,
1422                        const char __user *buffer, size_t count, loff_t *ppos)
1423{
1424        char buf[4];
1425        int i, new_value;
1426        struct virthba_info *virthbainfo;
1427
1428        u64 __iomem *Features_addr;
1429        u64 mask;
1430
1431        if (count >= ARRAY_SIZE(buf))
1432                return -EINVAL;
1433
1434        buf[count] = '\0';
1435        if (copy_from_user(buf, buffer, count)) {
1436                LOGERR("copy_from_user failed. buf<<%.*s>> count<<%lu>>\n",
1437                       (int) count, buf, count);
1438                return -EFAULT;
1439        }
1440
1441        i = kstrtoint(buf, 10 , &new_value);
1442
1443        if (i != 0) {
1444                LOGERR("Failed to scan value for enable_ints, buf<<%.*s>>",
1445                       (int) count, buf);
1446                return -EFAULT;
1447        }
1448
1449        /* set all counts to new_value usually 0 */
1450        for (i = 0; i < VIRTHBASOPENMAX; i++) {
1451                if (VirtHbasOpen[i].virthbainfo != NULL) {
1452                        virthbainfo = VirtHbasOpen[i].virthbainfo;
1453                        Features_addr =
1454                                &virthbainfo->chinfo.queueinfo->chan->features;
1455                        if (new_value == 1) {
1456                                mask = ~(ULTRA_IO_CHANNEL_IS_POLLING |
1457                                         ULTRA_IO_DRIVER_DISABLES_INTS);
1458                                uisqueue_interlocked_and(Features_addr, mask);
1459                                mask = ULTRA_IO_DRIVER_ENABLES_INTS;
1460                                uisqueue_interlocked_or(Features_addr, mask);
1461                                rsltq_wait_usecs = 4000000;
1462                        } else {
1463                                mask = ~(ULTRA_IO_DRIVER_ENABLES_INTS |
1464                                         ULTRA_IO_DRIVER_DISABLES_INTS);
1465                                uisqueue_interlocked_and(Features_addr, mask);
1466                                mask = ULTRA_IO_CHANNEL_IS_POLLING;
1467                                uisqueue_interlocked_or(Features_addr, mask);
1468                                rsltq_wait_usecs = 4000;
1469                        }
1470                }
1471        }
1472        return count;
1473}
1474
1475/* As per VirtpciFunc returns 1 for success and 0 for failure */
1476static int
1477virthba_serverup(struct virtpci_dev *virtpcidev)
1478{
1479        struct virthba_info *virthbainfo =
1480            (struct virthba_info *) ((struct Scsi_Host *) virtpcidev->scsi.
1481                                     scsihost)->hostdata;
1482
1483        DBGINF("virtpcidev bus_no<<%d>>devNo<<%d>>", virtpcidev->bus_no,
1484               virtpcidev->device_no);
1485
1486        if (!virthbainfo->serverdown) {
1487                DBGINF("Server up message received while server is already up.\n");
1488                return 1;
1489        }
1490        if (virthbainfo->serverchangingstate) {
1491                LOGERR("Server already processing change state message\n");
1492                return 0;
1493        }
1494
1495        virthbainfo->serverchangingstate = true;
1496        /* Must transition channel to ATTACHED state BEFORE we
1497         * can start using the device again
1498         */
1499        SPAR_CHANNEL_CLIENT_TRANSITION(virthbainfo->chinfo.queueinfo->chan,
1500                                       dev_name(&virtpcidev->generic_dev),
1501                                       CHANNELCLI_ATTACHED, NULL);
1502
1503        /* Start Processing the IOVM Response Queue Again */
1504        if (!uisthread_start(&virthbainfo->chinfo.threadinfo,
1505                             process_incoming_rsps,
1506                             virthbainfo, "vhba_incoming")) {
1507                LOGERR("uisthread_start rsp ****FAILED\n");
1508                return 0;
1509        }
1510        virthbainfo->serverdown = false;
1511        virthbainfo->serverchangingstate = false;
1512
1513        return 1;
1514}
1515
1516static void
1517virthba_serverdown_complete(struct work_struct *work)
1518{
1519        struct virthba_info *virthbainfo;
1520        struct virtpci_dev *virtpcidev;
1521        int i;
1522        struct scsipending *pendingdel = NULL;
1523        struct scsi_cmnd *scsicmd = NULL;
1524        struct uiscmdrsp *cmdrsp;
1525        unsigned long flags;
1526
1527        virthbainfo = container_of(work, struct virthba_info,
1528                                   serverdown_completion);
1529
1530        /* Stop Using the IOVM Response Queue (queue should be drained
1531         * by the end)
1532         */
1533        uisthread_stop(&virthbainfo->chinfo.threadinfo);
1534
1535        /* Fail Commands that weren't completed */
1536        spin_lock_irqsave(&virthbainfo->privlock, flags);
1537        for (i = 0; i < MAX_PENDING_REQUESTS; i++) {
1538                pendingdel = &(virthbainfo->pending[i]);
1539                switch (pendingdel->cmdtype) {
1540                case CMD_SCSI_TYPE:
1541                        scsicmd = (struct scsi_cmnd *) pendingdel->sent;
1542                        scsicmd->result = (DID_RESET << 16);
1543                        if (scsicmd->scsi_done)
1544                                scsicmd->scsi_done(scsicmd);
1545                        break;
1546                case CMD_SCSITASKMGMT_TYPE:
1547                        cmdrsp = (struct uiscmdrsp *) pendingdel->sent;
1548                        DBGINF("cmdrsp=0x%x, notify=0x%x\n", cmdrsp,
1549                               cmdrsp->scsitaskmgmt.notify);
1550                        *(int *) cmdrsp->scsitaskmgmt.notifyresult =
1551                            TASK_MGMT_FAILED;
1552                        wake_up_all((wait_queue_head_t *)
1553                                    cmdrsp->scsitaskmgmt.notify);
1554                        break;
1555                case CMD_VDISKMGMT_TYPE:
1556                        cmdrsp = (struct uiscmdrsp *) pendingdel->sent;
1557                        *(int *) cmdrsp->vdiskmgmt.notifyresult =
1558                            VDISK_MGMT_FAILED;
1559                        wake_up_all((wait_queue_head_t *)
1560                                    cmdrsp->vdiskmgmt.notify);
1561                        break;
1562                default:
1563                        if (pendingdel->sent != NULL)
1564                                LOGERR("Unknown command type: 0x%x.  Only freeing list structure.\n",
1565                                     pendingdel->cmdtype);
1566                }
1567                pendingdel->cmdtype = 0;
1568                pendingdel->sent = NULL;
1569        }
1570        spin_unlock_irqrestore(&virthbainfo->privlock, flags);
1571
1572        virtpcidev = virthbainfo->virtpcidev;
1573
1574        DBGINF("virtpcidev bus_no<<%d>>devNo<<%d>>", virtpcidev->bus_no,
1575               virtpcidev->device_no);
1576        virthbainfo->serverdown = true;
1577        virthbainfo->serverchangingstate = false;
1578        /* Return the ServerDown response to Command */
1579        visorchipset_device_pause_response(virtpcidev->bus_no,
1580                                           virtpcidev->device_no, 0);
1581}
1582
1583/* As per VirtpciFunc returns 1 for success and 0 for failure */
1584static int
1585virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state)
1586{
1587        struct virthba_info *virthbainfo =
1588            (struct virthba_info *) ((struct Scsi_Host *) virtpcidev->scsi.
1589                                     scsihost)->hostdata;
1590
1591        DBGINF("virthba_serverdown");
1592        DBGINF("virtpcidev bus_no<<%d>>devNo<<%d>>", virtpcidev->bus_no,
1593               virtpcidev->device_no);
1594
1595        if (!virthbainfo->serverdown && !virthbainfo->serverchangingstate) {
1596                virthbainfo->serverchangingstate = true;
1597                queue_work(virthba_serverdown_workqueue,
1598                           &virthbainfo->serverdown_completion);
1599        } else if (virthbainfo->serverchangingstate) {
1600                LOGERR("Server already processing change state message\n");
1601                return 0;
1602        } else
1603                LOGERR("Server already down, but another server down message received.");
1604
1605        return 1;
1606}
1607
1608/*****************************************************/
1609/* Module Init & Exit functions                      */
1610/*****************************************************/
1611
1612static int __init
1613virthba_parse_line(char *str)
1614{
1615        DBGINF("In virthba_parse_line %s\n", str);
1616        return 1;
1617}
1618
1619static void __init
1620virthba_parse_options(char *line)
1621{
1622        char *next = line;
1623
1624        POSTCODE_LINUX_2(VHBA_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
1625        if (line == NULL || !*line)
1626                return;
1627        while ((line = next) != NULL) {
1628                next = strchr(line, ' ');
1629                if (next != NULL)
1630                        *next++ = 0;
1631                if (!virthba_parse_line(line))
1632                        DBGINF("Unknown option '%s'\n", line);
1633        }
1634
1635        POSTCODE_LINUX_2(VHBA_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
1636}
1637
1638static int __init
1639virthba_mod_init(void)
1640{
1641        int error;
1642        int i;
1643
1644        if (!unisys_spar_platform)
1645                return -ENODEV;
1646
1647        LOGINF("Entering virthba_mod_init...\n");
1648
1649        POSTCODE_LINUX_2(VHBA_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
1650        virthba_parse_options(virthba_options);
1651
1652        error = virtpci_register_driver(&virthba_driver);
1653        if (error < 0) {
1654                LOGERR("register ****FAILED 0x%x\n", error);
1655                POSTCODE_LINUX_3(VHBA_CREATE_FAILURE_PC, error,
1656                                 POSTCODE_SEVERITY_ERR);
1657        } else {
1658
1659                /* create the debugfs directories and entries */
1660                virthba_debugfs_dir = debugfs_create_dir("virthba", NULL);
1661                debugfs_create_file("info", S_IRUSR, virthba_debugfs_dir,
1662                                NULL, &debugfs_info_fops);
1663                debugfs_create_u32("rqwait_usecs", S_IRUSR | S_IWUSR,
1664                                virthba_debugfs_dir, &rsltq_wait_usecs);
1665                debugfs_create_file("enable_ints", S_IWUSR,
1666                                virthba_debugfs_dir, NULL,
1667                                &debugfs_enable_ints_fops);
1668                /* Initialize DARWorkQ */
1669                INIT_WORK(&DARWorkQ, doDiskAddRemove);
1670                spin_lock_init(&DARWorkQLock);
1671
1672                /* clear out array */
1673                for (i = 0; i < VIRTHBASOPENMAX; i++)
1674                        VirtHbasOpen[i].virthbainfo = NULL;
1675                /* Initialize the serverdown workqueue */
1676                virthba_serverdown_workqueue =
1677                    create_singlethread_workqueue("virthba_serverdown");
1678                if (virthba_serverdown_workqueue == NULL) {
1679                        LOGERR("**** FAILED virthba_serverdown_workqueue creation\n");
1680                        POSTCODE_LINUX_2(VHBA_CREATE_FAILURE_PC,
1681                                         POSTCODE_SEVERITY_ERR);
1682                        error = -1;
1683                }
1684        }
1685
1686        POSTCODE_LINUX_2(VHBA_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
1687        LOGINF("Leaving virthba_mod_init\n");
1688        return error;
1689}
1690
1691static ssize_t
1692virthba_acquire_lun(struct device *cdev, struct device_attribute *attr,
1693                    const char *buf, size_t count)
1694{
1695        struct uisscsi_dest vdest;
1696        struct Scsi_Host *shost = class_to_shost(cdev);
1697        int i;
1698
1699        i = sscanf(buf, "%d-%d-%d", &vdest.channel, &vdest.id, &vdest.lun);
1700        if (i != 3)
1701                return i;
1702
1703        return forward_vdiskmgmt_command(VDISK_MGMT_ACQUIRE, shost, &vdest);
1704}
1705
1706static ssize_t
1707virthba_release_lun(struct device *cdev, struct device_attribute *attr,
1708                    const char *buf, size_t count)
1709{
1710        struct uisscsi_dest vdest;
1711        struct Scsi_Host *shost = class_to_shost(cdev);
1712        int i;
1713
1714        i = sscanf(buf, "%d-%d-%d", &vdest.channel, &vdest.id, &vdest.lun);
1715        if (i != 3)
1716                return i;
1717
1718        return forward_vdiskmgmt_command(VDISK_MGMT_RELEASE, shost, &vdest);
1719}
1720
1721#define CLASS_DEVICE_ATTR(_name, _mode, _show, _store)      \
1722        struct device_attribute class_device_attr_##_name =   \
1723                __ATTR(_name, _mode, _show, _store)
1724
1725static CLASS_DEVICE_ATTR(acquire_lun, S_IWUSR, NULL, virthba_acquire_lun);
1726static CLASS_DEVICE_ATTR(release_lun, S_IWUSR, NULL, virthba_release_lun);
1727
1728static DEVICE_ATTRIBUTE *virthba_shost_attrs[] = {
1729        &class_device_attr_acquire_lun,
1730        &class_device_attr_release_lun,
1731        NULL
1732};
1733
1734static void __exit
1735virthba_mod_exit(void)
1736{
1737        LOGINF("entering virthba_mod_exit...\n");
1738
1739        virtpci_unregister_driver(&virthba_driver);
1740        /* unregister is going to call virthba_remove */
1741        /* destroy serverdown completion workqueue */
1742        if (virthba_serverdown_workqueue) {
1743                destroy_workqueue(virthba_serverdown_workqueue);
1744                virthba_serverdown_workqueue = NULL;
1745        }
1746
1747        debugfs_remove_recursive(virthba_debugfs_dir);
1748        LOGINF("Leaving virthba_mod_exit\n");
1749
1750}
1751
1752/* specify function to be run at module insertion time */
1753module_init(virthba_mod_init);
1754
1755/* specify function to be run when module is removed */
1756module_exit(virthba_mod_exit);
1757
1758MODULE_LICENSE("GPL");
1759MODULE_AUTHOR("Usha Srinivasan");
1760MODULE_ALIAS("uisvirthba");
1761        /* this is extracted during depmod and kept in modules.dep */
1762/* module parameter */
1763module_param(virthba_options, charp, S_IRUGO);
1764
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.