virthba.c revision 79014eb1f25e145ea0dc70c628d1ad24106afba3
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
104
105static int virthba_slave_alloc(struct scsi_device *scsidev);
106static int virthba_slave_configure(struct scsi_device *scsidev);
107static void virthba_slave_destroy(struct scsi_device *scsidev);
108static int process_incoming_rsps(void *);
109static int virthba_serverup(struct virtpci_dev *virtpcidev);
110static int virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state);
111static void doDiskAddRemove(struct work_struct *work);
112static void virthba_serverdown_complete(struct work_struct *work);
113static ssize_t info_debugfs_read(struct file *file, char __user *buf,
114			size_t len, loff_t *offset);
115static ssize_t enable_ints_write(struct file *file,
116			const char __user *buffer, size_t count, loff_t *ppos);
117
118/*****************************************************/
119/* Globals                                           */
120/*****************************************************/
121
122static int rsltq_wait_usecs = 4000;	/* Default 4ms */
123static unsigned int MaxBuffLen;
124
125/* Module options */
126static char *virthba_options = "NONE";
127
128static const struct pci_device_id virthba_id_table[] = {
129	{PCI_DEVICE(PCI_VENDOR_ID_UNISYS, PCI_DEVICE_ID_VIRTHBA)},
130	{0},
131};
132
133/* export virthba_id_table */
134MODULE_DEVICE_TABLE(pci, virthba_id_table);
135
136static struct workqueue_struct *virthba_serverdown_workqueue;
137
138static struct virtpci_driver virthba_driver = {
139	.name = "uisvirthba",
140	.version = VERSION,
141	.vertag = NULL,
142	.id_table = virthba_id_table,
143	.probe = virthba_probe,
144	.remove = virthba_remove,
145	.resume = virthba_serverup,
146	.suspend = virthba_serverdown
147};
148
149/* The Send and Recive Buffers of the IO Queue may both be full */
150#define MAX_PENDING_REQUESTS (MIN_NUMSIGNALS*2)
151#define INTERRUPT_VECTOR_MASK 0x3F
152
153struct scsipending {
154	char cmdtype;		/* Type of pointer that is being stored */
155	void *sent;		/* The Data being tracked */
156	/* struct scsi_cmnd *type for virthba_queue_command */
157	/* struct uiscmdrsp *type for management commands */
158};
159
160#define VIRTHBA_ERROR_COUNT 30
161#define IOS_ERROR_THRESHOLD 1000
162struct virtdisk_info {
163	U32 valid;
164	U32 channel, id, lun;	/* Disk Path */
165	atomic_t ios_threshold;
166	atomic_t error_count;
167	struct virtdisk_info *next;
168};
169/* Each Scsi_Host has a host_data area that contains this struct. */
170struct virthba_info {
171	struct Scsi_Host *scsihost;
172	struct virtpci_dev *virtpcidev;
173	struct list_head dev_info_list;
174	struct chaninfo chinfo;
175	struct InterruptInfo intr;	/* use recvInterrupt info to receive
176					   interrupts when IOs complete */
177	int interrupt_vector;
178	struct scsipending pending[MAX_PENDING_REQUESTS]; /* Tracks the requests
179							     that have been */
180	/* forwarded to the IOVM and haven't returned yet */
181	unsigned int nextinsert;	/* Start search for next pending
182					   free slot here */
183	spinlock_t privlock;
184	bool serverdown;
185	bool serverchangingstate;
186	unsigned long long acquire_failed_cnt;
187	unsigned long long interrupts_rcvd;
188	unsigned long long interrupts_notme;
189	unsigned long long interrupts_disabled;
190	struct work_struct serverdown_completion;
191	U64 __iomem *flags_addr;
192	atomic_t interrupt_rcvd;
193	wait_queue_head_t rsp_queue;
194	struct virtdisk_info head;
195};
196
197/* Work Data for DARWorkQ */
198struct diskaddremove {
199	U8 add;			/* 0-remove, 1-add */
200	struct Scsi_Host *shost; /* Scsi Host for this virthba instance */
201	U32 channel, id, lun;	/* Disk Path */
202	struct diskaddremove *next;
203};
204
205#define virtpci_dev_to_virthba_virthba_get_info(d) \
206	container_of(d, struct virthba_info, virtpcidev)
207
208static DEVICE_ATTRIBUTE *virthba_shost_attrs[];
209static struct scsi_host_template virthba_driver_template = {
210	.name = "Unisys Virtual HBA",
211	.info = virthba_get_info,
212	.ioctl = virthba_ioctl,
213	.queuecommand = virthba_queue_command,
214	.eh_abort_handler = virthba_abort_handler,
215	.eh_device_reset_handler = virthba_device_reset_handler,
216	.eh_bus_reset_handler = virthba_bus_reset_handler,
217	.eh_host_reset_handler = virthba_host_reset_handler,
218	.shost_attrs = virthba_shost_attrs,
219
220#define VIRTHBA_MAX_CMNDS 128
221	.can_queue = VIRTHBA_MAX_CMNDS,
222	.sg_tablesize = 64,	/* largest number of address/length pairs */
223	.this_id = -1,
224	.slave_alloc = virthba_slave_alloc,
225	.slave_configure = virthba_slave_configure,
226	.slave_destroy = virthba_slave_destroy,
227	.use_clustering = ENABLE_CLUSTERING,
228};
229
230struct virthba_devices_open {
231	struct virthba_info *virthbainfo;
232};
233
234static const struct file_operations debugfs_info_fops = {
235	.read = info_debugfs_read,
236};
237
238static const struct file_operations debugfs_enable_ints_fops = {
239	.write = enable_ints_write,
240};
241
242/*****************************************************/
243/* Structs                                           */
244/*****************************************************/
245
246#define VIRTHBASOPENMAX 1
247/* array of open devices maintained by open() and close(); */
248static struct virthba_devices_open VirtHbasOpen[VIRTHBASOPENMAX];
249static struct dentry *virthba_debugfs_dir;
250
251/*****************************************************/
252/* Local Functions				     */
253/*****************************************************/
254static int
255add_scsipending_entry(struct virthba_info *vhbainfo, char cmdtype, void *new)
256{
257	unsigned long flags;
258	int insert_location;
259
260	spin_lock_irqsave(&vhbainfo->privlock, flags);
261	insert_location = vhbainfo->nextinsert;
262	while (vhbainfo->pending[insert_location].sent != NULL) {
263		insert_location = (insert_location + 1) % MAX_PENDING_REQUESTS;
264		if (insert_location == (int) vhbainfo->nextinsert) {
265			LOGERR("Queue should be full. insert_location<<%d>>  Unable to find open slot for pending commands.\n",
266			     insert_location);
267			spin_unlock_irqrestore(&vhbainfo->privlock, flags);
268			return -1;
269		}
270	}
271
272	vhbainfo->pending[insert_location].cmdtype = cmdtype;
273	vhbainfo->pending[insert_location].sent = new;
274	vhbainfo->nextinsert = (insert_location + 1) % MAX_PENDING_REQUESTS;
275	spin_unlock_irqrestore(&vhbainfo->privlock, flags);
276
277	return insert_location;
278}
279
280static unsigned int
281add_scsipending_entry_with_wait(struct virthba_info *vhbainfo, char cmdtype,
282				void *new)
283{
284	int insert_location = add_scsipending_entry(vhbainfo, cmdtype, new);
285
286	while (insert_location == -1) {
287		LOGERR("Failed to find empty queue slot.  Waiting to try again\n");
288		set_current_state(TASK_INTERRUPTIBLE);
289		schedule_timeout(msecs_to_jiffies(10));
290		insert_location = add_scsipending_entry(vhbainfo, cmdtype, new);
291	}
292
293	return (unsigned int) insert_location;
294}
295
296static void *
297del_scsipending_entry(struct virthba_info *vhbainfo, uintptr_t del)
298{
299	unsigned long flags;
300	void *sent = NULL;
301
302	if (del >= MAX_PENDING_REQUESTS) {
303		LOGERR("Invalid queue position <<%lu>> given to delete. MAX_PENDING_REQUESTS <<%d>>\n",
304		     (unsigned long) del, MAX_PENDING_REQUESTS);
305	} else {
306		spin_lock_irqsave(&vhbainfo->privlock, flags);
307
308		if (vhbainfo->pending[del].sent == NULL)
309			LOGERR("Deleting already cleared queue entry at <<%lu>>.\n",
310			     (unsigned long) del);
311
312		sent = vhbainfo->pending[del].sent;
313
314		vhbainfo->pending[del].cmdtype = 0;
315		vhbainfo->pending[del].sent = NULL;
316		spin_unlock_irqrestore(&vhbainfo->privlock, flags);
317	}
318
319	return sent;
320}
321
322/* DARWorkQ (Disk Add/Remove) */
323static struct work_struct DARWorkQ;
324static struct diskaddremove *DARWorkQHead;
325static spinlock_t DARWorkQLock;
326static unsigned short DARWorkQSched;
327#define QUEUE_DISKADDREMOVE(dar) { \
328	spin_lock_irqsave(&DARWorkQLock, flags); \
329	if (!DARWorkQHead) { \
330		DARWorkQHead = dar; \
331		dar->next = NULL; \
332	} \
333	else { \
334		dar->next = DARWorkQHead; \
335		DARWorkQHead = dar; \
336	} \
337	if (!DARWorkQSched) { \
338		schedule_work(&DARWorkQ); \
339		DARWorkQSched = 1; \
340	} \
341	spin_unlock_irqrestore(&DARWorkQLock, flags); \
342}
343
344static inline void
345SendDiskAddRemove(struct diskaddremove *dar)
346{
347	struct scsi_device *sdev;
348	int error;
349
350	sdev = scsi_device_lookup(dar->shost, dar->channel, dar->id, dar->lun);
351	if (sdev) {
352		if (!(dar->add))
353			scsi_remove_device(sdev);
354	} else if (dar->add) {
355		error =
356		    scsi_add_device(dar->shost, dar->channel, dar->id,
357				    dar->lun);
358		if (error)
359			LOGERR("Failed scsi_add_device: host_no=%d[chan=%d:id=%d:lun=%d]\n",
360			     dar->shost->host_no, dar->channel, dar->id,
361			     dar->lun);
362	} else
363		LOGERR("Failed scsi_device_lookup:[chan=%d:id=%d:lun=%d]\n",
364		       dar->channel, dar->id, dar->lun);
365	kfree(dar);
366}
367
368/*****************************************************/
369/* DARWorkQ Handler Thread                           */
370/*****************************************************/
371static void
372doDiskAddRemove(struct work_struct *work)
373{
374	struct diskaddremove *dar;
375	struct diskaddremove *tmphead;
376	int i = 0;
377	unsigned long flags;
378
379	spin_lock_irqsave(&DARWorkQLock, flags);
380	tmphead = DARWorkQHead;
381	DARWorkQHead = NULL;
382	DARWorkQSched = 0;
383	spin_unlock_irqrestore(&DARWorkQLock, flags);
384	while (tmphead) {
385		dar = tmphead;
386		tmphead = dar->next;
387		SendDiskAddRemove(dar);
388		i++;
389	}
390}
391
392/*****************************************************/
393/* Routine to add entry to DARWorkQ                  */
394/*****************************************************/
395static void
396process_disk_notify(struct Scsi_Host *shost, struct uiscmdrsp *cmdrsp)
397{
398	struct diskaddremove *dar;
399	unsigned long flags;
400
401	dar = kzalloc(sizeof(struct diskaddremove), GFP_ATOMIC);
402	if (dar) {
403		dar->add = cmdrsp->disknotify.add;
404		dar->shost = shost;
405		dar->channel = cmdrsp->disknotify.channel;
406		dar->id = cmdrsp->disknotify.id;
407		dar->lun = cmdrsp->disknotify.lun;
408		QUEUE_DISKADDREMOVE(dar);
409	} else {
410		LOGERR("kmalloc failed for dar. host_no=%d[chan=%d:id=%d:lun=%d]\n",
411		     shost->host_no, cmdrsp->disknotify.channel,
412		     cmdrsp->disknotify.id, cmdrsp->disknotify.lun);
413	}
414}
415
416/*****************************************************/
417/* Probe Remove Functions                            */
418/*****************************************************/
419static irqreturn_t
420virthba_ISR(int irq, void *dev_id)
421{
422	struct virthba_info *virthbainfo = (struct virthba_info *) dev_id;
423	CHANNEL_HEADER __iomem *pChannelHeader;
424	SIGNAL_QUEUE_HEADER __iomem *pqhdr;
425	U64 mask;
426	unsigned long long rc1;
427
428	if (virthbainfo == NULL)
429		return IRQ_NONE;
430	virthbainfo->interrupts_rcvd++;
431	pChannelHeader = virthbainfo->chinfo.queueinfo->chan;
432	if (((readq(&pChannelHeader->Features)
433	      & ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS) != 0)
434	    && ((readq(&pChannelHeader->Features) &
435		 ULTRA_IO_DRIVER_DISABLES_INTS) !=
436		0)) {
437		virthbainfo->interrupts_disabled++;
438		mask = ~ULTRA_CHANNEL_ENABLE_INTS;
439		rc1 = uisqueue_InterlockedAnd(virthbainfo->flags_addr, mask);
440	}
441	if (visor_signalqueue_empty(pChannelHeader, IOCHAN_FROM_IOPART)) {
442		virthbainfo->interrupts_notme++;
443		return IRQ_NONE;
444	}
445	pqhdr = (SIGNAL_QUEUE_HEADER __iomem *)
446		((char __iomem *) pChannelHeader +
447		 readq(&pChannelHeader->oChannelSpace)) + IOCHAN_FROM_IOPART;
448	writeq(readq(&pqhdr->NumInterruptsReceived) + 1,
449	       &pqhdr->NumInterruptsReceived);
450	atomic_set(&virthbainfo->interrupt_rcvd, 1);
451	wake_up_interruptible(&virthbainfo->rsp_queue);
452	return IRQ_HANDLED;
453}
454
455static int
456virthba_probe(struct virtpci_dev *virtpcidev, const struct pci_device_id *id)
457{
458	int error;
459	struct Scsi_Host *scsihost;
460	struct virthba_info *virthbainfo;
461	int rsp;
462	int i;
463	irq_handler_t handler = virthba_ISR;
464	CHANNEL_HEADER __iomem *pChannelHeader;
465	SIGNAL_QUEUE_HEADER __iomem *pqhdr;
466	U64 mask;
467
468	LOGVER("entering virthba_probe...\n");
469	LOGVER("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo,
470	       virtpcidev->deviceNo);
471
472	LOGINF("entering virthba_probe...\n");
473	LOGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo,
474	       virtpcidev->deviceNo);
475	POSTCODE_LINUX_2(VHBA_PROBE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
476	/* call scsi_host_alloc to register a scsi host adapter
477	 * instance - this virthba that has just been created is an
478	 * instance of a scsi host adapter. This scsi_host_alloc
479	 * function allocates a new Scsi_Host struct & performs basic
480	 * initializatoin.  The host is not published to the scsi
481	 * midlayer until scsi_add_host is called.
482	 */
483	DBGINF("calling scsi_host_alloc.\n");
484
485	/* arg 2 passed in length of extra space we want allocated
486	 * with scsi_host struct for our own use scsi_host_alloc
487	 * assign host_no
488	 */
489	scsihost = scsi_host_alloc(&virthba_driver_template,
490				   sizeof(struct virthba_info));
491	if (scsihost == NULL)
492		return -ENODEV;
493
494	DBGINF("scsihost: 0x%p, scsihost->this_id: %d, host_no: %d.\n",
495	       scsihost, scsihost->this_id, scsihost->host_no);
496
497	scsihost->this_id = UIS_MAGIC_VHBA;
498	/* linux treats max-channel differently than max-id & max-lun.
499	 * In the latter cases, those two values result in 0 to max-1
500	 * (inclusive) being scanned. But in the case of channels, the
501	 * scan is 0 to max (inclusive); so we will subtract one from
502	 * the max-channel value.
503	 */
504	LOGINF("virtpcidev->scsi.max.max_channel=%u, max_id=%u, max_lun=%u, cmd_per_lun=%u, max_io_size=%u\n",
505	     (unsigned) virtpcidev->scsi.max.max_channel - 1,
506	     (unsigned) virtpcidev->scsi.max.max_id,
507	     (unsigned) virtpcidev->scsi.max.max_lun,
508	     (unsigned) virtpcidev->scsi.max.cmd_per_lun,
509	     (unsigned) virtpcidev->scsi.max.max_io_size);
510	scsihost->max_channel = (unsigned) virtpcidev->scsi.max.max_channel;
511	scsihost->max_id = (unsigned) virtpcidev->scsi.max.max_id;
512	scsihost->max_lun = (unsigned) virtpcidev->scsi.max.max_lun;
513	scsihost->cmd_per_lun = (unsigned) virtpcidev->scsi.max.cmd_per_lun;
514	scsihost->max_sectors =
515	    (unsigned short) (virtpcidev->scsi.max.max_io_size >> 9);
516	scsihost->sg_tablesize =
517	    (unsigned short) (virtpcidev->scsi.max.max_io_size / PAGE_SIZE);
518	if (scsihost->sg_tablesize > MAX_PHYS_INFO)
519		scsihost->sg_tablesize = MAX_PHYS_INFO;
520	LOGINF("scsihost->max_channel=%u, max_id=%u, max_lun=%u, cmd_per_lun=%u, max_sectors=%hu, sg_tablesize=%hu\n",
521	     scsihost->max_channel, scsihost->max_id, scsihost->max_lun,
522	     scsihost->cmd_per_lun, scsihost->max_sectors,
523	     scsihost->sg_tablesize);
524	LOGINF("scsihost->can_queue=%u, scsihost->cmd_per_lun=%u, max_sectors=%hu, sg_tablesize=%hu\n",
525	     scsihost->can_queue, scsihost->cmd_per_lun, scsihost->max_sectors,
526	     scsihost->sg_tablesize);
527
528	DBGINF("calling scsi_add_host\n");
529
530	/* this creates "host%d" in sysfs.  If 2nd argument is NULL,
531	 * then this generic /sys/devices/platform/host?  device is
532	 * created and /sys/scsi_host/host? ->
533	 * /sys/devices/platform/host?  If 2nd argument is not NULL,
534	 * then this generic /sys/devices/<path>/host? is created and
535	 * host? points to that device instead.
536	 */
537	error = scsi_add_host(scsihost, &virtpcidev->generic_dev);
538	if (error) {
539		LOGERR("scsi_add_host ****FAILED 0x%x  TBD - RECOVER\n", error);
540		POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
541		/* decr refcount on scsihost which was incremented by
542		 * scsi_add_host so the scsi_host gets deleted
543		 */
544		scsi_host_put(scsihost);
545		return -ENODEV;
546	}
547
548	virthbainfo = (struct virthba_info *) scsihost->hostdata;
549	memset(virthbainfo, 0, sizeof(struct virthba_info));
550	for (i = 0; i < VIRTHBASOPENMAX; i++) {
551		if (VirtHbasOpen[i].virthbainfo == NULL) {
552			VirtHbasOpen[i].virthbainfo = virthbainfo;
553			break;
554		}
555	}
556	virthbainfo->interrupt_vector = -1;
557	virthbainfo->chinfo.queueinfo = &virtpcidev->queueinfo;
558	virthbainfo->virtpcidev = virtpcidev;
559	spin_lock_init(&virthbainfo->chinfo.insertlock);
560
561	DBGINF("generic_dev: 0x%p, queueinfo: 0x%p.\n",
562	       &virtpcidev->generic_dev, &virtpcidev->queueinfo);
563
564	init_waitqueue_head(&virthbainfo->rsp_queue);
565	spin_lock_init(&virthbainfo->privlock);
566	memset(&virthbainfo->pending, 0, sizeof(virthbainfo->pending));
567	virthbainfo->serverdown = false;
568	virthbainfo->serverchangingstate = false;
569
570	virthbainfo->intr = virtpcidev->intr;
571	/* save of host within virthba_info */
572	virthbainfo->scsihost = scsihost;
573
574	/* save of host within virtpci_dev */
575	virtpcidev->scsi.scsihost = scsihost;
576
577	/* Setup workqueue for serverdown messages */
578	INIT_WORK(&virthbainfo->serverdown_completion,
579		  virthba_serverdown_complete);
580
581	writeq(readq(&virthbainfo->chinfo.queueinfo->chan->Features) |
582	       ULTRA_IO_CHANNEL_IS_POLLING,
583	       &virthbainfo->chinfo.queueinfo->chan->Features);
584	/* start thread that will receive scsicmnd responses */
585	DBGINF("starting rsp thread -- queueinfo: 0x%p, threadinfo: 0x%p.\n",
586	       virthbainfo->chinfo.queueinfo, &virthbainfo->chinfo.threadinfo);
587
588	pChannelHeader = virthbainfo->chinfo.queueinfo->chan;
589	pqhdr = (SIGNAL_QUEUE_HEADER __iomem *)
590		((char __iomem *)pChannelHeader +
591		 readq(&pChannelHeader->oChannelSpace)) + IOCHAN_FROM_IOPART;
592	virthbainfo->flags_addr = &pqhdr->FeatureFlags;
593
594	if (!uisthread_start(&virthbainfo->chinfo.threadinfo,
595			     process_incoming_rsps,
596			     virthbainfo, "vhba_incoming")) {
597		LOGERR("uisthread_start rsp ****FAILED\n");
598		/* decr refcount on scsihost which was incremented by
599		 * scsi_add_host so the scsi_host gets deleted
600		 */
601		POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
602		scsi_host_put(scsihost);
603		return -ENODEV;
604	}
605	LOGINF("sendInterruptHandle=0x%16llX",
606	       virthbainfo->intr.sendInterruptHandle);
607	LOGINF("recvInterruptHandle=0x%16llX",
608	       virthbainfo->intr.recvInterruptHandle);
609	LOGINF("recvInterruptVector=0x%8X",
610	       virthbainfo->intr.recvInterruptVector);
611	LOGINF("recvInterruptShared=0x%2X",
612	       virthbainfo->intr.recvInterruptShared);
613	LOGINF("scsihost.hostt->name=%s", scsihost->hostt->name);
614	virthbainfo->interrupt_vector =
615	    virthbainfo->intr.recvInterruptHandle & INTERRUPT_VECTOR_MASK;
616	rsp = request_irq(virthbainfo->interrupt_vector, handler, IRQF_SHARED,
617			  scsihost->hostt->name, virthbainfo);
618	if (rsp != 0) {
619		LOGERR("request_irq(%d) uislib_virthba_ISR request failed with rsp=%d\n",
620		       virthbainfo->interrupt_vector, rsp);
621		virthbainfo->interrupt_vector = -1;
622		POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
623	} else {
624		U64 __iomem *Features_addr =
625		    &virthbainfo->chinfo.queueinfo->chan->Features;
626		LOGERR("request_irq(%d) uislib_virthba_ISR request succeeded\n",
627		       virthbainfo->interrupt_vector);
628		mask = ~(ULTRA_IO_CHANNEL_IS_POLLING |
629			 ULTRA_IO_DRIVER_DISABLES_INTS);
630		uisqueue_InterlockedAnd(Features_addr, mask);
631		mask = ULTRA_IO_DRIVER_ENABLES_INTS;
632		uisqueue_InterlockedOr(Features_addr, mask);
633		rsltq_wait_usecs = 4000000;
634	}
635
636	DBGINF("calling scsi_scan_host.\n");
637	scsi_scan_host(scsihost);
638	DBGINF("return from scsi_scan_host.\n");
639
640	LOGINF("virthba added scsihost:0x%p\n", scsihost);
641	POSTCODE_LINUX_2(VHBA_PROBE_EXIT_PC, POSTCODE_SEVERITY_INFO);
642	return 0;
643}
644
645static void
646virthba_remove(struct virtpci_dev *virtpcidev)
647{
648	struct virthba_info *virthbainfo;
649	struct Scsi_Host *scsihost =
650	    (struct Scsi_Host *) virtpcidev->scsi.scsihost;
651
652	LOGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo,
653	       virtpcidev->deviceNo);
654	virthbainfo = (struct virthba_info *) scsihost->hostdata;
655	if (virthbainfo->interrupt_vector != -1)
656		free_irq(virthbainfo->interrupt_vector, virthbainfo);
657	LOGINF("Removing virtpcidev: 0x%p, virthbainfo: 0x%p\n", virtpcidev,
658	       virthbainfo);
659
660	DBGINF("removing scsihost: 0x%p, scsihost->this_id: %d\n", scsihost,
661	       scsihost->this_id);
662	scsi_remove_host(scsihost);
663
664	DBGINF("stopping thread.\n");
665	uisthread_stop(&virthbainfo->chinfo.threadinfo);
666
667	DBGINF("calling scsi_host_put\n");
668
669	/* decr refcount on scsihost which was incremented by
670	 * scsi_add_host so the scsi_host gets deleted
671	 */
672	scsi_host_put(scsihost);
673	LOGINF("virthba removed scsi_host.\n");
674}
675
676static int
677forward_vdiskmgmt_command(VDISK_MGMT_TYPES vdiskcmdtype,
678			  struct Scsi_Host *scsihost,
679			  struct uisscsi_dest *vdest)
680{
681	struct uiscmdrsp *cmdrsp;
682	struct virthba_info *virthbainfo =
683	    (struct virthba_info *) scsihost->hostdata;
684	int notifyresult = 0xffff;
685	wait_queue_head_t notifyevent;
686
687	LOGINF("vDiskMgmt:%d %d:%d:%d\n", vdiskcmdtype,
688	       vdest->channel, vdest->id, vdest->lun);
689
690	if (virthbainfo->serverdown || virthbainfo->serverchangingstate) {
691		DBGINF("Server is down/changing state. Returning Failure.\n");
692		return FAILED;
693	}
694
695	cmdrsp = kzalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
696	if (cmdrsp == NULL) {
697		LOGERR("kmalloc of cmdrsp failed.\n");
698		return FAILED;	/* reject */
699	}
700
701	init_waitqueue_head(&notifyevent);
702
703	/* issue VDISK_MGMT_CMD
704	 * set type to command - as opposed to task mgmt
705	 */
706	cmdrsp->cmdtype = CMD_VDISKMGMT_TYPE;
707	/* specify the event that has to be triggered when this cmd is
708	 * complete
709	 */
710	cmdrsp->vdiskmgmt.notify = (void *) &notifyevent;
711	cmdrsp->vdiskmgmt.notifyresult = (void *) &notifyresult;
712
713	/* save destination */
714	cmdrsp->vdiskmgmt.vdisktype = vdiskcmdtype;
715	cmdrsp->vdiskmgmt.vdest.channel = vdest->channel;
716	cmdrsp->vdiskmgmt.vdest.id = vdest->id;
717	cmdrsp->vdiskmgmt.vdest.lun = vdest->lun;
718	cmdrsp->vdiskmgmt.scsicmd =
719	    (void *) (uintptr_t)
720		add_scsipending_entry_with_wait(virthbainfo, CMD_VDISKMGMT_TYPE,
721						(void *) cmdrsp);
722
723	uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
724					     cmdrsp, IOCHAN_TO_IOPART,
725					     &virthbainfo->chinfo.insertlock,
726					     DONT_ISSUE_INTERRUPT, (U64) NULL,
727					     OK_TO_WAIT, "vhba");
728	LOGINF("VdiskMgmt waiting on event notifyevent=0x%p\n",
729	       cmdrsp->scsitaskmgmt.notify);
730	wait_event(notifyevent, notifyresult != 0xffff);
731	LOGINF("VdiskMgmt complete; result:%d\n", cmdrsp->vdiskmgmt.result);
732	kfree(cmdrsp);
733	return SUCCESS;
734}
735
736/*****************************************************/
737/* Scsi Host support functions                       */
738/*****************************************************/
739
740static int
741forward_taskmgmt_command(TASK_MGMT_TYPES tasktype, 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:%d\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	return;
1109}
1110
1111/*****************************************************/
1112/* Scsi Cmnd support thread                          */
1113/*****************************************************/
1114
1115static void
1116do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
1117{
1118	struct virtdisk_info *vdisk;
1119	struct scsi_device *scsidev;
1120	struct sense_data *sd;
1121
1122	scsidev = scsicmd->device;
1123	memcpy(scsicmd->sense_buffer, cmdrsp->scsi.sensebuf, MAX_SENSE_SIZE);
1124	sd = (struct sense_data *) scsicmd->sense_buffer;
1125
1126	/* Do not log errors for disk-not-present inquiries */
1127	if ((cmdrsp->scsi.cmnd[0] == INQUIRY) &&
1128	    (host_byte(cmdrsp->scsi.linuxstat) == DID_NO_CONNECT) &&
1129	    (cmdrsp->scsi.addlstat == ADDL_SEL_TIMEOUT))
1130		return;
1131
1132	/* Okay see what our error_count is here.... */
1133	for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
1134	     vdisk->next; vdisk = vdisk->next) {
1135		if ((scsidev->channel != vdisk->channel)
1136		    || (scsidev->id != vdisk->id)
1137		    || (scsidev->lun != vdisk->lun))
1138			continue;
1139
1140		if (atomic_read(&vdisk->error_count) < VIRTHBA_ERROR_COUNT) {
1141			atomic_inc(&vdisk->error_count);
1142			LOGERR("SCSICMD ****FAILED scsicmd:0x%p op:0x%x <%d:%d:%d:%d> 0x%x-0x%x-0x%x-0x%x-0x%x.\n",
1143			       scsicmd, cmdrsp->scsi.cmnd[0],
1144			       scsidev->host->host_no, scsidev->id,
1145			       scsidev->channel, scsidev->lun,
1146			       cmdrsp->scsi.linuxstat, sd->Valid, sd->SenseKey,
1147			       sd->AdditionalSenseCode,
1148			       sd->AdditionalSenseCodeQualifier);
1149			if (atomic_read(&vdisk->error_count) ==
1150			    VIRTHBA_ERROR_COUNT) {
1151				LOGERR("Throtling SCSICMD errors disk <%d:%d:%d:%d>\n",
1152				     scsidev->host->host_no, scsidev->id,
1153				     scsidev->channel, scsidev->lun);
1154			}
1155			atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD);
1156		}
1157	}
1158}
1159
1160static void
1161do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
1162{
1163	struct scsi_device *scsidev;
1164	unsigned char buf[36];
1165	struct scatterlist *sg;
1166	unsigned int i;
1167	char *thispage;
1168	char *thispage_orig;
1169	int bufind = 0;
1170	struct virtdisk_info *vdisk;
1171
1172	scsidev = scsicmd->device;
1173	if ((cmdrsp->scsi.cmnd[0] == INQUIRY)
1174	    && (cmdrsp->scsi.bufflen >= MIN_INQUIRY_RESULT_LEN)) {
1175		if (cmdrsp->scsi.no_disk_result == 0)
1176			return;
1177
1178		/* Linux scsi code is weird; it wants
1179		 * a device at Lun 0 to issue report
1180		 * luns, but we don't want a disk
1181		 * there so we'll present a processor
1182		 * there. */
1183		SET_NO_DISK_INQUIRY_RESULT(buf, cmdrsp->scsi.bufflen,
1184					   scsidev->lun,
1185					   DEV_DISK_CAPABLE_NOT_PRESENT,
1186					   DEV_NOT_CAPABLE);
1187
1188		if (scsi_sg_count(scsicmd) == 0) {
1189			if (scsi_bufflen(scsicmd) > 0) {
1190				LOGERR("**** FAILED No scatter list for bufflen > 0\n");
1191				BUG_ON(scsi_sg_count(scsicmd) ==
1192				       0);
1193			}
1194			memcpy(scsi_sglist(scsicmd), buf,
1195			       cmdrsp->scsi.bufflen);
1196			return;
1197		}
1198
1199		sg = scsi_sglist(scsicmd);
1200		for (i = 0; i < scsi_sg_count(scsicmd); i++) {
1201			DBGVER("copying OUT OF buf into 0x%p %d\n",
1202			     sg_page(sg + i), sg[i].length);
1203			thispage_orig = kmap_atomic(sg_page(sg + i));
1204			thispage = (void *) ((unsigned long)thispage_orig |
1205					     sg[i].offset);
1206			memcpy(thispage, buf + bufind, sg[i].length);
1207			kunmap_atomic(thispage_orig);
1208			bufind += sg[i].length;
1209		}
1210	} else {
1211
1212		vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
1213		for ( ; vdisk->next; vdisk = vdisk->next) {
1214			if ((scsidev->channel != vdisk->channel)
1215			    || (scsidev->id != vdisk->id)
1216			    || (scsidev->lun != vdisk->lun))
1217				continue;
1218
1219			if (atomic_read(&vdisk->ios_threshold) > 0) {
1220				atomic_dec(&vdisk->ios_threshold);
1221				if (atomic_read(&vdisk->ios_threshold) == 0) {
1222					LOGERR("Resetting error count for disk\n");
1223					atomic_set(&vdisk->error_count, 0);
1224				}
1225			}
1226		}
1227	}
1228}
1229
1230static void
1231complete_scsi_command(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
1232{
1233	DBGINF("cmdrsp: 0x%p, scsistat:0x%x.\n", cmdrsp, cmdrsp->scsi.scsistat);
1234
1235	/* take what we need out of cmdrsp and complete the scsicmd */
1236	scsicmd->result = cmdrsp->scsi.linuxstat;
1237	if (cmdrsp->scsi.linuxstat)
1238		do_scsi_linuxstat(cmdrsp, scsicmd);
1239	else
1240		do_scsi_nolinuxstat(cmdrsp, scsicmd);
1241
1242	if (scsicmd->scsi_done) {
1243		DBGVER("Scsi_DONE\n");
1244		scsicmd->scsi_done(scsicmd);
1245	}
1246}
1247
1248static inline void
1249complete_vdiskmgmt_command(struct uiscmdrsp *cmdrsp)
1250{
1251	/* copy the result of the taskmgmt and */
1252	/* wake up the error handler that is waiting for this */
1253	*(int *) cmdrsp->vdiskmgmt.notifyresult = cmdrsp->vdiskmgmt.result;
1254	wake_up_all((wait_queue_head_t *) cmdrsp->vdiskmgmt.notify);
1255	LOGINF("set notify result to %d\n", cmdrsp->vdiskmgmt.result);
1256}
1257
1258static inline void
1259complete_taskmgmt_command(struct uiscmdrsp *cmdrsp)
1260{
1261	/* copy the result of the taskmgmt and */
1262	/* wake up the error handler that is waiting for this */
1263	*(int *) cmdrsp->scsitaskmgmt.notifyresult =
1264	    cmdrsp->scsitaskmgmt.result;
1265	wake_up_all((wait_queue_head_t *) cmdrsp->scsitaskmgmt.notify);
1266	LOGINF("set notify result to %d\n", cmdrsp->scsitaskmgmt.result);
1267}
1268
1269static void
1270drain_queue(struct virthba_info *virthbainfo, struct chaninfo *dc,
1271		struct uiscmdrsp *cmdrsp)
1272{
1273	unsigned long flags;
1274	int qrslt = 0;
1275	struct scsi_cmnd *scsicmd;
1276	struct Scsi_Host *shost = virthbainfo->scsihost;
1277
1278	while (1) {
1279		spin_lock_irqsave(&virthbainfo->chinfo.insertlock, flags);
1280		if (!ULTRA_CHANNEL_CLIENT_ACQUIRE_OS(dc->queueinfo->chan,
1281						     "vhba", NULL)) {
1282			spin_unlock_irqrestore(&virthbainfo->chinfo.insertlock,
1283					       flags);
1284			virthbainfo->acquire_failed_cnt++;
1285			break;
1286		}
1287		qrslt = uisqueue_get_cmdrsp(dc->queueinfo, cmdrsp,
1288					    IOCHAN_FROM_IOPART);
1289		ULTRA_CHANNEL_CLIENT_RELEASE_OS(dc->queueinfo->chan,
1290						"vhba", NULL);
1291		spin_unlock_irqrestore(&virthbainfo->chinfo.insertlock, flags);
1292		if (qrslt == 0)
1293			break;
1294		if (cmdrsp->cmdtype == CMD_SCSI_TYPE) {
1295			/* scsicmd location is returned by the
1296			 * deletion
1297			 */
1298			scsicmd = del_scsipending_entry(virthbainfo,
1299					(uintptr_t) cmdrsp->scsi.scsicmd);
1300			if (!scsicmd)
1301				break;
1302			/* complete the orig cmd */
1303			complete_scsi_command(cmdrsp, scsicmd);
1304		} else if (cmdrsp->cmdtype == CMD_SCSITASKMGMT_TYPE) {
1305			if (!del_scsipending_entry(virthbainfo,
1306				   (uintptr_t) cmdrsp->scsitaskmgmt.scsicmd))
1307				break;
1308			complete_taskmgmt_command(cmdrsp);
1309		} else if (cmdrsp->cmdtype == CMD_NOTIFYGUEST_TYPE) {
1310			/* The vHba pointer has no meaning in
1311			 * a Client/Guest Partition. Let's be
1312			 * safe and set it to NULL now.  Do
1313			 * not use it here! */
1314			cmdrsp->disknotify.vHba = NULL;
1315			process_disk_notify(shost, cmdrsp);
1316		} else if (cmdrsp->cmdtype == CMD_VDISKMGMT_TYPE) {
1317			if (!del_scsipending_entry(virthbainfo,
1318				   (uintptr_t) cmdrsp->vdiskmgmt.scsicmd))
1319				break;
1320			complete_vdiskmgmt_command(cmdrsp);
1321		} else
1322			LOGERR("Invalid cmdtype %d\n", cmdrsp->cmdtype);
1323		/* cmdrsp is now available for reuse */
1324	}
1325}
1326
1327
1328/* main function for the thread that waits for scsi commands to arrive
1329 * in a specified queue
1330 */
1331static int
1332process_incoming_rsps(void *v)
1333{
1334	struct virthba_info *virthbainfo = v;
1335	struct chaninfo *dc = &virthbainfo->chinfo;
1336	struct uiscmdrsp *cmdrsp = NULL;
1337	const int SZ = sizeof(struct uiscmdrsp);
1338	U64 mask;
1339	unsigned long long rc1;
1340
1341	UIS_DAEMONIZE("vhba_incoming");
1342	/* alloc once and reuse */
1343	cmdrsp = kmalloc(SZ, GFP_ATOMIC);
1344	if (cmdrsp == NULL) {
1345		LOGERR("process_incoming_rsps ****FAILED to malloc - thread exiting\n");
1346		complete_and_exit(&dc->threadinfo.has_stopped, 0);
1347		return 0;
1348	}
1349	mask = ULTRA_CHANNEL_ENABLE_INTS;
1350	while (1) {
1351		wait_event_interruptible_timeout(virthbainfo->rsp_queue,
1352			 (atomic_read(&virthbainfo->interrupt_rcvd) == 1),
1353					 usecs_to_jiffies(rsltq_wait_usecs));
1354		atomic_set(&virthbainfo->interrupt_rcvd, 0);
1355		/* drain queue */
1356		drain_queue(virthbainfo, dc, cmdrsp);
1357		rc1 = uisqueue_InterlockedOr(virthbainfo->flags_addr, mask);
1358		if (dc->threadinfo.should_stop)
1359			break;
1360	}
1361
1362	kfree(cmdrsp);
1363
1364	DBGINF("exiting processing incoming rsps.\n");
1365	complete_and_exit(&dc->threadinfo.has_stopped, 0);
1366}
1367
1368/*****************************************************/
1369/* Debugfs filesystem functions                      */
1370/*****************************************************/
1371
1372static ssize_t info_debugfs_read(struct file *file,
1373			char __user *buf, size_t len, loff_t *offset)
1374{
1375	ssize_t bytes_read = 0;
1376	int str_pos = 0;
1377	U64 phys_flags_addr;
1378	int i;
1379	struct virthba_info *virthbainfo;
1380	char *vbuf;
1381
1382	if (len > MAX_BUF)
1383		len = MAX_BUF;
1384	vbuf = kzalloc(len, GFP_KERNEL);
1385	if (!vbuf)
1386		return -ENOMEM;
1387
1388	for (i = 0; i < VIRTHBASOPENMAX; i++) {
1389		if (VirtHbasOpen[i].virthbainfo == NULL)
1390			continue;
1391
1392		virthbainfo = VirtHbasOpen[i].virthbainfo;
1393
1394		str_pos += scnprintf(vbuf + str_pos,
1395				len - str_pos, "MaxBuffLen:%u\n", MaxBuffLen);
1396
1397		str_pos += scnprintf(vbuf + str_pos, len - str_pos,
1398				"\nvirthba result queue poll wait:%d usecs.\n",
1399				rsltq_wait_usecs);
1400		str_pos += scnprintf(vbuf + str_pos, len - str_pos,
1401				"\ninterrupts_rcvd = %llu, interrupts_disabled = %llu\n",
1402				virthbainfo->interrupts_rcvd,
1403				virthbainfo->interrupts_disabled);
1404		str_pos += scnprintf(vbuf + str_pos,
1405				len - str_pos, "\ninterrupts_notme = %llu,\n",
1406				virthbainfo->interrupts_notme);
1407		phys_flags_addr = virt_to_phys((__force  void *)
1408					       virthbainfo->flags_addr);
1409		str_pos += scnprintf(vbuf + str_pos, len - str_pos,
1410				"flags_addr = %p, phys_flags_addr=0x%016llx, FeatureFlags=%llu\n",
1411				virthbainfo->flags_addr, phys_flags_addr,
1412				(__le64)readq(virthbainfo->flags_addr));
1413		str_pos += scnprintf(vbuf + str_pos,
1414			len - str_pos, "acquire_failed_cnt:%llu\n",
1415			virthbainfo->acquire_failed_cnt);
1416		str_pos += scnprintf(vbuf + str_pos, len - str_pos, "\n");
1417	}
1418
1419	bytes_read = simple_read_from_buffer(buf, len, offset, vbuf, str_pos);
1420	kfree(vbuf);
1421	return bytes_read;
1422}
1423
1424static ssize_t enable_ints_write(struct file *file,
1425			const char __user *buffer, size_t count, loff_t *ppos)
1426{
1427	char buf[4];
1428	int i, new_value;
1429	struct virthba_info *virthbainfo;
1430
1431	U64 __iomem *Features_addr;
1432	U64 mask;
1433
1434	if (count >= ARRAY_SIZE(buf))
1435		return -EINVAL;
1436
1437	buf[count] = '\0';
1438	if (copy_from_user(buf, buffer, count)) {
1439		LOGERR("copy_from_user failed. buf<<%.*s>> count<<%lu>>\n",
1440		       (int) count, buf, count);
1441		return -EFAULT;
1442	}
1443
1444	i = kstrtoint(buf, 10 , &new_value);
1445
1446	if (i != 0) {
1447		LOGERR("Failed to scan value for enable_ints, buf<<%.*s>>",
1448		       (int) count, buf);
1449		return -EFAULT;
1450	}
1451
1452	/*set all counts to new_value usually 0*/
1453	for (i = 0; i < VIRTHBASOPENMAX; i++) {
1454		if (VirtHbasOpen[i].virthbainfo != NULL) {
1455			virthbainfo = VirtHbasOpen[i].virthbainfo;
1456			Features_addr =
1457				&virthbainfo->chinfo.queueinfo->chan->Features;
1458			if (new_value == 1) {
1459				mask = ~(ULTRA_IO_CHANNEL_IS_POLLING |
1460					 ULTRA_IO_DRIVER_DISABLES_INTS);
1461				uisqueue_InterlockedAnd(Features_addr, mask);
1462				mask = ULTRA_IO_DRIVER_ENABLES_INTS;
1463				uisqueue_InterlockedOr(Features_addr, mask);
1464				rsltq_wait_usecs = 4000000;
1465			} else {
1466				mask = ~(ULTRA_IO_DRIVER_ENABLES_INTS |
1467					 ULTRA_IO_DRIVER_DISABLES_INTS);
1468				uisqueue_InterlockedAnd(Features_addr, mask);
1469				mask = ULTRA_IO_CHANNEL_IS_POLLING;
1470				uisqueue_InterlockedOr(Features_addr, mask);
1471				rsltq_wait_usecs = 4000;
1472			}
1473		}
1474	}
1475	return count;
1476}
1477
1478/* As per VirtpciFunc returns 1 for success and 0 for failure */
1479static int
1480virthba_serverup(struct virtpci_dev *virtpcidev)
1481{
1482	struct virthba_info *virthbainfo =
1483	    (struct virthba_info *) ((struct Scsi_Host *) virtpcidev->scsi.
1484				     scsihost)->hostdata;
1485
1486	DBGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo,
1487	       virtpcidev->deviceNo);
1488
1489	if (!virthbainfo->serverdown) {
1490		DBGINF("Server up message received while server is already up.\n");
1491		return 1;
1492	}
1493	if (virthbainfo->serverchangingstate) {
1494		LOGERR("Server already processing change state message\n");
1495		return 0;
1496	}
1497
1498	virthbainfo->serverchangingstate = true;
1499	/* Must transition channel to ATTACHED state BEFORE we
1500	 * can start using the device again
1501	 */
1502	ULTRA_CHANNEL_CLIENT_TRANSITION(virthbainfo->chinfo.queueinfo->chan,
1503					dev_name(&virtpcidev->generic_dev),
1504					CHANNELCLI_ATTACHED, NULL);
1505
1506	/* Start Processing the IOVM Response Queue Again */
1507	if (!uisthread_start(&virthbainfo->chinfo.threadinfo,
1508			     process_incoming_rsps,
1509			     virthbainfo, "vhba_incoming")) {
1510		LOGERR("uisthread_start rsp ****FAILED\n");
1511		return 0;
1512	}
1513	virthbainfo->serverdown = false;
1514	virthbainfo->serverchangingstate = false;
1515
1516	return 1;
1517}
1518
1519static void
1520virthba_serverdown_complete(struct work_struct *work)
1521{
1522	struct virthba_info *virthbainfo;
1523	struct virtpci_dev *virtpcidev;
1524	int i;
1525	struct scsipending *pendingdel = NULL;
1526	struct scsi_cmnd *scsicmd = NULL;
1527	struct uiscmdrsp *cmdrsp;
1528	unsigned long flags;
1529
1530	virthbainfo = container_of(work, struct virthba_info,
1531				   serverdown_completion);
1532
1533	/* Stop Using the IOVM Response Queue (queue should be drained
1534	 * by the end)
1535	 */
1536	uisthread_stop(&virthbainfo->chinfo.threadinfo);
1537
1538	/* Fail Commands that weren't completed */
1539	spin_lock_irqsave(&virthbainfo->privlock, flags);
1540	for (i = 0; i < MAX_PENDING_REQUESTS; i++) {
1541		pendingdel = &(virthbainfo->pending[i]);
1542		switch (pendingdel->cmdtype) {
1543		case CMD_SCSI_TYPE:
1544			scsicmd = (struct scsi_cmnd *) pendingdel->sent;
1545			scsicmd->result = (DID_RESET << 16);
1546			if (scsicmd->scsi_done)
1547				scsicmd->scsi_done(scsicmd);
1548			break;
1549		case CMD_SCSITASKMGMT_TYPE:
1550			cmdrsp = (struct uiscmdrsp *) pendingdel->sent;
1551			DBGINF("cmdrsp=0x%x, notify=0x%x\n", cmdrsp,
1552			       cmdrsp->scsitaskmgmt.notify);
1553			*(int *) cmdrsp->scsitaskmgmt.notifyresult =
1554			    TASK_MGMT_FAILED;
1555			wake_up_all((wait_queue_head_t *)
1556				    cmdrsp->scsitaskmgmt.notify);
1557			break;
1558		case CMD_VDISKMGMT_TYPE:
1559			cmdrsp = (struct uiscmdrsp *) pendingdel->sent;
1560			*(int *) cmdrsp->vdiskmgmt.notifyresult =
1561			    VDISK_MGMT_FAILED;
1562			wake_up_all((wait_queue_head_t *)
1563				    cmdrsp->vdiskmgmt.notify);
1564			break;
1565		default:
1566			if (pendingdel->sent != NULL)
1567				LOGERR("Unknown command type: 0x%x.  Only freeing list structure.\n",
1568				     pendingdel->cmdtype);
1569		}
1570		pendingdel->cmdtype = 0;
1571		pendingdel->sent = NULL;
1572	}
1573	spin_unlock_irqrestore(&virthbainfo->privlock, flags);
1574
1575	virtpcidev = virthbainfo->virtpcidev;
1576
1577	DBGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo,
1578	       virtpcidev->deviceNo);
1579	virthbainfo->serverdown = true;
1580	virthbainfo->serverchangingstate = false;
1581	/* Return the ServerDown response to Command */
1582	visorchipset_device_pause_response(virtpcidev->busNo,
1583					   virtpcidev->deviceNo, 0);
1584}
1585
1586/* As per VirtpciFunc returns 1 for success and 0 for failure */
1587static int
1588virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state)
1589{
1590	struct virthba_info *virthbainfo =
1591	    (struct virthba_info *) ((struct Scsi_Host *) virtpcidev->scsi.
1592				     scsihost)->hostdata;
1593
1594	DBGINF("virthba_serverdown");
1595	DBGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo,
1596	       virtpcidev->deviceNo);
1597
1598	if (!virthbainfo->serverdown && !virthbainfo->serverchangingstate) {
1599		virthbainfo->serverchangingstate = true;
1600		queue_work(virthba_serverdown_workqueue,
1601			   &virthbainfo->serverdown_completion);
1602	} else if (virthbainfo->serverchangingstate) {
1603		LOGERR("Server already processing change state message\n");
1604		return 0;
1605	} else
1606		LOGERR("Server already down, but another server down message received.");
1607
1608	return 1;
1609}
1610
1611/*****************************************************/
1612/* Module Init & Exit functions                      */
1613/*****************************************************/
1614
1615static int __init
1616virthba_parse_line(char *str)
1617{
1618	DBGINF("In virthba_parse_line %s\n", str);
1619	return 1;
1620}
1621
1622static void __init
1623virthba_parse_options(char *line)
1624{
1625	char *next = line;
1626
1627	POSTCODE_LINUX_2(VHBA_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
1628	if (line == NULL || !*line)
1629		return;
1630	while ((line = next) != NULL) {
1631		next = strchr(line, ' ');
1632		if (next != NULL)
1633			*next++ = 0;
1634		if (!virthba_parse_line(line))
1635			DBGINF("Unknown option '%s'\n", line);
1636	}
1637
1638	POSTCODE_LINUX_2(VHBA_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
1639}
1640
1641static int __init
1642virthba_mod_init(void)
1643{
1644	int error;
1645	int i;
1646
1647	if (!unisys_spar_platform)
1648		return -ENODEV;
1649
1650	LOGINF("Entering virthba_mod_init...\n");
1651
1652	POSTCODE_LINUX_2(VHBA_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
1653	virthba_parse_options(virthba_options);
1654
1655	error = virtpci_register_driver(&virthba_driver);
1656	if (error < 0) {
1657		LOGERR("register ****FAILED 0x%x\n", error);
1658		POSTCODE_LINUX_3(VHBA_CREATE_FAILURE_PC, error,
1659				 POSTCODE_SEVERITY_ERR);
1660	} else {
1661
1662		/* create the debugfs directories and entries */
1663		virthba_debugfs_dir = debugfs_create_dir("virthba", NULL);
1664		debugfs_create_file("info", S_IRUSR, virthba_debugfs_dir,
1665				NULL, &debugfs_info_fops);
1666		debugfs_create_u32("rqwait_usecs", S_IRUSR | S_IWUSR,
1667				virthba_debugfs_dir, &rsltq_wait_usecs);
1668		debugfs_create_file("enable_ints", S_IWUSR,
1669				virthba_debugfs_dir, NULL,
1670				&debugfs_enable_ints_fops);
1671		/* Initialize DARWorkQ */
1672		INIT_WORK(&DARWorkQ, doDiskAddRemove);
1673		spin_lock_init(&DARWorkQLock);
1674
1675		/* clear out array */
1676		for (i = 0; i < VIRTHBASOPENMAX; i++)
1677			VirtHbasOpen[i].virthbainfo = NULL;
1678		/* Initialize the serverdown workqueue */
1679		virthba_serverdown_workqueue =
1680		    create_singlethread_workqueue("virthba_serverdown");
1681		if (virthba_serverdown_workqueue == NULL) {
1682			LOGERR("**** FAILED virthba_serverdown_workqueue creation\n");
1683			POSTCODE_LINUX_2(VHBA_CREATE_FAILURE_PC,
1684					 POSTCODE_SEVERITY_ERR);
1685			error = -1;
1686		}
1687	}
1688
1689	POSTCODE_LINUX_2(VHBA_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
1690	LOGINF("Leaving virthba_mod_init\n");
1691	return error;
1692}
1693
1694static ssize_t
1695virthba_acquire_lun(struct device *cdev, struct device_attribute *attr,
1696		    const char *buf, size_t count)
1697{
1698	struct uisscsi_dest vdest;
1699	struct Scsi_Host *shost = class_to_shost(cdev);
1700	int i;
1701
1702	i = sscanf(buf, "%d-%d-%d", &vdest.channel, &vdest.id, &vdest.lun);
1703	if (i != 3)
1704		return i;
1705
1706	return forward_vdiskmgmt_command(VDISK_MGMT_ACQUIRE, shost, &vdest);
1707}
1708
1709static ssize_t
1710virthba_release_lun(struct device *cdev, struct device_attribute *attr,
1711		    const char *buf, size_t count)
1712{
1713	struct uisscsi_dest vdest;
1714	struct Scsi_Host *shost = class_to_shost(cdev);
1715	int i;
1716
1717	i = sscanf(buf, "%d-%d-%d", &vdest.channel, &vdest.id, &vdest.lun);
1718	if (i != 3)
1719		return i;
1720
1721	return forward_vdiskmgmt_command(VDISK_MGMT_RELEASE, shost, &vdest);
1722}
1723
1724#define CLASS_DEVICE_ATTR(_name, _mode, _show, _store)      \
1725	struct device_attribute class_device_attr_##_name =   \
1726		__ATTR(_name, _mode, _show, _store)
1727
1728static CLASS_DEVICE_ATTR(acquire_lun, S_IWUSR, NULL, virthba_acquire_lun);
1729static CLASS_DEVICE_ATTR(release_lun, S_IWUSR, NULL, virthba_release_lun);
1730
1731static DEVICE_ATTRIBUTE *virthba_shost_attrs[] = {
1732	&class_device_attr_acquire_lun,
1733	&class_device_attr_release_lun,
1734	NULL
1735};
1736
1737static void __exit
1738virthba_mod_exit(void)
1739{
1740	LOGINF("entering virthba_mod_exit...\n");
1741
1742	virtpci_unregister_driver(&virthba_driver);
1743	/* unregister is going to call virthba_remove */
1744	/* destroy serverdown completion workqueue */
1745	if (virthba_serverdown_workqueue) {
1746		destroy_workqueue(virthba_serverdown_workqueue);
1747		virthba_serverdown_workqueue = NULL;
1748	}
1749
1750	/* remove debugfs directory and files. */
1751	debugfs_remove_recursive(virthba_debugfs_dir);
1752	LOGINF("Leaving virthba_mod_exit\n");
1753
1754}
1755
1756/* specify function to be run at module insertion time */
1757module_init(virthba_mod_init);
1758
1759/* specify function to be run when module is removed */
1760module_exit(virthba_mod_exit);
1761
1762MODULE_LICENSE("GPL");
1763MODULE_AUTHOR("Usha Srinivasan");
1764MODULE_ALIAS("uisvirthba");
1765	/* this is extracted during depmod and kept in modules.dep */
1766/* module parameter */
1767module_param(virthba_options, charp, S_IRUGO);
1768