Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d3849d51 authored by David Woodhouse's avatar David Woodhouse Committed by James Bottomley
Browse files

[SCSI] Fix ibmvscsi client for multiplatform iSeries+pSeries kernel



If you build a multiplatform kernel for iSeries and pSeries, with
ibmvscsic support, the resulting client doesn't work on iSeries.

This fixes that, using the appropriate low-level operations
for the machine detected at runtime.

[jejb: fixed up rejections around the srp transport patch]

Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
Acked by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 5307b1e8
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
obj-$(CONFIG_SCSI_IBMVSCSI)	+= ibmvscsic.o

ibmvscsic-y			+= ibmvscsi.o
ifndef CONFIG_PPC_PSERIES
ibmvscsic-$(CONFIG_PPC_ISERIES)	+= iseries_vscsi.o 
endif
ibmvscsic-$(CONFIG_PPC_PSERIES)	+= rpa_vscsi.o 

obj-$(CONFIG_SCSI_IBMVSCSIS)	+= ibmvstgt.o
+28 −18
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@
#include <linux/moduleparam.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <asm/firmware.h>
#include <asm/vio.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -92,6 +93,8 @@ static struct scsi_transport_template *ibmvscsi_transport_template;

#define IBMVSCSI_VERSION "1.5.8"

static struct ibmvscsi_ops *ibmvscsi_ops;

MODULE_DESCRIPTION("IBM Virtual SCSI");
MODULE_AUTHOR("Dave Boutcher");
MODULE_LICENSE("GPL");
@@ -509,8 +512,8 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
	atomic_set(&hostdata->request_limit, 0);

	purge_requests(hostdata, DID_ERROR);
	if ((ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata)) ||
	    (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0)) ||
	if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata)) ||
	    (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0)) ||
	    (vio_enable_interrupts(to_vio_dev(hostdata->dev)))) {
		atomic_set(&hostdata->request_limit, -1);
		dev_err(hostdata->dev, "error after reset\n");
@@ -615,7 +618,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
	}

	if ((rc =
	     ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
	     ibmvscsi_ops->send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
		list_del(&evt_struct->list);
		del_timer(&evt_struct->timer);

@@ -1214,7 +1217,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
		case 0x01:	/* Initialization message */
			dev_info(hostdata->dev, "partner initialized\n");
			/* Send back a response */
			if ((rc = ibmvscsi_send_crq(hostdata,
			if ((rc = ibmvscsi_ops->send_crq(hostdata,
							 0xC002000000000000LL, 0)) == 0) {
				/* Now login */
				send_srp_login(hostdata);
@@ -1240,9 +1243,9 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
			/* We need to re-setup the interpartition connection */
			dev_info(hostdata->dev, "Re-enabling adapter!\n");
			purge_requests(hostdata, DID_REQUEUE);
			if ((ibmvscsi_reenable_crq_queue(&hostdata->queue,
			if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue,
							      hostdata)) ||
			    (ibmvscsi_send_crq(hostdata,
			    (ibmvscsi_ops->send_crq(hostdata,
						    0xC001000000000000LL, 0))) {
					atomic_set(&hostdata->request_limit,
						   -1);
@@ -1253,9 +1256,9 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
				crq->format);

			purge_requests(hostdata, DID_ERROR);
			if ((ibmvscsi_reset_crq_queue(&hostdata->queue,
			if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue,
							   hostdata)) ||
			    (ibmvscsi_send_crq(hostdata,
			    (ibmvscsi_ops->send_crq(hostdata,
						    0xC001000000000000LL, 0))) {
					atomic_set(&hostdata->request_limit,
						   -1);
@@ -1579,7 +1582,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
	atomic_set(&hostdata->request_limit, -1);
	hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */

	rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests);
	rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_requests);
	if (rc != 0 && rc != H_RESOURCE) {
		dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
		goto init_crq_failed;
@@ -1608,7 +1611,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
	 * to fail if the other end is not acive.  In that case we don't
	 * want to scan
	 */
	if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0
	if (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0) == 0
	    || rc == H_RESOURCE) {
		/*
		 * Wait around max init_timeout secs for the adapter to finish
@@ -1636,7 +1639,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
      add_host_failed:
	release_event_pool(&hostdata->pool, hostdata);
      init_pool_failed:
	ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_requests);
	ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_requests);
      init_crq_failed:
	scsi_host_put(host);
      scsi_host_alloc_failed:
@@ -1647,7 +1650,7 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
{
	struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
	release_event_pool(&hostdata->pool, hostdata);
	ibmvscsi_release_crq_queue(&hostdata->queue, hostdata,
	ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
					max_requests);

	srp_remove_host(hostdata->host);
@@ -1684,6 +1687,13 @@ int __init ibmvscsi_module_init(void)
{
	int ret;

	if (firmware_has_feature(FW_FEATURE_ISERIES))
		ibmvscsi_ops = &iseriesvscsi_ops;
	else if (firmware_has_feature(FW_FEATURE_VIO))
		ibmvscsi_ops = &rpavscsi_ops;
	else
		return -ENODEV;

	ibmvscsi_transport_template =
		srp_attach_transport(&ibmvscsi_transport_functions);
	if (!ibmvscsi_transport_template)
+18 −14
Original line number Diff line number Diff line
@@ -98,21 +98,25 @@ struct ibmvscsi_host_data {
};

/* routines for managing a command/response queue */
int ibmvscsi_init_crq_queue(struct crq_queue *queue,
void ibmvscsi_handle_crq(struct viosrp_crq *crq,
			 struct ibmvscsi_host_data *hostdata);

struct ibmvscsi_ops {
	int (*init_crq_queue)(struct crq_queue *queue,
			      struct ibmvscsi_host_data *hostdata,
			      int max_requests);
void ibmvscsi_release_crq_queue(struct crq_queue *queue,
	void (*release_crq_queue)(struct crq_queue *queue,
				  struct ibmvscsi_host_data *hostdata,
				  int max_requests);
int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
	int (*reset_crq_queue)(struct crq_queue *queue,
			       struct ibmvscsi_host_data *hostdata);

int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
	int (*reenable_crq_queue)(struct crq_queue *queue,
				  struct ibmvscsi_host_data *hostdata);

void ibmvscsi_handle_crq(struct viosrp_crq *crq,
			 struct ibmvscsi_host_data *hostdata);
int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
	int (*send_crq)(struct ibmvscsi_host_data *hostdata,
		       u64 word1, u64 word2);
};

extern struct ibmvscsi_ops iseriesvscsi_ops;
extern struct ibmvscsi_ops rpavscsi_ops;

#endif				/* IBMVSCSI_H */
+23 −14
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ struct srp_lp_event {
/** 
 * standard interface for handling logical partition events.
 */
static void ibmvscsi_handle_event(struct HvLpEvent *lpevt)
static void iseriesvscsi_handle_event(struct HvLpEvent *lpevt)
{
	struct srp_lp_event *evt = (struct srp_lp_event *)lpevt;

@@ -74,7 +74,7 @@ static void ibmvscsi_handle_event(struct HvLpEvent *lpevt)
/* ------------------------------------------------------------
 * Routines for driver initialization
 */
int ibmvscsi_init_crq_queue(struct crq_queue *queue,
static int iseriesvscsi_init_crq_queue(struct crq_queue *queue,
				       struct ibmvscsi_host_data *hostdata,
				       int max_requests)
{
@@ -88,7 +88,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
		goto viopath_open_failed;
	}

	rc = vio_setHandler(viomajorsubtype_scsi, ibmvscsi_handle_event);
	rc = vio_setHandler(viomajorsubtype_scsi, iseriesvscsi_handle_event);
	if (rc < 0) {
		printk("vio_setHandler failed with rc %d in open_event_path\n",
		       rc);
@@ -102,7 +102,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
	return -1;
}

void ibmvscsi_release_crq_queue(struct crq_queue *queue,
static void iseriesvscsi_release_crq_queue(struct crq_queue *queue,
					   struct ibmvscsi_host_data *hostdata,
					   int max_requests)
{
@@ -117,7 +117,7 @@ void ibmvscsi_release_crq_queue(struct crq_queue *queue,
 *
 * no-op for iSeries
 */
int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
static int iseriesvscsi_reset_crq_queue(struct crq_queue *queue,
					struct ibmvscsi_host_data *hostdata)
{
	return 0;
@@ -130,19 +130,20 @@ int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
 *
 * no-op for iSeries
 */
int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
static int iseriesvscsi_reenable_crq_queue(struct crq_queue *queue,
					   struct ibmvscsi_host_data *hostdata)
{
	return 0;
}

/**
 * ibmvscsi_send_crq: - Send a CRQ
 * iseriesvscsi_send_crq: - Send a CRQ
 * @hostdata:	the adapter
 * @word1:	the first 64 bits of the data
 * @word2:	the second 64 bits of the data
 */
int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
static int iseriesvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
				 u64 word1, u64 word2)
{
	single_host_data = hostdata;
	return HvCallEvent_signalLpEventFast(viopath_hostLp,
@@ -156,3 +157,11 @@ int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
					     VIOVERSION << 16, word1, word2, 0,
					     0);
}

struct ibmvscsi_ops iseriesvscsi_ops = {
	.init_crq_queue = iseriesvscsi_init_crq_queue,
	.release_crq_queue = iseriesvscsi_release_crq_queue,
	.reset_crq_queue = iseriesvscsi_reset_crq_queue,
	.reenable_crq_queue = iseriesvscsi_reenable_crq_queue,
	.send_crq = iseriesvscsi_send_crq,
};
+61 −52
Original line number Diff line number Diff line
@@ -42,14 +42,14 @@ static unsigned int partition_number = -1;
 * Routines for managing the command/response queue
 */
/**
 * ibmvscsi_handle_event: - Interrupt handler for crq events
 * rpavscsi_handle_event: - Interrupt handler for crq events
 * @irq:	number of irq to handle, not used
 * @dev_instance: ibmvscsi_host_data of host that received interrupt
 *
 * Disables interrupts and schedules srp_task
 * Always returns IRQ_HANDLED
 */
static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
static irqreturn_t rpavscsi_handle_event(int irq, void *dev_instance)
{
	struct ibmvscsi_host_data *hostdata =
	    (struct ibmvscsi_host_data *)dev_instance;
@@ -66,7 +66,7 @@ static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
 * Frees irq, deallocates a page for messages, unmaps dma, and unregisters
 * the crq with the hypervisor.
 */
void ibmvscsi_release_crq_queue(struct crq_queue *queue,
static void rpavscsi_release_crq_queue(struct crq_queue *queue,
				       struct ibmvscsi_host_data *hostdata,
				       int max_requests)
{
@@ -108,12 +108,13 @@ static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue)
}

/**
 * ibmvscsi_send_crq: - Send a CRQ
 * rpavscsi_send_crq: - Send a CRQ
 * @hostdata:	the adapter
 * @word1:	the first 64 bits of the data
 * @word2:	the second 64 bits of the data
 */
int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
static int rpavscsi_send_crq(struct ibmvscsi_host_data *hostdata,
			     u64 word1, u64 word2)
{
	struct vio_dev *vdev = to_vio_dev(hostdata->dev);

@@ -121,10 +122,10 @@ int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
}

/**
 * ibmvscsi_task: - Process srps asynchronously
 * rpavscsi_task: - Process srps asynchronously
 * @data:	ibmvscsi_host_data of host
 */
static void ibmvscsi_task(void *data)
static void rpavscsi_task(void *data)
{
	struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data;
	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -189,6 +190,42 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
	hostdata->madapter_info.os_type = 2;
}

/**
 * reset_crq_queue: - resets a crq after a failure
 * @queue:	crq_queue to initialize and register
 * @hostdata:	ibmvscsi_host_data of host
 *
 */
static int rpavscsi_reset_crq_queue(struct crq_queue *queue,
				    struct ibmvscsi_host_data *hostdata)
{
	int rc;
	struct vio_dev *vdev = to_vio_dev(hostdata->dev);

	/* Close the CRQ */
	do {
		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));

	/* Clean out the queue */
	memset(queue->msgs, 0x00, PAGE_SIZE);
	queue->cur = 0;

	set_adapter_info(hostdata);

	/* And re-open it again */
	rc = plpar_hcall_norets(H_REG_CRQ,
				vdev->unit_address,
				queue->msg_token, PAGE_SIZE);
	if (rc == 2) {
		/* Adapter is good, but other end is not ready */
		dev_warn(hostdata->dev, "Partner adapter not ready\n");
	} else if (rc != 0) {
		dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
	}
	return rc;
}

/**
 * initialize_crq_queue: - Initializes and registers CRQ with hypervisor
 * @queue:	crq_queue to initialize and register
@@ -198,7 +235,7 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
 * the crq with the hypervisor.
 * Returns zero on success.
 */
int ibmvscsi_init_crq_queue(struct crq_queue *queue,
static int rpavscsi_init_crq_queue(struct crq_queue *queue,
				   struct ibmvscsi_host_data *hostdata,
				   int max_requests)
{
@@ -227,7 +264,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
				queue->msg_token, PAGE_SIZE);
	if (rc == H_RESOURCE)
		/* maybe kexecing and resource is busy. try a reset */
		rc = ibmvscsi_reset_crq_queue(queue,
		rc = rpavscsi_reset_crq_queue(queue,
					      hostdata);

	if (rc == 2) {
@@ -240,7 +277,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
	}

	if (request_irq(vdev->irq,
			ibmvscsi_handle_event,
			rpavscsi_handle_event,
			0, "ibmvscsi", (void *)hostdata) != 0) {
		dev_err(hostdata->dev, "couldn't register irq 0x%x\n",
			vdev->irq);
@@ -256,7 +293,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
	queue->cur = 0;
	spin_lock_init(&queue->lock);

	tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task,
	tasklet_init(&hostdata->srp_task, (void *)rpavscsi_task,
		     (unsigned long)hostdata);

	return retrc;
@@ -281,7 +318,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
 * @hostdata:	ibmvscsi_host_data of host
 *
 */
int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
static int rpavscsi_reenable_crq_queue(struct crq_queue *queue,
				       struct ibmvscsi_host_data *hostdata)
{
	int rc;
@@ -297,38 +334,10 @@ int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
	return rc;
}

/**
 * reset_crq_queue: - resets a crq after a failure
 * @queue:	crq_queue to initialize and register
 * @hostdata:	ibmvscsi_host_data of host
 *
 */
int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
			      struct ibmvscsi_host_data *hostdata)
{
	int rc;
	struct vio_dev *vdev = to_vio_dev(hostdata->dev);

	/* Close the CRQ */
	do {
		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));

	/* Clean out the queue */
	memset(queue->msgs, 0x00, PAGE_SIZE);
	queue->cur = 0;

	set_adapter_info(hostdata);

	/* And re-open it again */
	rc = plpar_hcall_norets(H_REG_CRQ,
				vdev->unit_address,
				queue->msg_token, PAGE_SIZE);
	if (rc == 2) {
		/* Adapter is good, but other end is not ready */
		dev_warn(hostdata->dev, "Partner adapter not ready\n");
	} else if (rc != 0) {
		dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
	}
	return rc;
}
struct ibmvscsi_ops rpavscsi_ops = {
	.init_crq_queue = rpavscsi_init_crq_queue,
	.release_crq_queue = rpavscsi_release_crq_queue,
	.reset_crq_queue = rpavscsi_reset_crq_queue,
	.reenable_crq_queue = rpavscsi_reenable_crq_queue,
	.send_crq = rpavscsi_send_crq,
};