// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2012 - 2015 UNISYS CORPORATION
* All rights reserved.
*/
#include <linux/debugfs.h>
#include <linux/kthread.h>
#include <linux/idr.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/visorbus.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include "iochannel.h"
/* The Send and Receive Buffers of the IO Queue may both be full */
#define IOS_ERROR_THRESHOLD 1000
#define MAX_PENDING_REQUESTS (MIN_NUMSIGNALS * 2)
#define VISORHBA_ERROR_COUNT 30
static struct dentry *visorhba_debugfs_dir;
/* GUIDS for HBA channel type supported by this driver */
static struct visor_channeltype_descriptor visorhba_channel_types[] = {
/* Note that the only channel type we expect to be reported by the
* bus driver is the VISOR_VHBA channel.
*/
{ VISOR_VHBA_CHANNEL_GUID, "sparvhba", sizeof(struct channel_header),
VISOR_VHBA_CHANNEL_VERSIONID },
{}
};
MODULE_DEVICE_TABLE(visorbus, visorhba_channel_types);
MODULE_ALIAS("visorbus:" VISOR_VHBA_CHANNEL_GUID_STR);
struct visordisk_info {
struct scsi_device *sdev;
u32 valid;
atomic_t ios_threshold;
atomic_t error_count;
struct visordisk_info *next;
};
struct scsipending {
struct uiscmdrsp cmdrsp;
/* The Data being tracked */
void *sent;
/* Type of pointer that is being stored */
char cmdtype;
};
/* Each scsi_host has a host_data area that contains this struct. */
struct visorhba_devdata {
struct Scsi_Host *scsihost;
struct visor_device *dev;
struct list_head dev_info_list;
/* Tracks the requests that have been forwarded to
* the IOVM and haven't returned yet
*/
struct scsipending pending[MAX_PENDING_REQUESTS];
/* Start search for next pending free slot here */
unsigned int nextinsert;
/* lock to protect data in devdata */
spinlock_t privlock;
bool serverdown;
bool serverchangingstate;
unsigned long long acquire_failed_cnt;
unsigned long long interrupts_rcvd;
unsigned long long interrupts_notme;
unsigned long long interrupts_disabled;
u64 __iomem *flags_addr;
atomic_t interrupt_rcvd;
wait_queue_head_t rsp_queue;
struct visordisk_info head;
unsigned int max_buff_len;
int devnum;
struct task_struct *thread;
int thread_wait_ms;
/*
* allows us to pass int handles back-and-forth between us and
* iovm, instead of raw pointers
*/
struct idr idr;
struct dentry *debugfs_dir;
struct dentry *debugfs_info;
};
struct visorhba_devices_open {
struct visorhba_devdata *devdata;
};
/*
* visor_thread_start - Starts a thread for the device
* @threadfn: Function the thread starts
* @thrcontext: Context to pass to the thread, i.e. devdata
* @name: String describing name of thread
*
* Starts a thread for the device.
*
* Return: The task_struct * denoting the thread on success,
* or NULL on failure
*/
static struct task_struct *visor_thread_start(int (*threadfn)(void *),
void *thrcontext, char *name)
{
struct task_struct *task;
task = kthread_run(threadfn, thrcontext, "%s", name);
if (IS_ERR(task)) {
pr_err("visorbus failed to start thread\n");
return NULL;
}
return task;
}
/*
* visor_thread_stop - Stops the thread if it is running
* @task: Description of process to stop
*/
static