From 001e95d7c6c95acbfedec9391dd383e749d4db3e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 5 Nov 2010 20:35:00 +0000 Subject: [PATCH] Replaced ibmvscsis source code by a more recent version (svn merge -c2585 https://scst.svn.sourceforge.net/svnroot/scst/branches/ibmvstgt-port). git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@2614 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- ...05-ibmvscsis.c => SLES-10-SP3-ibmvscsis.c} | 1616 ++++++++++------- 1 file changed, 950 insertions(+), 666 deletions(-) rename ibmvstgt/src/{2005-ibmvscsis.c => SLES-10-SP3-ibmvscsis.c} (66%) diff --git a/ibmvstgt/src/2005-ibmvscsis.c b/ibmvstgt/src/SLES-10-SP3-ibmvscsis.c similarity index 66% rename from ibmvstgt/src/2005-ibmvscsis.c rename to ibmvstgt/src/SLES-10-SP3-ibmvscsis.c index cd4c7e8c6..6c15cb62d 100644 --- a/ibmvstgt/src/2005-ibmvscsis.c +++ b/ibmvstgt/src/SLES-10-SP3-ibmvscsis.c @@ -1,66 +1,65 @@ /************************************************************************ IBM eServer i/pSeries Virtual SCSI Target Driver - Copyright (C) 2003-2005 Dave Boutcher (boutcher@xxxxxxxxxx) IBM Corp. - Santiago Leon (santil@xxxxxxxxxx) IBM Corp. - Linda Xie (lxie@xxxxxxxxxx) IBM Corp. + Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp. + Santiago Leon (santil@us.ibm.com) IBM Corp. + Linda Xie (lxie@us.ibm.com) IBM Corp. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA - ********************************************************************** - This driver is a SCSI target that interoperates according to the PAPR - (POWER Architecture Platform Requirements) document. Currently it is - specific to POWER logical partitioning, however in the future it would - be nice to extend this to other virtualized environments. + ********************************************************************** + This driver is a SCSI target that interoperates according to the PAPR + (POWER Architecture Platform Requirements) document. Currently it is + specific to POWER logical partitioning, however in the future it would + be nice to extend this to other virtualized environments. - The architecture defines virtual adapters, whose configuration is - reported in the Open Firmware device tree. There area number of - power hypervisor calls (such as h_reg_crq, to register the inter-OS - queue) that support the virtual adapters. + The architecture defines virtual adapters, whose configuration is + reported in the Open Firmware device tree. There area number of + power hypervisor calls (such as h_reg_crq, to register the inter-OS + queue) that support the virtual adapters. - Messages are sent between partitions on a "Command/Response Queue" - (CRQ), which is just a buffer of 16 byte entries in the receiver's - Senders cannot access the buffer directly, but send messages by - making a hypervisor call and passing in the 16 bytes. The hypervisor - puts the message in the next 16 byte space in round-robbin fashion, - turns on the high order bit of the message (the valid bit), and - generates an interrupt to the receiver (if interrupts are turned on.) - The receiver just turns off the valid bit when they have copied out - the message. + Messages are sent between partitions on a "Command/Response Queue" + (CRQ), which is just a buffer of 16 byte entries in the receiver's + Senders cannot access the buffer directly, but send messages by + making a hypervisor call and passing in the 16 bytes. The hypervisor + puts the message in the next 16 byte space in round-robbin fashion, + turns on the high order bit of the message (the valid bit), and + generates an interrupt to the receiver (if interrupts are turned on.) + The receiver just turns off the valid bit when they have copied out + the message. - The VSCSI client builds a SCSI Remote Protocol (SRP) Information Unit - (IU) (as defined in the T10 standard available at www.t10.org), gets - a DMA address for the message, and sends it to the target as the - payload of a CRQ message. The target DMAs the SRP IU and processes it, - including doing any additional data transfers. When it is done, it - DMAs the SRP response back to the same address as the request came from - and sends a CRQ message back to inform the client that the request has - completed. + The VSCSI client builds a SCSI Remote Protocol (SRP) Information Unit + (IU) (as defined in the T10 standard available at www.t10.org), gets + a DMA address for the message, and sends it to the target as the + payload of a CRQ message. The target DMAs the SRP IU and processes it, + including doing any additional data transfers. When it is done, it + DMAs the SRP response back to the same address as the request came from + and sends a CRQ message back to inform the client that the request has + completed. - This target interoperates not only with the Linux client (ibmvscsi.c) - but also with AIX and OS/400 clients. Thus, while the implementation - can be changed, the underlying behaviour (protocol) is fixed. + This target interoperates not only with the Linux client (ibmvscsi.c) + but also with AIX and OS/400 clients. Thus, while the implementation + can be changed, the underlying behaviour (protocol) is fixed. - Configuration of the target is done via sysfs. The target driver - maps either block devices (e.g. IDE CD drive, loopback file, etc) to - SCSI LUNs, in which case it emulates the SCSI protocol and issues - kernel block device calls, or maps real SCSI devices, in which case - the SCSI commands are just passed on to the real SCSI device. + Configuration of the target is done via sysfs. The target driver + maps either block devices (e.g. IDE CD drive, loopback file, etc) to + SCSI LUNs, in which case it emulates the SCSI protocol and issues + kernel block device calls, or maps real SCSI devices, in which case + the SCSI commands are just passed on to the real SCSI device. ************************************************************************/ - #include #include #include @@ -86,7 +85,7 @@ #include #include #include -#include +#include #include "viosrp.h" @@ -101,20 +100,21 @@ #define DMA_BUFFER_INIT_COUNT (4) #define DMA_BUFFER_INIT_LEN (PAGE_SIZE*16) #define MODE_SENSE_BUFFER_SIZE (512) -#define REFCOUNT_TIMEOUT_MS (250) /* 1/4 second */ -#define DEFAULT_MAX_SECTORS (512) /* 256 kb */ +#define REFCOUNT_TIMEOUT_MS (250) /* 1/4 second */ +#define DEFAULT_MAX_SECTORS (512) /* 256 kb */ +#define MAX_H_COPY_RDMA (128*1024) /* * The following are lifted from usb.h */ static int ibmvscsis_debug = 0; -#define dbg(format, arg...) \ - do { \ - if (ibmvscsis_debug) printk(KERN_WARNING __FILE__ ": " \ - format , ## arg); \ +#define dbg(format, arg...) \ + do {\ + if (ibmvscsis_debug) printk(KERN_WARNING __FILE__ ": " \ + format , ## arg);\ } while(0) #define err(format, arg...) printk(KERN_ERR "ibmvscsis: " format , ## arg) -#define info(format, arg...) printk(KERN_INFO "ibmvscsis: " format , ## arg) +#define info(format, arg...) printk(KERN_INFO "ibmvscsis: " format , ## arg) #define warn(format, arg...) printk(KERN_WARNING "ibmvscsis: " format , ## arg) /* @@ -128,28 +128,27 @@ static int ibmvscsis_debug = 0; /* * sysfs attributes macro */ -#define ATTR(_type, _name, _mode) \ - struct attribute vscsi_##_type##_##_name##_attr = { \ - .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE \ +#define ATTR(_type, _name, _mode) \ + struct attribute vscsi_##_type##_##_name##_attr = { \ + .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE \ }; /* * Hypervisor calls. */ -#define h_copy_rdma(l, sa, sb, da, db) \ - plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db) -#define h_send_crq(ua, l, h) \ - plpar_hcall_norets(H_SEND_CRQ, ua, l, h) -#define h_reg_crq(ua, tok, sz) \ - plpar_hcall_norets(H_REG_CRQ, ua, tok, sz); -#define h_free_crq(ua) \ - plpar_hcall_norets(H_FREE_CRQ, ua); +#define h_send_crq(ua, l, h) \ + plpar_hcall_norets(H_SEND_CRQ, ua, l, h) +#define h_reg_crq(ua, tok, sz)\ + plpar_hcall_norets(H_REG_CRQ, ua, tok, sz); +#define h_free_crq(ua) \ + plpar_hcall_norets(H_FREE_CRQ, ua); MODULE_DESCRIPTION("IBM Virtual SCSI Target"); MODULE_AUTHOR("Dave Boutcher"); MODULE_LICENSE("GPL"); MODULE_VERSION(IBMVSCSIS_VERSION); + /* * These are fixed for the system and come from the Open Firmware device tree. * We just store them here to save getting them every time. @@ -181,7 +180,7 @@ struct inquiry_data { }; /* - * an RPA command/response transport queue. This is our structure + * an RPA command/response transport queue. This is our structure * that points to the actual queue (not architected by firmware) */ struct crq_queue { @@ -192,19 +191,19 @@ struct crq_queue { }; enum iue_flags { - V_IN_USE = 0, - V_DIOVER = 1, - V_WRITE = 2, - V_LINKED = 3, - V_ABORTED = 4, - V_FLYING = 5, - V_BARRIER = 6, - V_PARSED = 7, - V_DONE = 8, + V_IN_USE = 0, + V_DIOVER = 1, + V_WRITE = 2, + V_LINKED = 3, + V_ABORTED = 4, + V_FLYING = 5, + V_BARRIER = 6, + V_PARSED = 7, + V_DONE = 8, }; /* - * This structure tracks our fundamental unit of work. Whenever + * This structure tracks our fundamental unit of work. Whenever * an SRP Information Unit (IU) arrives, we track all the good stuff * here */ @@ -253,7 +252,7 @@ struct iu_pool { */ struct vdev { struct list_head list; - char direct_scsi; + char type; atomic_t refcount; int disabled; u64 lun; @@ -269,13 +268,10 @@ struct vdev { int removable; int changed; } b; - struct { - struct scsi_device *sdev; - } s; }; /* - * Represents a bus. target #'s in SCSI are 6 bits long, + * Represents a bus. target #'s in SCSI are 6 bits long, * so you can have 64 targets per bus */ struct vbus { @@ -286,8 +282,8 @@ struct vbus { }; /* - * Cached buffer. This is a data buffer that we have issued - * dma_map_foo on. Rather than do this every time we need a + * Cached buffer. This is a data buffer that we have issued + * dma_map_foo on. Rather than do this every time we need a * data buffer, keep a cache of mapped buffers around. */ struct dma_buffer { @@ -321,8 +317,8 @@ struct server_adapter { struct dma_buffer dma_buffer[DMA_BUFFER_CACHE_SIZE]; /* Statistics only */ - atomic_t iu_count; /* number allocated */ - atomic_t bio_count; /* number allocated */ + atomic_t iu_count; /* number allocated */ + atomic_t bio_count; /* number allocated */ atomic_t crq_processed; atomic_t interrupts; atomic_t read_processed; @@ -331,16 +327,6 @@ struct server_adapter { atomic_t errors; }; -/* - * We use the following struct, list, and lock to keep track of the scsi - * devices and their mapping to targets in the vscsis adapters. - */ -struct scsi_dev_node { - struct list_head node; - struct scsi_device *sdev; - struct vdev *vdev; -}; - /* The state of a request */ enum ibmvscsis_iue_state { FREE_IU, @@ -349,8 +335,6 @@ enum ibmvscsis_iue_state { RETRY_SPLIT_BUF, }; -static LIST_HEAD(scsi_dev_list); -static spinlock_t sdev_list_lock = SPIN_LOCK_UNLOCKED; /* ============================================================== * Utility Routines @@ -386,18 +370,18 @@ static u8 getlink(struct iu_entry *iue) static int data_out_desc_size(struct srp_cmd *cmd) { - switch (cmd->data_out_format) { - case SRP_NO_BUFFER: + switch (cmd->buf_fmt >> 4) { + case SRP_NO_DATA_DESC: return 0; - case SRP_DIRECT_BUFFER: - return sizeof(struct memory_descriptor); - case SRP_INDIRECT_BUFFER: - return sizeof(struct indirect_descriptor) + - ((cmd->data_out_count - - 1) * sizeof(struct memory_descriptor)); + case SRP_DATA_DESC_DIRECT: + return sizeof(struct srp_direct_buf); + case SRP_DATA_DESC_INDIRECT: + return sizeof(struct srp_indirect_buf) + + ((cmd->data_out_desc_cnt - + 1) * sizeof(struct srp_direct_buf)); default: err("client error. Invalid data_out_format %d\n", - cmd->data_out_format); + cmd->buf_fmt >> 4); return 0; } } @@ -407,29 +391,29 @@ static int data_out_desc_size(struct srp_cmd *cmd) */ static int vscsis_data_length(struct srp_cmd *cmd, int out) { - struct memory_descriptor *md; - struct indirect_descriptor *id; - int offset = cmd->additional_cdb_len * 4; + struct srp_direct_buf *md; + struct srp_indirect_buf *id; + int offset = cmd->add_cdb_len * 4; int switch_value; if (out) - switch_value = cmd->data_out_format; + switch_value = cmd->buf_fmt >> 4; else { - switch_value = cmd->data_in_format; + switch_value = cmd->buf_fmt & ((1U << 4) - 1); offset += data_out_desc_size(cmd); } switch (switch_value) { - case SRP_NO_BUFFER: + case SRP_NO_DATA_DESC: return 0; - case SRP_DIRECT_BUFFER: - md = (struct memory_descriptor *)(cmd->additional_data + + case SRP_DATA_DESC_DIRECT: + md = (struct srp_direct_buf *)(cmd->add_data + offset); - return md->length; - case SRP_INDIRECT_BUFFER: - id = (struct indirect_descriptor *)(cmd->additional_data + + return md->len; + case SRP_DATA_DESC_INDIRECT: + id = (struct srp_indirect_buf *)(cmd->add_data + offset); - return id->total_length; + return id->len; default: err("invalid data format\n"); return 0; @@ -442,21 +426,21 @@ static int vscsis_data_length(struct srp_cmd *cmd, int out) */ static void make_direct_buffer(struct srp_cmd *cmd) { - struct indirect_descriptor *id = (struct indirect_descriptor *) - (cmd->additional_data); - struct memory_descriptor *md = (struct memory_descriptor *) - (cmd->additional_data); - unsigned int length = id->list[0].length; - unsigned int address = id->list[0].virtual_address; + struct srp_indirect_buf *id = (struct srp_indirect_buf *) + (cmd->add_data); + struct srp_direct_buf *md = (struct srp_direct_buf *) + (cmd->add_data); + unsigned int length = id->desc_list[0].len; + unsigned int address = id->desc_list[0].va; - if (cmd->data_out_format == SRP_INDIRECT_BUFFER) - cmd->data_out_format = SRP_DIRECT_BUFFER; - if (cmd->data_in_format == SRP_INDIRECT_BUFFER) - cmd->data_in_format = SRP_DIRECT_BUFFER; + if (cmd->buf_fmt >> 4 == SRP_DATA_DESC_INDIRECT) + cmd->buf_fmt = SRP_DATA_DESC_DIRECT << 4; + if ((cmd->buf_fmt & ((1U << 4) - 1)) == SRP_DATA_DESC_INDIRECT) + cmd->buf_fmt = SRP_DATA_DESC_DIRECT; - md->length = length; - md->virtual_address = address; - cmd->data_in_count = cmd->data_out_count = 0; + md->len = length; + md->va = address; + cmd->data_in_desc_cnt = cmd->data_out_desc_cnt = 0; } /* @@ -478,7 +462,7 @@ static struct vdev *find_vscsis_vdev(struct iu_entry *iue) return NULL; /* Only from SRP CMD */ - if (iue->iu->srp.generic.type != SRP_CMD_TYPE) + if (iue->iu->srp.generic.type != SRP_CMD) return NULL; /* if not a recognized LUN format, return NULL */ @@ -504,15 +488,36 @@ out_unlock: return vd; } +static long h_copy_rdma(u64 length, unsigned long siobn, dma_addr_t saddr, + unsigned long diobn, dma_addr_t daddr) +{ + u64 bytes_copied = 0; + u64 rc; + + while (bytes_copied < length) { + u64 bytes_to_copy = (length - bytes_copied) > MAX_H_COPY_RDMA ? + MAX_H_COPY_RDMA : (length - bytes_copied); + rc = plpar_hcall_norets(H_COPY_RDMA, bytes_to_copy, siobn, + saddr, diobn, daddr); + if (rc != H_Success) + return rc; + + bytes_copied += bytes_to_copy; + saddr += bytes_to_copy; + daddr += bytes_to_copy; + } + return H_Success; +} + /* ============================================================== * Information Unit (IU) Pool Routines * ============================================================== */ /* - * We keep a pool of IUs, this routine builds the pool. The pool is - * per-adapter. The size of the pool is negotiated as part of the SRP + * We keep a pool of IUs, this routine builds the pool. The pool is + * per-adapter. The size of the pool is negotiated as part of the SRP * login, where we negotiate the number of requests (IUs) the client - * can send us. This routine is not synchronized, since it happens + * can send us. This routine is not synchronized, since it happens * only at probe time. */ static int initialize_iu_pool(struct server_adapter *adapter, int size) @@ -532,9 +537,9 @@ static int initialize_iu_pool(struct server_adapter *adapter, int size) memset(pool->list, 0, pool->size * sizeof(*pool->list)); pool->iu_storage = - dma_alloc_coherent(adapter->dev, - pool->size * sizeof(*pool->iu_storage), - &pool->iu_token, GFP_KERNEL); + dma_alloc_coherent(adapter->dev, + pool->size * sizeof(*pool->iu_storage), + &pool->iu_token, GFP_KERNEL); if (!pool->iu_storage) { err("Error: Cannot allocate memory for IU pool\n"); kfree(pool->list); @@ -544,7 +549,7 @@ static int initialize_iu_pool(struct server_adapter *adapter, int size) for (i = 0; i < pool->size; ++i) { pool->list[i].iu = pool->iu_storage + i; pool->list[i].iu_token = - pool->iu_token + sizeof(*pool->iu_storage) * i; + pool->iu_token + sizeof(*pool->iu_storage) * i; pool->list[i].adapter = adapter; list_add_tail(&pool->list[i].next, &pool->iu_entries); } @@ -572,8 +577,8 @@ static void release_iu_pool(struct server_adapter *adapter) } /* - * Get an IU from the pool. Return NULL if the pool is empty. This - * routine is syncronized by the adapter lock. The routine sets all the + * Get an IU from the pool. Return NULL if the pool is empty. This + * routine is syncronized by the adapter lock. The routine sets all the * important fields to 0 */ static struct iu_entry *get_iu(struct server_adapter *adapter) @@ -602,7 +607,7 @@ static struct iu_entry *get_iu(struct server_adapter *adapter) } /* - * Return an IU to the pool. This routine is synchronized by the + * Return an IU to the pool. This routine is synchronized by the * adapter lock */ static void free_iu(struct iu_entry *iue) @@ -635,17 +640,19 @@ static int split_iu(struct iu_entry* iue) struct iu_entry *child_iue; struct srp_cmd *child_cmd; struct srp_cmd *cmd = &iue->iu->srp.cmd; - struct indirect_descriptor *child_id; - struct indirect_descriptor *id = (struct indirect_descriptor *) - (cmd->additional_data); + struct srp_indirect_buf *child_id; + struct srp_indirect_buf *id = (struct srp_indirect_buf *) + (cmd->add_data); + u8 out_fmt = cmd->buf_fmt >> 4; + u8 in_fmt = cmd->buf_fmt & ((1U << 4) - 1); - if (cmd->data_out_format && cmd->data_in_format) { + if (out_fmt && in_fmt) { err("Don't support bidirectional buffers yet\n"); return -EPERM; } dbg("splitting %p len %lx incount %x outcount %x lba %lx\n", iue, - iue->req.len, cmd->data_in_count, cmd->data_out_count, + iue->req.len, cmd->data_in_desc_cnt, cmd->data_out_desc_cnt, iue->req.lba); if (iue->req.len < PAGE_SIZE) { @@ -654,14 +661,14 @@ static int split_iu(struct iu_entry* iue) } child1 = kmalloc(sizeof(struct iu_entry) + sizeof(union viosrp_iu), - GFP_KERNEL); + GFP_ATOMIC); if (child1 == NULL) return -ENOMEM; child2 = kmalloc(sizeof(struct iu_entry) + sizeof(union viosrp_iu), - GFP_KERNEL); + GFP_ATOMIC); if (child2 == NULL) { - free_iu(child1); + kfree(child1); return -ENOMEM; } @@ -670,69 +677,70 @@ static int split_iu(struct iu_entry* iue) child1->adapter = child2->adapter = iue->adapter; memset(&child1->req, 0, sizeof(child1->req)); memset(&child2->req, 0, sizeof(child2->req)); - memset(&child1->iu->srp.cmd, 0, sizeof(struct srp_cmd)); - memset(&child2->iu->srp.cmd, 0, sizeof(struct srp_cmd)); + memset(&child1->iu->srp.cmd, 0, sizeof(struct srp_cmd) + + sizeof(struct srp_indirect_buf)); + memset(&child2->iu->srp.cmd, 0, sizeof(struct srp_cmd) + + sizeof(struct srp_indirect_buf)); __set_bit(V_IN_USE, &child1->req.flags); __set_bit(V_IN_USE, &child2->req.flags); /* Split a direct buffer */ - if (cmd->data_out_format == SRP_DIRECT_BUFFER || - cmd->data_in_format == SRP_DIRECT_BUFFER) { - struct memory_descriptor *md = (struct memory_descriptor *) - (cmd->additional_data); - struct memory_descriptor *ch1_md = (struct memory_descriptor *) - (child1->iu->srp.cmd.additional_data); - struct memory_descriptor *ch2_md = (struct memory_descriptor *) - (child2->iu->srp.cmd.additional_data); + if (out_fmt == SRP_DATA_DESC_DIRECT || + in_fmt == SRP_DATA_DESC_DIRECT) { + struct srp_direct_buf *md = (struct srp_direct_buf *) + (cmd->add_data); + struct srp_direct_buf *ch1_md = (struct srp_direct_buf *) + (child1->iu->srp.cmd.add_data); + struct srp_direct_buf *ch2_md = (struct srp_direct_buf *) + (child2->iu->srp.cmd.add_data); - int npages = (md->length - 1) / PAGE_SIZE + 1; - ch1_md->length = ((npages + 1) / 2) * PAGE_SIZE; - ch2_md->length = md->length - ch1_md->length; - ch1_md->virtual_address = md->virtual_address; - ch2_md->virtual_address = md->virtual_address + ch1_md->length; - child1->req.len = ch1_md->length; - child2->req.len = ch2_md->length; + int npages = (md->len - 1) / PAGE_SIZE + 1; + ch1_md->len = ((npages + 1) / 2) * PAGE_SIZE; + ch2_md->len = md->len - ch1_md->len; + ch1_md->va = md->va; + ch2_md->va = md->va + ch1_md->len; + child1->req.len = ch1_md->len; + child2->req.len = ch2_md->len; goto splitted; } child_iue = child1; child_cmd = &child1->iu->srp.cmd; - child_id = (struct indirect_descriptor *) (child_cmd->additional_data); - count = iue->req.rw ? cmd->data_out_count : cmd->data_in_count; + child_id = (struct srp_indirect_buf *) (child_cmd->add_data); + count = iue->req.rw ? cmd->data_out_desc_cnt : cmd->data_in_desc_cnt; for (i = 0; i < count ; i++) { - child_id->list[i - child1i].length = id->list[i].length; - child_id->list[i - child1i].virtual_address = - id->list[i].virtual_address; + child_id->desc_list[i - child1i].len = id->desc_list[i].len; + child_id->desc_list[i - child1i].va = + id->desc_list[i].va; if (iue->req.rw) - child_cmd->data_out_count++; + child_cmd->data_out_desc_cnt++; else - child_cmd->data_in_count++; + child_cmd->data_in_desc_cnt++; - child_id->total_length += id->list[i].length; - length += id->list[i].length; - child_iue->req.len += id->list[i].length; + child_id->len += id->desc_list[i].len; + child_id->table_desc.len += sizeof(struct srp_direct_buf); + length += id->desc_list[i].len; + child_iue->req.len += id->desc_list[i].len; if (!child1i && (length >= iue->req.len / 2 || - i >= count - 2)) { + i >= count - 2)) { child_iue = child2; child_cmd = &child2->iu->srp.cmd; - child_id = (struct indirect_descriptor *) - (child_cmd->additional_data); + child_id = (struct srp_indirect_buf *) + (child_cmd->add_data); child1i = i + 1; } } splitted: - child1->iu->srp.cmd.data_out_format = iue->iu->srp.cmd.data_out_format; - child1->iu->srp.cmd.data_in_format = iue->iu->srp.cmd.data_in_format; - child2->iu->srp.cmd.data_out_format = iue->iu->srp.cmd.data_out_format; - child2->iu->srp.cmd.data_in_format = iue->iu->srp.cmd.data_in_format; + child1->iu->srp.cmd.buf_fmt = iue->iu->srp.cmd.buf_fmt; + child2->iu->srp.cmd.buf_fmt = iue->iu->srp.cmd.buf_fmt; - if (child1->iu->srp.cmd.data_out_count == 1 || - child1->iu->srp.cmd.data_in_count == 1) + if (child1->iu->srp.cmd.data_out_desc_cnt == 1 || + child1->iu->srp.cmd.data_in_desc_cnt == 1) make_direct_buffer(&child1->iu->srp.cmd); - if (child2->iu->srp.cmd.data_out_count == 1 || - child2->iu->srp.cmd.data_in_count == 1) + if (child2->iu->srp.cmd.data_out_desc_cnt == 1 || + child2->iu->srp.cmd.data_in_desc_cnt == 1) make_direct_buffer(&child2->iu->srp.cmd); child1->req.rw = child2->req.rw = iue->req.rw; @@ -750,16 +758,16 @@ splitted: } /* ============================================================== - * Data buffer cache routines. Note that we don't NEED a + * Data buffer cache routines. Note that we don't NEED a * data cache, but this eliminates mapping and unmapping DMA * addresses for data buffers on every request, which can be quite - * expensive on a PPC64 system. santi hates these routines (that + * expensive on a PPC64 system. santi hates these routines (that * just do first-fit allocation) but they are Good Enough (tm) until * he writes something more elegant. * ============================================================== */ /* - * Get some data buffers to start. This doesn't lock the adapter structure! + * Get some data buffers to start. This doesn't lock the adapter structure! */ static void init_data_buffer(struct server_adapter *adapter) { @@ -768,11 +776,11 @@ static void init_data_buffer(struct server_adapter *adapter) for (i = 0; i < DMA_BUFFER_INIT_COUNT; i++) { if (adapter->dma_buffer[i].addr == NULL) { adapter->dma_buffer[i].addr = - dma_alloc_coherent(adapter->dev, - DMA_BUFFER_INIT_LEN, - &adapter->dma_buffer[i]. - token, - GFP_KERNEL); + dma_alloc_coherent(adapter->dev, + DMA_BUFFER_INIT_LEN, + &adapter->dma_buffer[i]. + token, + GFP_KERNEL); adapter->dma_buffer[i].len = DMA_BUFFER_INIT_LEN; atomic_inc(&adapter->buffers_allocated); } @@ -780,10 +788,10 @@ static void init_data_buffer(struct server_adapter *adapter) } /* - * Get a memory buffer that includes a mapped DMA address. Just use first-fit + * Get a memory buffer that includes a mapped DMA address. Just use first-fit */ static void get_data_buffer(char **buffer, dma_addr_t * data_token, size_t len, - struct server_adapter *adapter) + struct server_adapter *adapter) { int i; @@ -797,7 +805,7 @@ static void get_data_buffer(char **buffer, dma_addr_t * data_token, size_t len, } } - /* Couldn't get a buffer! Try and get a new one */ + /* Couldn't get a buffer! Try and get a new one */ *buffer = dma_alloc_coherent(adapter->dev, len, data_token, GFP_KERNEL); atomic_inc(&adapter->buffers_allocated); return; @@ -807,7 +815,7 @@ static void get_data_buffer(char **buffer, dma_addr_t * data_token, size_t len, * Free a memory buffer that includes a mapped DMA address. */ static void free_data_buffer(char *buffer, dma_addr_t data_token, size_t len, - struct server_adapter *adapter) + struct server_adapter *adapter) { int i; @@ -859,7 +867,7 @@ static void free_data_buffer(char *buffer, dma_addr_t data_token, size_t len, } } - /* No space to cache this. Give it back to the kernel */ + /* No space to cache this. Give it back to the kernel */ dma_free_coherent(adapter->dev, len, buffer, data_token); atomic_dec(&adapter->buffers_allocated); } @@ -943,7 +951,7 @@ static int send_iu(struct iu_entry *iue, u64 length, u8 format) crq.cooked.IU_data_ptr = iue->iu->srp.generic.tag; if (rc == 0) - crq.cooked.status = 0x99; /* Just needs to be non-zero */ + crq.cooked.status = 0x99; /* Just needs to be non-zero */ else crq.cooked.status = 0x00; @@ -964,24 +972,24 @@ static int send_iu(struct iu_entry *iue, u64 length, u8 format) * Returns amount of data sent, or negative value on error */ static long send_md_data(dma_addr_t stoken, int len, - struct memory_descriptor *md, - struct server_adapter *adapter) + struct srp_direct_buf *md, + struct server_adapter *adapter) { int tosend; long rc; - if (len < md->length) + if (len < md->len) tosend = len; else - tosend = md->length; + tosend = md->len; rc = h_copy_rdma(tosend, adapter->liobn, - stoken, adapter->riobn, md->virtual_address); + stoken, adapter->riobn, md->va); if (rc != H_Success) { err("send_md_data: Error %ld transferring data to client\n", - rc); + rc); return -EIO; } @@ -991,21 +999,21 @@ static long send_md_data(dma_addr_t stoken, int len, /* Send data to a list of memory descriptors */ static int send_md_list(int num_entries, int tosendlen, - dma_addr_t stoken, - struct memory_descriptor *md, - struct iu_entry *iue) + dma_addr_t stoken, + struct srp_direct_buf *md, + struct iu_entry *iue) { int i, thislen, bytes; int sentlen = 0; for (i = 0; ((i < num_entries) && (tosendlen)); i++) { - if (tosendlen > md[i].length) - thislen = md[i].length; + if (tosendlen > md[i].len) + thislen = md[i].len; else thislen = tosendlen; bytes = send_md_data(stoken + sentlen, thislen, - md + i, iue->adapter); + md + i, iue->adapter); if (bytes < 0) return bytes; @@ -1026,20 +1034,20 @@ static int send_md_list(int num_entries, int tosendlen, static long send_cmd_data(dma_addr_t stoken, int len, struct iu_entry *iue) { struct srp_cmd *cmd = &iue->iu->srp.cmd; - struct memory_descriptor *md = NULL, *ext_list = NULL; - struct indirect_descriptor *id = NULL; + struct srp_direct_buf *md = NULL, *ext_list = NULL; + struct srp_indirect_buf *id = NULL; dma_addr_t data_token; int offset = 0; int sentlen = 0; int num_md, rc; - offset = cmd->additional_cdb_len * 4 + data_out_desc_size(cmd); + offset = cmd->add_cdb_len * 4 + data_out_desc_size(cmd); - switch (cmd->data_in_format) { - case SRP_NO_BUFFER: + switch (cmd->buf_fmt & ((1U << 4) - 1)) { + case SRP_NO_DATA_DESC: return 0; - case SRP_DIRECT_BUFFER: - md = (struct memory_descriptor *)(cmd->additional_data + + case SRP_DATA_DESC_DIRECT: + md = (struct srp_direct_buf *)(cmd->add_data + offset); sentlen = send_md_data(stoken, len, md, iue->adapter); len -= sentlen; @@ -1050,21 +1058,21 @@ static long send_cmd_data(dma_addr_t stoken, int len, struct iu_entry *iue) return sentlen; } - if (cmd->data_in_format != SRP_INDIRECT_BUFFER) { + if ((cmd->buf_fmt & ((1U << 4) - 1)) != SRP_DATA_DESC_INDIRECT) { err("client error Invalid data_in_format %d\n", - cmd->data_in_format); + cmd->buf_fmt & ((1U << 4) - 1)); return 0; } - id = (struct indirect_descriptor *)(cmd->additional_data + offset); - num_md = id->head.length / sizeof(struct memory_descriptor); + id = (struct srp_indirect_buf *)(cmd->add_data + offset); + num_md = id->table_desc.len / sizeof(struct srp_direct_buf); - if (num_md == cmd->data_in_count) - md = &id->list[0]; + if (num_md == cmd->data_in_desc_cnt) + md = &id->desc_list[0]; else { ext_list = dma_alloc_coherent(iue->adapter->dev, - id->head.length, + id->table_desc.len, &data_token, GFP_KERNEL); if (!ext_list) { @@ -1073,17 +1081,17 @@ static long send_cmd_data(dma_addr_t stoken, int len, struct iu_entry *iue) } /* get indirect memory descriptor table from initiator */ - rc = h_copy_rdma(id->head.length, - iue->adapter->riobn, - id->head.virtual_address, - iue->adapter->liobn, - data_token); + rc = h_copy_rdma(id->table_desc.len, + iue->adapter->riobn, + id->table_desc.va, + iue->adapter->liobn, + data_token); if (rc != H_Success) { err("Error copying indirect table rc %d\n", rc); return 0; } - md = (struct memory_descriptor *)ext_list; + md = (struct srp_direct_buf *)ext_list; } /* Work through the memory descriptor list */ @@ -1100,7 +1108,7 @@ static long send_cmd_data(dma_addr_t stoken, int len, struct iu_entry *iue) if (ext_list) dma_free_coherent(iue->adapter->dev, - id->head.length, ext_list, data_token); + id->table_desc.len, ext_list, data_token); return sentlen; } @@ -1110,24 +1118,24 @@ static long send_cmd_data(dma_addr_t stoken, int len, struct iu_entry *iue) * Returns amount of data received, or negative value on error */ static long get_md_data(dma_addr_t ttoken, int len, - struct memory_descriptor *md, - struct server_adapter *adapter) + struct srp_direct_buf *md, + struct server_adapter *adapter) { int toget; long rc; - if (len < md->length) + if (len < md->len) toget = len; else - toget = md->length; + toget = md->len; rc = h_copy_rdma(toget, adapter->riobn, - md->virtual_address, adapter->liobn, ttoken); + md->va, adapter->liobn, ttoken); if (rc != H_Success) { err("get_md_data: Error %ld transferring data from client\n", - rc); + rc); return -EIO; } @@ -1135,16 +1143,16 @@ static long get_md_data(dma_addr_t ttoken, int len, } static int get_md_list(int num_entries, int togetlen, - dma_addr_t stoken, - struct memory_descriptor *md, - struct iu_entry *iue) + dma_addr_t stoken, + struct srp_direct_buf *md, + struct iu_entry *iue) { int i, thislen, bytes; int gotlen = 0; for (i = 0; ((i < num_entries) && (togetlen)); i++) { - if (togetlen > md[i].length) - thislen = md[i].length; + if (togetlen > md[i].len) + thislen = md[i].len; else thislen = togetlen; @@ -1155,7 +1163,7 @@ static int get_md_list(int num_entries, int togetlen, if (bytes != thislen) err("Partial data got from client (%d/%d)\n", - bytes, thislen); + bytes, thislen); gotlen += bytes; togetlen -= bytes; @@ -1171,50 +1179,50 @@ static int get_md_list(int num_entries, int togetlen, static long get_cmd_data(dma_addr_t stoken, int len, struct iu_entry *iue) { struct srp_cmd *cmd = &iue->iu->srp.cmd; - struct memory_descriptor *md, *ext_list; - struct indirect_descriptor *id; + struct srp_direct_buf *md, *ext_list; + struct srp_indirect_buf *id; dma_addr_t data_token; int offset = 0; int total_length = 0; int num_md, rc; int gotlen = 0; - offset = cmd->additional_cdb_len * 4; + offset = cmd->add_cdb_len * 4; - switch (cmd->data_out_format) { - case SRP_NO_BUFFER: + switch (cmd->buf_fmt >> 4) { + case SRP_NO_DATA_DESC: return 0; break; - case SRP_DIRECT_BUFFER: - md = (struct memory_descriptor *)(cmd->additional_data + + case SRP_DATA_DESC_DIRECT: + md = (struct srp_direct_buf *)(cmd->add_data + offset); return get_md_data(stoken, len, md, iue->adapter); break; } - if (cmd->data_out_format != SRP_INDIRECT_BUFFER) { + if (cmd->buf_fmt >> 4 != SRP_DATA_DESC_INDIRECT) { err("client error: Invalid data_out_format %d\n", - cmd->data_out_format); + cmd->buf_fmt >> 4); return 0; } - id = (struct indirect_descriptor *)(cmd->additional_data + offset); + id = (struct srp_indirect_buf *)(cmd->add_data + offset); - total_length = id->total_length; + total_length = id->len; - num_md = id->head.length / sizeof(struct memory_descriptor); + num_md = id->table_desc.len / sizeof(struct srp_direct_buf); - if (num_md == cmd->data_out_count) { + if (num_md == cmd->data_out_desc_cnt) { /* Work through the partial memory descriptor list */ gotlen = get_md_list(num_md, len, - stoken, &id->list[0], iue); + stoken, &id->desc_list[0], iue); return gotlen; } /* get indirect table */ ext_list = dma_alloc_coherent(iue->adapter->dev, - id->head.length, + id->table_desc.len, &data_token, GFP_KERNEL); if (!ext_list) { @@ -1223,23 +1231,23 @@ static long get_cmd_data(dma_addr_t stoken, int len, struct iu_entry *iue) } /* get indirect memory descriptor table */ - rc = h_copy_rdma(id->head.length, - iue->adapter->riobn, - id->head.virtual_address, - iue->adapter->liobn, - data_token); + rc = h_copy_rdma(id->table_desc.len, + iue->adapter->riobn, + id->table_desc.va, + iue->adapter->liobn, + data_token); if (rc != H_Success) { err("Error copying indirect table rc %d\n", rc); dma_free_coherent(iue->adapter->dev, - id->head.length, + id->table_desc.len, ext_list, data_token); return 0; } gotlen = get_md_list(num_md, len, - stoken, ext_list, iue); + stoken, ext_list, iue); dma_free_coherent(iue->adapter->dev, - id->head.length, + id->table_desc.len, ext_list, data_token); return gotlen; @@ -1249,10 +1257,10 @@ static long get_cmd_data(dma_addr_t stoken, int len, struct iu_entry *iue) * Send an SRP response that includes sense data */ static long send_rsp(struct iu_entry *iue, - unsigned char status, - unsigned char asc) + unsigned char status, + unsigned char asc) { - u8 *sense = iue->iu->srp.rsp.sense_and_response_data; + u8 *sense = iue->iu->srp.rsp.data; u64 tag = iue->iu->srp.generic.tag; union viosrp_iu *iu = iue->iu; unsigned long flags; @@ -1291,26 +1299,25 @@ static long send_rsp(struct iu_entry *iue, status = 0x10; memset(iu, 0, sizeof(struct srp_rsp)); - iu->srp.rsp.type = SRP_RSP_TYPE; + iu->srp.rsp.opcode = SRP_RSP; spin_lock_irqsave(&iue->adapter->lock, flags); - iu->srp.rsp.request_limit_delta = 1 + iue->adapter->next_rsp_delta; + iu->srp.rsp.req_lim_delta = 1 + iue->adapter->next_rsp_delta; iue->adapter->next_rsp_delta = 0; spin_unlock_irqrestore(&iue->adapter->lock, flags); iu->srp.rsp.tag = tag; - iu->srp.rsp.diover = test_bit(V_DIOVER, &iue->req.flags) ? 1 : 0; + iu->srp.rsp.flags |= + test_bit(V_DIOVER, &iue->req.flags) ? SRP_RSP_FLAG_DIOVER : 0; - iu->srp.rsp.data_in_residual_count = iue->req.data_in_residual_count; - iu->srp.rsp.data_out_residual_count = iue->req.data_out_residual_count; + iu->srp.rsp.data_in_res_cnt = iue->req.data_in_residual_count; + iu->srp.rsp.data_out_res_cnt = iue->req.data_out_residual_count; - iu->srp.rsp.rspvalid = 0; - - iu->srp.rsp.response_data_list_length = 0; + iu->srp.rsp.resp_data_len = 0; if (status && !iue->req.sense) { iu->srp.rsp.status = SAM_STAT_CHECK_CONDITION; - iu->srp.rsp.snsvalid = 1; - iu->srp.rsp.sense_data_list_length = 18; + iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; + iu->srp.rsp.sense_data_len = 18; /* Valid bit and 'current errors' */ sense[0] = (0x1 << 7 | 0x70); @@ -1319,21 +1326,22 @@ static long send_rsp(struct iu_entry *iue, sense[2] = status; /* Additional sense length */ - sense[7] = 0xa; /* 10 bytes */ + sense[7] = 0xa; /* 10 bytes */ /* Additional sense code */ sense[12] = asc; } else { if (iue->req.sense) { - iu->srp.rsp.snsvalid = 1; - iu->srp.rsp.sense_data_list_length = - SCSI_SENSE_BUFFERSIZE; + iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; + iu->srp.rsp.sense_data_len = SCSI_SENSE_BUFFERSIZE; memcpy(sense, iue->req.sense, SCSI_SENSE_BUFFERSIZE); - } + } else + iu->srp.rsp.sense_data_len = 0; iu->srp.rsp.status = status; } - send_iu(iue, sizeof(iu->srp.rsp), VIOSRP_SRP_FORMAT); + send_iu(iue, sizeof(iu->srp.rsp) + iu->srp.rsp.sense_data_len, + VIOSRP_SRP_FORMAT); return 0; } @@ -1380,8 +1388,7 @@ static void finish_iue(struct iu_entry *iue) } else send_rsp(iue, NO_SENSE, 0x00); -out: - free_data_buffer(iue->req.data_buffer, +out: free_data_buffer(iue->req.data_buffer, iue->req.data_token, iue->req.data_len, adapter); spin_lock_irqsave(&adapter->lock, flags); @@ -1390,11 +1397,11 @@ out: } /* - * the routine that gets called on end_io of our bios. We basically + * the routine that gets called on end_io of our bios. We basically * schedule the processing to be done in our task, since we don't want * do things like RDMA in someone else's interrupt handler * - * Each iu request may result in multiple bio requests. only proceed + * Each iu request may result in multiple bio requests. only proceed * when all the bio requests have done. */ static int ibmvscsis_end_io(struct bio *bio, unsigned int nbytes, int error) @@ -1426,7 +1433,7 @@ static int ibmvscsis_end_io(struct bio *bio, unsigned int nbytes, int error) } /* - * Process BH buffer completions. When the end_io routine gets called + * Process BH buffer completions. When the end_io routine gets called * we queue the bio on an internal queue and start a task to process them */ static void endio_task(unsigned long data) @@ -1501,25 +1508,25 @@ static int process_inquiry(struct iu_entry *iue) /* Standard inquiry page */ if ((iue->iu->srp.cmd.cdb[1] == 0x00) && (iue->iu->srp.cmd.cdb[2] == 0x00)) { - dbg(" inquiry returning device\n"); + dbg(" inquiry returning device\n"); id->qual_type = iue->req.vd->b.scsi_type; id->rmb_reserve = - iue->req.vd->b.removable ? 0x80 : 0x00; - id->version = 0x84; /* ISO/IE */ + iue->req.vd->b.removable ? 0x80 : 0x00; + id->version = 0x84; /* ISO/IE */ id->aerc_naca_hisup_format = 0x22;/* naca & fmt 0x02 */ id->addl_len = sizeof(*id) - 4; id->bque_encserv_vs_multip_mchngr_reserved = 0x00; id->reladr_reserved_linked_cmdqueue_vs = 0x02;/*CMDQ*/ - memcpy(id->vendor, "IBM ", 8); - /* Don't even ask about the next bit. AIX uses + memcpy(id->vendor, "IBM ", 8); + /* Don't even ask about the next bit. AIX uses * hardcoded device naming to recognize device types - * and their client won't work unless we use VOPTA and + * and their client won't work unless we use VOPTA and * VDASD. */ if (id->qual_type == TYPE_ROM) - memcpy(id->product, "VOPTA blkdev ", 16); + memcpy(id->product, "VOPTA blkdev ", 16); else - memcpy(id->product, "VDASD blkdev ", 16); + memcpy(id->product, "VDASD blkdev ", 16); memcpy(id->revision, "0001", 4); snprintf(id->unique,sizeof(id->unique), "IBM-VSCSI-%s-P%d-%x-%d-%d-%d\n", @@ -1563,8 +1570,8 @@ static int process_inquiry(struct iu_entry *iue) return FREE_IU; } } else { - dbg(" inquiry returning no device\n"); - id->qual_type = 0x7F; /* Not supported, no device */ + dbg(" inquiry returning no device\n"); + id->qual_type = 0x7F; /* Not supported, no device */ } if (test_bit(V_ABORTED, &iue->req.flags)) { @@ -1576,7 +1583,7 @@ static int process_inquiry(struct iu_entry *iue) return FREE_IU; } - bytes = send_cmd_data(data_token, sizeof(*id), iue); + bytes = send_cmd_data(data_token, iue->iu->srp.cmd.cdb[4], iue); dma_free_coherent(iue->adapter->dev, sizeof(*id), id, data_token); @@ -1589,10 +1596,10 @@ static int process_inquiry(struct iu_entry *iue) } /* - * Handle an I/O. Called by WRITE6, WRITE10, etc + * Handle an I/O. Called by WRITE6, WRITE10, etc */ static int process_rw(char *cmd, int rw, struct iu_entry *iue, long lba, - long len) + long len) { char *buffer; struct bio *bio; @@ -1615,7 +1622,7 @@ static int process_rw(char *cmd, int rw, struct iu_entry *iue, long lba, if (len == 0) { warn("Zero length I/O\n"); - send_rsp(iue, ILLEGAL_REQUEST, 0x20); + send_rsp(iue, ILLEGAL_REQUEST, 0x24); return FREE_IU; } @@ -1662,7 +1669,7 @@ static int process_rw(char *cmd, int rw, struct iu_entry *iue, long lba, if (bytes != len) { err("Error transferring data\n"); free_data_buffer(buffer, iue->req.data_token, len, - iue->adapter); + iue->adapter); send_rsp(iue, HARDWARE_ERROR, 0x00); return FREE_IU; } @@ -1672,10 +1679,11 @@ static int process_rw(char *cmd, int rw, struct iu_entry *iue, long lba, bio = bio_alloc(GFP_KERNEL, num_biovec); if (!bio) { - err("Not able to allocate a bio, retrying later\n"); + if (printk_ratelimit()) + err("Not able to allocate a bio, retrying later %x %p \n",num_biovec,__builtin_return_address(0)); free_data_buffer(buffer, iue->req.data_token, len, - iue->adapter); + iue->adapter); return RETRY; } @@ -1684,7 +1692,7 @@ static int process_rw(char *cmd, int rw, struct iu_entry *iue, long lba, spin_lock_irqsave(&iue->adapter->lock, flags); iue->adapter->next_rsp_delta++; free_data_buffer(buffer, iue->req.data_token, len, - iue->adapter); + iue->adapter); spin_unlock_irqrestore(&iue->adapter->lock, flags); bio_put(bio); return FREE_IU; @@ -1717,7 +1725,7 @@ static int process_rw(char *cmd, int rw, struct iu_entry *iue, long lba, bio->bi_io_vec[cur_biovec].bv_page = virt_to_page(buffer); bio->bi_io_vec[cur_biovec].bv_len = thislen; bio->bi_io_vec[cur_biovec].bv_offset = - (unsigned long)buffer & (PAGE_SIZE-1); + (unsigned long)buffer & (PAGE_SIZE-1); bio->bi_vcnt++; len -= thislen; @@ -1751,7 +1759,7 @@ static int process_read10(struct iu_entry *iue) { long lba = *((u32 *) (iue->iu->srp.cmd.cdb + 2)); long len = - *((u16 *) (iue->iu->srp.cmd.cdb + 7)) * iue->req.vd->b.sectsize; + *((u16 *) (iue->iu->srp.cmd.cdb + 7)) * iue->req.vd->b.sectsize; return process_rw("Read10", READ, iue, lba, len); } @@ -1760,7 +1768,7 @@ static int process_read12(struct iu_entry *iue) { long lba = *((u32 *) (iue->iu->srp.cmd.cdb + 2)); long len = - *((u32 *) (iue->iu->srp.cmd.cdb + 6)) * iue->req.vd->b.sectsize; + *((u32 *) (iue->iu->srp.cmd.cdb + 6)) * iue->req.vd->b.sectsize; return process_rw("Read12", READ, iue, lba, len); } @@ -1783,7 +1791,7 @@ static int process_write10(struct iu_entry *iue) { long lba = *((u32 *) (iue->iu->srp.cmd.cdb + 2)); long len = - *((u16 *) (iue->iu->srp.cmd.cdb + 7)) * iue->req.vd->b.sectsize; + *((u16 *) (iue->iu->srp.cmd.cdb + 7)) * iue->req.vd->b.sectsize; return process_rw("Write10", WRITE, iue, lba, len); } @@ -1792,7 +1800,7 @@ static int process_write12(struct iu_entry *iue) { long lba = *((u32 *) (iue->iu->srp.cmd.cdb + 2)); long len = - *((u32 *) (iue->iu->srp.cmd.cdb + 6)) * iue->req.vd->b.sectsize; + *((u32 *) (iue->iu->srp.cmd.cdb + 6)) * iue->req.vd->b.sectsize; return process_rw("Write12", WRITE, iue, lba, len); } @@ -1821,7 +1829,7 @@ static int process_read_capacity(struct iu_entry *iue) /* return block size and last valid block */ cap->blocksize = iue->req.vd->b.sectsize; cap->blocks = - iue->req.vd->b.bdev->bd_inode->i_size / cap->blocksize - 1; + iue->req.vd->b.bdev->bd_inode->i_size / cap->blocksize - 1; dbg("capacity %ld bytes, %d blocks, %d blocksize\n", (long)iue->req.vd->b.bdev->bd_inode->i_size, @@ -1851,78 +1859,64 @@ static int process_read_capacity(struct iu_entry *iue) return FREE_IU; } +static void init_blk_desc(struct iu_entry *iue, u8 *mode) +{ + mode[1] = 0x00; /* Default medium */ + if (iue->req.vd->b.ro) + mode[2] = 0x80; /* device specific */ + else + mode[2] = 0x00; /* device specific */ + + /* note the DPOFUA bit is set to zero! */ + mode[3] = 0x08; /* block descriptor length */ + *((u32 *) & mode[4]) = + iue->req.vd->b.bdev->bd_inode->i_size + / iue->req.vd->b.sectsize - 1; + + *((u32 *) & mode[8]) = iue->req.vd->b.sectsize; +} + /* * Process Mode Sense */ static int process_mode_sense(struct iu_entry *iue) { dma_addr_t data_token; - int bytes; + u8 bytes; unsigned long flags; u8 *mode = dma_alloc_coherent(iue->adapter->dev, MODE_SENSE_BUFFER_SIZE, - &data_token, GFP_KERNEL); + &data_token, GFP_KERNEL); if (mode == NULL) { err("Not able to get mode buffer, retrying later\n"); return RETRY; } + memset(mode, 0, MODE_SENSE_BUFFER_SIZE); + /* which page */ switch (iue->iu->srp.cmd.cdb[2]) { case 0: - case 0x3f: - mode[1] = 0x00; /* Default medium */ - if (iue->req.vd->b.ro) - mode[2] = 0x80; /* device specific */ - else - mode[2] = 0x00; /* device specific */ - - /* note the DPOFUA bit is set to zero! */ - mode[3] = 0x08; /* block descriptor length */ - *((u32 *) & mode[4]) = - iue->req.vd->b.bdev->bd_inode->i_size - / iue->req.vd->b.sectsize - 1; - - *((u32 *) & mode[8]) = iue->req.vd->b.sectsize; - bytes = mode[0] = 12; /* length */ + init_blk_desc(iue, mode); + mode[0] = 11; break; - case 0x08: /* Cache page */ - /* length should be 4 */ - if (iue->iu->srp.cmd.cdb[4] != 4 - && iue->iu->srp.cmd.cdb[4] != 0x20) { - send_rsp(iue, ILLEGAL_REQUEST, 0x20); - dma_free_coherent(iue->adapter->dev, - MODE_SENSE_BUFFER_SIZE, - mode, data_token); - return FREE_IU; - } - - mode[1] = 0x00; /* Default medium */ - if (iue->req.vd->b.ro) - mode[2] = 0x80; /* device specific */ - else - mode[2] = 0x00; /* device specific */ - - /* note the DPOFUA bit is set to zero! */ - mode[3] = 0x08; /* block descriptor length */ - *((u32 *) & mode[4]) = - iue->req.vd->b.bdev->bd_inode->i_size - / iue->req.vd->b.sectsize - 1; - *((u32 *) & mode[8]) = iue->req.vd->b.sectsize; + case 0x08: /* Cache page */ + case 0x3f: + init_blk_desc(iue, mode); /* Cache page */ - mode[12] = 0x08; /* page */ - mode[13] = 0x12; /* page length */ - mode[14] = 0x01; /* no cache (0x04 for read/write cache) */ + mode[12] = 0x08; /* page */ + mode[13] = 0x12; /* page length */ + mode[14] = 0x01; /* no cache (0x04 for read/write cache) */ - bytes = mode[0] = 12 + mode[13]; /* length */ + mode[0] = 11 + mode[13]; /* length */ break; default: warn("Request for unknown mode page %d\n", iue->iu->srp.cmd.cdb[2]); - send_rsp(iue, ILLEGAL_REQUEST, 0x20); + send_rsp(iue, ILLEGAL_REQUEST, 0x24); dma_free_coherent(iue->adapter->dev, MODE_SENSE_BUFFER_SIZE, mode, data_token); return FREE_IU; @@ -1937,7 +1931,8 @@ static int process_mode_sense(struct iu_entry *iue) return FREE_IU; } - bytes = send_cmd_data(data_token, bytes, iue); + bytes = mode[0] + 1; + bytes = send_cmd_data(data_token, min(bytes, iue->iu->srp.cmd.cdb[4]), iue); dma_free_coherent(iue->adapter->dev, MODE_SENSE_BUFFER_SIZE, mode, data_token); @@ -1954,7 +1949,7 @@ static int process_reportLUNs(struct iu_entry *iue) { int listsize = vscsis_data_length(&iue->iu->srp.cmd, 0); dma_addr_t data_token; - int index = 2; /* Start after the two entries (length and LUN0) */ + int index = 2; /* Start after the two entries (length and LUN0) */ int bus; int target; int bytes; @@ -2004,15 +1999,15 @@ static int process_reportLUNs(struct iu_entry *iue) (!iue->adapter->vbus[bus]-> vdev[target]->disabled)) { lunlist[index++] = - iue->adapter->vbus[bus]->vdev[target]->lun; - dbg(" lun %16.16lx\n", + iue->adapter->vbus[bus]->vdev[target]->lun; + dbg(" lun %16.16lx\n", iue->adapter->vbus[bus]->vdev[target]->lun); } } } -send_lunlist: + send_lunlist: spin_unlock_irqrestore(&iue->adapter->lock, flags); if (test_bit(V_ABORTED, &iue->req.flags)) { @@ -2055,6 +2050,9 @@ static int try_passthru(struct iu_entry *iue) if (dodlen && didlen) return -EIO; + if (!q->queue_lock) + return -EINVAL; + if (dodlen) rw = WRITE; else @@ -2124,11 +2122,49 @@ static void reset_changed(struct iu_entry *iue) if (iue->req.vd->b.changed) { bd_set_size(iue->req.vd->b.bdev, (loff_t)get_capacity(iue->req.vd->b.bdev->bd_disk) - <<9); + <<9); iue->req.vd->b.changed = 0; } } +static int request_sense(struct iu_entry *iue) +{ + dma_addr_t data_token; + u8 bytes; + unsigned long flags; + + u8 *sense = dma_alloc_coherent(iue->adapter->dev, SCSI_SENSE_BUFFERSIZE, + &data_token, GFP_KERNEL); + + if (sense == NULL) { + err("Not able to get sense buffer, retrying later\n"); + return RETRY; + } + + memset(sense, 0, SCSI_SENSE_BUFFERSIZE); + + sense[0] = 0x70; + sense[7] = 10; + + if (test_bit(V_ABORTED, &iue->req.flags)) { + spin_lock_irqsave(&iue->adapter->lock, flags); + iue->adapter->next_rsp_delta++; + spin_unlock_irqrestore(&iue->adapter->lock, flags); + dma_free_coherent(iue->adapter->dev, + SCSI_SENSE_BUFFERSIZE, sense, data_token); + return FREE_IU; + } + + bytes = send_cmd_data(data_token, + min_t(u8, SCSI_SENSE_BUFFERSIZE, iue->iu->srp.cmd.cdb[4]), iue); + + dma_free_coherent(iue->adapter->dev, SCSI_SENSE_BUFFERSIZE, + sense, data_token); + + send_rsp(iue, NO_SENSE, 0x00); + return FREE_IU; +} + /* * Process an IU when the target is a block device */ @@ -2228,6 +2264,9 @@ static int process_cmd_block(struct iu_entry *iue) case WRITE_12: case WRITE_VERIFY_12: return process_write12(iue); + case REQUEST_SENSE: + if (!bdev_get_queue(iue->req.vd->b.bdev)->queue_lock) + return request_sense(iue); default: dbg("unknown command 0x%2.2x\n`",iu->srp.cmd.cdb[0]); if (try_passthru(iue) == 0) { @@ -2250,152 +2289,7 @@ static int process_cmd_block(struct iu_entry *iue) } } -/* ============================================================== - * SCSI Redirection Routines - * ============================================================== - */ -/* - * Callback when the scsi command issued by process_cmd_scsi() is completed - */ -static void scsi_cmd_done(struct scsi_cmnd *cmd) -{ - struct iu_entry *iue = (struct iu_entry*)cmd->sc_request-> - upper_private_data; - struct server_adapter *adapter = iue->adapter; - unsigned long flags; - int bytes; - dbg("scsi_cmd_done got cmd %p iue %p\n", cmd, iue); - - spin_lock_irqsave(&adapter->lock, flags); - list_del(&iue->next); - spin_unlock_irqrestore(&adapter->lock, flags); - - if (test_bit(V_ABORTED, &iue->req.flags)) { - dbg("scsi_cmd_done: aborted tag %16.16x\n", cmd->tag); - spin_lock_irqsave(&iue->adapter->lock, flags); - iue->adapter->next_rsp_delta++; - spin_unlock_irqrestore(&iue->adapter->lock, flags); - goto out; - } - - if(!test_bit(V_WRITE, &iue->req.flags)) { - bytes = send_cmd_data(iue->req.data_token, - iue->req.data_len, iue); - if(bytes != iue->req.data_len) { - err("Error sending data on response (%ld, sent %d)\n", - iue->req.data_len, bytes); - send_rsp(iue, ABORTED_COMMAND, 0x00); - goto out; - } - } - - if (cmd->result) - iue->req.sense = cmd->sense_buffer; - - send_rsp(iue, cmd->result, 0x00); - -out: - scsi_release_request(iue->req.sreq); - if (iue->req.data_len) { - free_data_buffer(iue->req.data_buffer, iue->req.data_token, - iue->req.data_len, adapter); - } - spin_lock_irqsave(&adapter->lock, flags); - free_iu(iue); - spin_unlock_irqrestore(&adapter->lock, flags); -} - -/* - * Process an IU when the target is a scsi device - */ -static int process_cmd_scsi(struct iu_entry *iue) -{ - union viosrp_iu *iu = iue->iu; - struct scsi_request *req; - char *buffer = NULL; - int len = 0; - - dbg("%x %x %16.16lx[%d:%d:%d][%s] link %d iue %p\n", - iu->srp.cmd.cdb[0], - iu->srp.cmd.cdb[1], - iue->iu->srp.cmd.lun, - GETBUS(iue->iu->srp.cmd.lun), - GETTARGET(iue->iu->srp.cmd.lun), - GETLUN(iue->iu->srp.cmd.lun), - iue->req.vd->device_name, - test_bit(V_LINKED, &iue->req.flags), iue); - - req = scsi_allocate_request(iue->req.vd->s.sdev, GFP_KERNEL); - if (req == NULL) { - err("Not able to get scsi_request, retrying later\n"); - return RETRY; - } - - memcpy(req->sr_cmnd, iu->srp.cmd.cdb, sizeof(iu->srp.cmd.cdb)); - - req->sr_cmd_len = sizeof(iu->srp.cmd.cdb); - if (iu->srp.cmd.data_out_format && iu->srp.cmd.data_in_format) { - err("Invalid bidirectional buffer\n"); - send_rsp(iue, ABORTED_COMMAND, 0x00); - scsi_release_request(req); - return FREE_IU; - } else if (iu->srp.cmd.data_out_format) { /* write */ - atomic_inc(&iue->adapter->write_processed); - req->sr_data_direction = DMA_TO_DEVICE; - len = vscsis_data_length(&iue->iu->srp.cmd, 1); - __set_bit(V_WRITE, &iue->req.flags); - if (iue->req.vd->b.ro) { - warn("WRITE to read-only device\n"); - send_rsp(iue, DATA_PROTECT, 0x27); - scsi_release_request(req); - return FREE_IU; - } - } else if (iu->srp.cmd.data_in_format) { /* read */ - atomic_inc(&iue->adapter->read_processed); - req->sr_data_direction = DMA_FROM_DEVICE; - len = vscsis_data_length(&iue->iu->srp.cmd, 0); - } else { - dbg("No buffer command\n"); - req->sr_data_direction = DMA_NONE; - goto nobuf; - } - - get_data_buffer(&buffer, &iue->req.data_token, len, iue->adapter); - iue->req.data_buffer = buffer; - iue->req.data_len = len; - - if (test_bit(V_WRITE, &iue->req.flags)) { - int bytes = get_cmd_data(iue->req.data_token, len, iue); - - if (bytes != len) { - err("Error transferring data\n"); - free_data_buffer(buffer, iue->req.data_token, len, - iue->adapter); - scsi_release_request(req); - send_rsp(iue, HARDWARE_ERROR, 0x00); - return FREE_IU; - } - } - -nobuf: req->sr_use_sg = 0; - req->sr_bufflen = len; - req->sr_buffer = buffer; - req->sr_sense_buffer[0] = 0; - req->sr_request->flags = - test_bit(V_BARRIER, &iue->req.flags) ? REQ_HARDBARRIER : 0; - req->upper_private_data = (void*)iue; - iue->req.sreq = req; - dbg("sending %s of %d bytes, buffer %p, timeout=%d\n", - test_bit(V_WRITE, &iue->req.flags) ? "write" : "read", len, buffer, - iue->req.timeout); - - scsi_do_req(req, iu->srp.cmd.cdb, buffer, len, scsi_cmd_done, - iue->req.timeout, 3); - - return INFLIGHT; - -} /* ============================================================== * SRP Processing Routines @@ -2413,14 +2307,14 @@ static void process_login(struct iu_entry *iue) * buffer format is wrong */ memset(iu, 0, sizeof(struct srp_login_rsp)); - iu->srp.login_rsp.type = SRP_LOGIN_RSP_TYPE; - iu->srp.login_rsp.request_limit_delta = INITIAL_SRP_LIMIT; + iu->srp.login_rsp.opcode = SRP_LOGIN_RSP; + iu->srp.login_rsp.req_lim_delta = INITIAL_SRP_LIMIT; iu->srp.login_rsp.tag = tag; - iu->srp.login_rsp.max_initiator_to_target_iulen = sizeof(union srp_iu); - iu->srp.login_rsp.max_target_to_initiator_iulen = sizeof(union srp_iu); + iu->srp.login_rsp.max_it_iu_len = sizeof(union srp_iu); + iu->srp.login_rsp.max_ti_iu_len = sizeof(union srp_iu); /* direct and indirect */ - iu->srp.login_rsp.supported_buffer_formats = 0x0006; - iu->srp.login_rsp.multi_channel_result = 0x00; + iu->srp.login_rsp.buf_fmt = 0x0006; + iu->srp.login_rsp.rsp_flags = 0x00; send_iu(iue, sizeof(iu->srp.login_rsp), VIOSRP_SRP_FORMAT); } @@ -2455,7 +2349,7 @@ static void process_abort(struct iu_entry *iue) struct iu_entry *tmp_iue; unsigned long flags; union viosrp_iu *iu = iue->iu; - u64 tag = iu->srp.tsk_mgmt.managed_task_tag; + u64 tag = iu->srp.tsk_mgmt.task_tag; unsigned char status = ABORTED_COMMAND; info("aborting task with tag %16.16lx, lun %16.16lx\n", @@ -2489,9 +2383,9 @@ static void process_tsk_mgmt(struct iu_entry *iue) { union viosrp_iu *iu = iue->iu; - if (iu->srp.tsk_mgmt.task_mgmt_flags == 0x01) + if (iu->srp.tsk_mgmt.tsk_mgmt_func == 0x01) process_abort(iue); - else if (iu->srp.tsk_mgmt.task_mgmt_flags == 0x08) + else if (iu->srp.tsk_mgmt.tsk_mgmt_func == 0x08) process_device_reset(iue); else send_rsp(iue, ILLEGAL_REQUEST, 0x20); @@ -2519,33 +2413,30 @@ static int process_cmd(struct iu_entry *iue) if (getlink(iue)) __set_bit(V_LINKED, &iue->req.flags); - switch (iu->srp.cmd.task_attribute) { - case SRP_ORDERED_TASK: + switch (iu->srp.cmd.task_attr) { + case TASK_ATTR_ORDERED: __set_bit(V_BARRIER, &iue->req.flags); - case SRP_SIMPLE_TASK: + case TASK_ATTR_SIMPLE: break; default: __set_bit(V_BARRIER, &iue->req.flags); warn("Task attribute %d not supported, assuming barrier\n", - iu->srp.cmd.task_attribute); + iu->srp.cmd.task_attr); } - if (!iue->req.vd || !iue->req.vd->direct_scsi) - return process_cmd_block(iue); - else - return process_cmd_scsi(iue); + return process_cmd_block(iue); } /* * Respond to the adapter_info request */ u16 send_adapter_info(struct iu_entry *iue, - dma_addr_t remote_buffer, u16 length) + dma_addr_t remote_buffer, u16 length) { dma_addr_t data_token; struct mad_adapter_info_data *info = - dma_alloc_coherent(iue->adapter->dev, sizeof(*info), &data_token, - GFP_KERNEL); + dma_alloc_coherent(iue->adapter->dev, sizeof(*info), &data_token, + GFP_KERNEL); dbg("in send_adapter_info\n "); if (info != NULL) { @@ -2645,8 +2536,8 @@ static void run_cmd_queue(struct server_adapter *adapter) case INFLIGHT: if (!test_bit(V_IN_USE, &curr_iue->req.flags)) /* this means that the request finished - before process_cmd() returned, so we - lost a handle of the cmd_queue list */ + before process_cmd() returned, so we + lost a handle of the cmd_queue list */ goto out; break; case RETRY_SPLIT_BUF: @@ -2663,8 +2554,8 @@ static void run_cmd_queue(struct server_adapter *adapter) kblockd_schedule_work(&adapter->crq_task); /* if a barrier fails, we don't want anything - new to go through, retry when new cmd arrives - or when workqueue runs */ + new to go through, retry when new cmd arrives + or when workqueue runs */ if (test_bit(V_BARRIER, &curr_iue->req.flags)) goto out; break; @@ -2705,7 +2596,7 @@ static void process_iu(struct viosrp_crq *crq, struct server_adapter *adapter) if (rc) { err("process_iu: Error %ld transferring data from client\n", - rc); + rc); } if (crq->format == VIOSRP_MAD_FORMAT) { @@ -2721,10 +2612,10 @@ static void process_iu(struct viosrp_crq *crq, struct server_adapter *adapter) break; case VIOSRP_ADAPTER_INFO_TYPE: iu->mad.adapter_info.common.status = - send_adapter_info(iue, - iu->mad.adapter_info.buffer, - iu->mad.adapter_info.common. - length); + send_adapter_info(iue, + iu->mad.adapter_info.buffer, + iu->mad.adapter_info.common. + length); send_iu(iue, sizeof(iu->mad.adapter_info), VIOSRP_MAD_FORMAT); @@ -2736,45 +2627,47 @@ static void process_iu(struct viosrp_crq *crq, struct server_adapter *adapter) break; default: warn("Unsupported MAD type %d\n", iu->srp.generic.type); + iu->mad.common.status = VIOSRP_MAD_NOT_SUPPORTED; + send_iu(iue, sizeof(iu->mad.common), VIOSRP_MAD_FORMAT); } } else { switch (iu->srp.generic.type) { - case SRP_LOGIN_REQ_TYPE: + case SRP_LOGIN_REQ: dbg("SRP LOGIN\n"); process_login(iue); break; - case SRP_LOGIN_RSP_TYPE: + case SRP_LOGIN_RSP: warn("Unsupported LOGIN_RSP SRP IU\n"); break; - case SRP_I_LOGOUT_TYPE: + case SRP_I_LOGOUT: warn("Unsupported I_LOGOUT SRP IU\n"); break; - case SRP_T_LOGOUT_TYPE: + case SRP_T_LOGOUT: warn("Unsupported T_LOGOUT SRP IU\n"); break; - case SRP_TSK_MGMT_TYPE: + case SRP_TSK_MGMT: process_tsk_mgmt(iue); break; - case SRP_CMD_TYPE: + case SRP_CMD: spin_lock_irqsave(&adapter->lock, flags); list_add_tail(&iue->next, &adapter->cmd_queue); spin_unlock_irqrestore(&adapter->lock, flags); run_cmd_queue(adapter); return; break; - case SRP_RSP_TYPE: + case SRP_RSP: warn("Unsupported RSP SRP IU\n"); break; - case SRP_CRED_REQ_TYPE: + case SRP_CRED_REQ: warn("Unsupported CRED_REQ SRP IU\n"); break; - case SRP_CRED_RSP_TYPE: + case SRP_CRED_RSP: warn("Unsupported CRED_RSP SRP IU\n"); break; - case SRP_AER_REQ_TYPE: + case SRP_AER_REQ: warn("Unsupported AER_REQ SRP IU\n"); break; - case SRP_AER_RSP_TYPE: + case SRP_AER_RSP: warn("Unsupported AER_RSP SRP IU\n"); break; default: @@ -2798,7 +2691,7 @@ static void process_iu(struct viosrp_crq *crq, struct server_adapter *adapter) static void handle_crq(struct viosrp_crq *crq, struct server_adapter *adapter) { switch (crq->valid) { - case 0xC0: /* initialization */ + case 0xC0: /* initialization */ switch (crq->format) { case 0x01: h_send_crq(adapter->dma_dev->unit_address, @@ -2811,9 +2704,9 @@ static void handle_crq(struct viosrp_crq *crq, struct server_adapter *adapter) crq->format); } return; - case 0xFF: /* transport event */ + case 0xFF: /* transport event */ return; - case 0x80: /* real payload */ + case 0x80: /* real payload */ { switch (crq->format) { case VIOSRP_SRP_FORMAT: @@ -2883,7 +2776,7 @@ static void crq_task(void *data) * Handle the interrupt that occurs when something is placed on our CRQ */ static irqreturn_t handle_interrupt(int irq, void *dev_instance, - struct pt_regs *regs) + struct pt_regs *regs) { struct server_adapter *adapter = (struct server_adapter *)dev_instance; @@ -2901,7 +2794,7 @@ static irqreturn_t handle_interrupt(int irq, void *dev_instance, * return zero on success, non-zero on failure */ static int initialize_crq_queue(struct crq_queue *queue, - struct server_adapter *adapter) + struct server_adapter *adapter) { int rc; @@ -2924,11 +2817,11 @@ static int initialize_crq_queue(struct crq_queue *queue, * try freeing and re-registering */ if (rc == H_Resource) { - do { - rc = h_free_crq(adapter->dma_dev->unit_address); - } while ((rc == H_Busy) || (H_isLongBusy(rc))); - rc = h_reg_crq(adapter->dma_dev->unit_address, queue->msg_token, - PAGE_SIZE); + do { + rc = h_free_crq(adapter->dma_dev->unit_address); + } while ((rc == H_Busy) || (H_isLongBusy(rc))); + rc = h_reg_crq(adapter->dma_dev->unit_address, queue->msg_token, + PAGE_SIZE); } if ((rc != H_Success) && (rc != 2)) { @@ -2950,17 +2843,17 @@ static int initialize_crq_queue(struct crq_queue *queue, return 0; -req_irq_failed: + req_irq_failed: do { rc = h_free_crq(adapter->dma_dev->unit_address); } while ((rc == H_Busy) || (H_isLongBusy(rc))); -reg_crq_failed: + reg_crq_failed: dma_unmap_single(adapter->dev, queue->msg_token, queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); -map_failed: + map_failed: free_page((unsigned long)queue->msgs); -malloc_failed: + malloc_failed: return -ENOMEM; } @@ -2968,7 +2861,7 @@ malloc_failed: * Release the CRQ */ static void release_crq_queue(struct crq_queue *queue, - struct server_adapter *adapter) + struct server_adapter *adapter) { int rc; @@ -2994,39 +2887,15 @@ static int activate_device(struct vdev *vdev) struct block_device *bdev; char *name = vdev->device_name; int ro = vdev->b.ro; - unsigned long flags; - struct scsi_dev_node *tmp_sdn; bdev = open_bdev_excl(name, ro, activate_device); if (IS_ERR(bdev)) return PTR_ERR(bdev);; - spin_lock_irqsave(&sdev_list_lock, flags); - list_for_each_entry(tmp_sdn, &scsi_dev_list, node) { - struct scsi_device *sdev = tmp_sdn->sdev; - /* if the block device is a known scsi_device and - device is not a partition */ - if (sdev->request_queue == bdev->bd_disk->queue && - bdev == bdev->bd_contains) { - vdev->s.sdev = sdev; - tmp_sdn->vdev = vdev; - spin_unlock_irqrestore(&sdev_list_lock, flags); - close_bdev_excl(bdev); - vdev->direct_scsi = (char)1; - vdev->disabled = 0; - info("Activating %s (scsi %d:%d:%d:%d) as LUN 0x%lx\n", - name, sdev->host->host_no, sdev->channel, - sdev->id, sdev->lun, vdev->lun); - return 0; - } - } - spin_unlock_irqrestore(&sdev_list_lock, flags); - - vdev->direct_scsi = 0; vdev->b.bdev = bdev; vdev->disabled = 0; vdev->b.sectsize = bdev_hardsect_size(bdev); - vdev->b.blocksize = bdev->bd_block_size; + vdev->b.blocksize = PAGE_CACHE_SIZE; if (bdev->bd_disk->flags & GENHD_FL_CD) vdev->b.scsi_type = TYPE_ROM; /* CD/DVD */ else @@ -3046,23 +2915,12 @@ static int activate_device(struct vdev *vdev) return 0; } -static void deactivate_scsi_device(struct vdev *vdev) -{ - struct scsi_dev_node *tmp_sdn; - - vdev->disabled = 1; - vdev->s.sdev = NULL; - - list_for_each_entry(tmp_sdn, &scsi_dev_list, node) - if (tmp_sdn->vdev == vdev) - tmp_sdn->vdev = NULL; -} static void deactivate_device(struct vdev *vdev) { info("Deactivating block device, LUN 0x%lx\n", vdev->lun); - /* Wait while any users of this device finish. Note there should + /* Wait while any users of this device finish. Note there should * be no new users, since we have marked this disabled * * We just poll here, since we are blocking write @@ -3073,60 +2931,466 @@ static void deactivate_device(struct vdev *vdev) vdev->disabled = 1; - if (!vdev->direct_scsi) - close_bdev_excl(vdev->b.bdev); - else - deactivate_scsi_device(vdev); + close_bdev_excl(vdev->b.bdev); } -/* - * Callback when a scsi_device gets added to the system + +/* ============================================================== + * SYSFS Routines + * ============================================================== */ -static int add_scsi_device(struct class_device *cdev) +static struct kobj_type ktype_vscsi_target; +static struct kobj_type ktype_vscsi_bus; +static struct kobj_type ktype_vscsi_stats; + +static void vscsi_target_release(struct kobject *kobj) { + struct vdev *tmpdev = + container_of(kobj,struct vdev,kobj); + kfree(tmpdev); +} + +static void vscsi_bus_release(struct kobject *kobj) { + struct vbus *tmpbus = + container_of(kobj,struct vbus,kobj); + kfree(tmpbus); +} + +static void set_num_targets(struct vbus* vbus, long value) { - struct scsi_device *sdev = to_scsi_device(cdev->dev); - struct scsi_dev_node * sdevnode = - kmalloc(sizeof(struct scsi_dev_node), GFP_ATOMIC); + struct device *dev = + container_of(vbus->kobj.parent, struct device , kobj); + struct server_adapter *adapter = + (struct server_adapter *)dev->driver_data; + int cur_num_targets = atomic_read(&vbus->num_targets); unsigned long flags; + struct vdev *tmpdev; - dbg("add_scsi_device got %p, %d:%d:%d:%d, sdn=%p\n", sdev, - sdev->host->host_no, sdev->channel, sdev->id, sdev->lun, sdevnode); + /* Growing */ + if (cur_num_targets < value) { + int i; + for (i = cur_num_targets; i < value; i++) { + tmpdev = (struct vdev *)kmalloc(sizeof(struct vdev), + GFP_KERNEL); + if (!tmpdev) { + err("Couldn't allocate target memory %d\n", i); + return; + } + memset(tmpdev, 0, sizeof(struct vdev)); - sdevnode->sdev = sdev; - sdevnode->vdev = NULL; + tmpdev->lun = make_lun(vbus->bus_num, i, 0); + tmpdev->b.blocksize = PAGE_CACHE_SIZE; + tmpdev->b.sectsize = 512; + tmpdev->type = 'B'; + tmpdev->disabled = 1; - spin_lock_irqsave(&sdev_list_lock, flags); - list_add_tail(&sdevnode->node, &scsi_dev_list); - spin_unlock_irqrestore(&sdev_list_lock, flags); + tmpdev->kobj.parent = &vbus->kobj; + sprintf(tmpdev->kobj.name, "target%d", i); + tmpdev->kobj.ktype = &ktype_vscsi_target; + kobject_register(&tmpdev->kobj); + + spin_lock_irqsave(&adapter->lock, flags); + if (vbus->vdev[i]) { + /* Race!!! */ + spin_unlock_irqrestore(&adapter->lock, flags); + kobject_unregister(&tmpdev->kobj); + continue; + } + + adapter->nvdevs++; + atomic_inc(&vbus->num_targets); + vbus->vdev[i] = tmpdev; + spin_unlock_irqrestore(&adapter->lock, flags); + } + } else { /* shrinking */ + int i; + for (i = cur_num_targets - 1; i >= value; i--) + { + if (!vbus->vdev[i]->disabled) { + err("Can't remove active target %d\n", i); + return; + } + + spin_lock_irqsave(&adapter->lock, flags); + tmpdev = vbus->vdev[i]; + vbus->vdev[i] = NULL; + spin_unlock_irqrestore(&adapter->lock, flags); + + if (tmpdev) + kobject_unregister(&tmpdev->kobj); + + adapter->nvdevs--; + atomic_dec(&vbus->num_targets); + } + } +} + +static void set_num_buses(struct device *dev, long value) +{ + struct server_adapter *adapter = + (struct server_adapter *)dev->driver_data; + int cur_num_buses = atomic_read(&adapter->num_buses); + unsigned long flags; + struct vbus *tmpbus; + + if (cur_num_buses < value) { /* growing */ + int i; + for (i = cur_num_buses; i < value; i++) { + tmpbus = (struct vbus *) kmalloc(sizeof(struct vbus), + GFP_KERNEL); + if (!tmpbus) { + err("Couldn't allocate bus %d memory\n", i); + return; + } + + memset(tmpbus, 0, sizeof(struct vbus)); + tmpbus->bus_num = i; + tmpbus->kobj.parent = &dev->kobj; + sprintf(tmpbus->kobj.name, "bus%d", i); + tmpbus->kobj.ktype = &ktype_vscsi_bus; + kobject_register(&tmpbus->kobj); + + spin_lock_irqsave(&adapter->lock, flags); + + if (adapter->vbus[i] != NULL) { + /* Race condition! */ + spin_unlock_irqrestore(&adapter->lock, flags); + kobject_unregister(&tmpbus->kobj); + continue; + } + + adapter->vbus[i] = tmpbus; + + atomic_inc(&adapter->num_buses); + spin_unlock_irqrestore(&adapter->lock, flags); + + set_num_targets(adapter->vbus[i], 1); + } + + } else if (cur_num_buses > value) { /* shrinking */ + int i, j, active_target; + for (i = cur_num_buses - 1; i >= value; i--) { + active_target = -1; + for (j = 0; j < TARGETS_PER_BUS; j++) { + if (adapter->vbus[i]->vdev[j] && + !adapter->vbus[i]->vdev[j]->disabled) { + active_target = j; + break; + } + } + if (active_target != -1) { + err("Can't remove bus%d, target%d active\n", + i, active_target); + return ; + } + + set_num_targets(adapter->vbus[i], 0); + + spin_lock_irqsave(&adapter->lock, flags); + atomic_dec(&adapter->num_buses); + tmpbus = adapter->vbus[i]; + adapter->vbus[i] = NULL; + spin_unlock_irqrestore(&adapter->lock, flags); + + /* If we race this could already be NULL */ + if (tmpbus) + kobject_unregister(&tmpbus->kobj); + } + } +} + +/* Target sysfs stuff */ +static ATTR(target, type, 0644); +static ATTR(target, device, 0644); +static ATTR(target, active, 0644); +static ATTR(target, ro, 0644); + +static ssize_t vscsi_target_show(struct kobject * kobj, + struct attribute * attr, char * buf) +{ + struct vdev *vdev = container_of(kobj, struct vdev, kobj); + struct device *dev = container_of(kobj->parent->parent, + struct device, kobj); + struct server_adapter *adapter = + (struct server_adapter *)dev->driver_data; + unsigned long flags; + ssize_t returned; + + spin_lock_irqsave(&adapter->lock, flags); + + if (attr == &vscsi_target_device_attr) + returned = sprintf(buf, "%s\n", vdev->device_name); + else if (attr == &vscsi_target_active_attr) + returned = sprintf(buf, "%d\n", !vdev->disabled); + else if (attr == &vscsi_target_ro_attr) + returned = sprintf(buf, "%d\n", vdev->b.ro); + else if (attr == &vscsi_target_type_attr) + returned = sprintf(buf, "%c\n", vdev->type); + else { + returned = -EFAULT; + BUG(); + } + + spin_unlock_irqrestore(&adapter->lock, flags); + + return returned; +} + +static ssize_t vscsi_target_store(struct kobject * kobj, + struct attribute * attr, + const char * buf, size_t count) +{ + struct vdev *vdev = container_of(kobj, struct vdev, kobj); + struct device *dev = container_of(kobj->parent->parent, + struct device, kobj); + struct server_adapter *adapter = + (struct server_adapter *)dev->driver_data; + long flags; + long value = simple_strtol(buf, NULL, 10); + + if (attr != &vscsi_target_active_attr && !vdev->disabled) { + err("Error: Can't modify properties while target is active.\n"); + return -EPERM; + } + + if (attr == &vscsi_target_device_attr) { + int i; + spin_lock_irqsave(&adapter->lock, flags); + i = strlcpy(vdev->device_name, buf, TARGET_MAX_NAME_LEN); + for (; i >= 0; i--) + if (vdev->device_name[i] == '\n') + vdev->device_name[i] = '\0'; + spin_unlock_irqrestore(&adapter->lock, flags); + } else if (attr == &vscsi_target_active_attr) { + if (value) { + int rc; + if (!vdev->disabled) { + warn("Warning: Target was already active\n"); + return -EINVAL; + } + rc = activate_device(vdev); + if (rc) { + err("Error opening device=%d\n", rc); + return rc; + } + } else { + if (!vdev->disabled) + deactivate_device(vdev); + } + } else if (attr == &vscsi_target_ro_attr) + vdev->b.ro = value > 0 ? 1 : 0; + else if (attr == &vscsi_target_type_attr) { + if (buf[0] == 'B' || buf[0] == 'b') + vdev->type = 'B'; + else if (buf[0] == 'S' || buf[0] == 's') + vdev->type = 'S'; + else + return -EINVAL; + } + else + BUG(); + + return count; +} + +static struct attribute * vscsi_target_attrs[] = { + &vscsi_target_type_attr, + &vscsi_target_device_attr, + &vscsi_target_active_attr, + &vscsi_target_ro_attr, + NULL, +}; + +static struct sysfs_ops vscsi_target_ops = { + .show = vscsi_target_show, + .store = vscsi_target_store, +}; + +static struct kobj_type ktype_vscsi_target = { + .release = vscsi_target_release, + .sysfs_ops = &vscsi_target_ops, + .default_attrs = vscsi_target_attrs, +}; + +/* Bus sysfs stuff */ +static ssize_t vscsi_bus_show(struct kobject * kobj, + struct attribute * attr, char * buf) +{ + struct vbus *vbus = container_of(kobj, struct vbus, kobj); + return sprintf(buf, "%d\n", atomic_read(&vbus->num_targets)); +} + +static ssize_t vscsi_bus_store(struct kobject * kobj, struct attribute * attr, +const char * buf, size_t count) +{ + struct vbus *vbus = container_of(kobj, struct vbus, kobj); + long value = simple_strtol(buf, NULL, 10); + + if (value < 0 || value > TARGETS_PER_BUS) + return -EINVAL; + + set_num_targets(vbus, value); + + return count; +} + +static ATTR(bus, num_targets, 0644); + +static struct attribute * vscsi_bus_attrs[] = { + &vscsi_bus_num_targets_attr, + NULL, +}; + +static struct sysfs_ops vscsi_bus_ops = { + .show = vscsi_bus_show, + .store = vscsi_bus_store, +}; + +static struct kobj_type ktype_vscsi_bus = { + .release = vscsi_bus_release, + .sysfs_ops = &vscsi_bus_ops, + .default_attrs = vscsi_bus_attrs, +}; + +/* Device attributes */ +static ssize_t vscsi_dev_bus_show(struct device * dev, + struct device_attribute *attr, + char * buf) +{ + struct server_adapter *adapter = + (struct server_adapter *)dev->driver_data; + + return sprintf(buf, "%d\n", atomic_read(&adapter->num_buses)); +} + +static ssize_t vscsi_dev_sector_show(struct device * dev, + struct device_attribute *attr, + char * buf) +{ + struct server_adapter *adapter = + (struct server_adapter *)dev->driver_data; + + return sprintf(buf, "%d\n", adapter->max_sectors); +} + +static ssize_t vscsi_dev_bus_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ + long value = simple_strtol(buf, NULL, 10); + + if (value < 0 || value > BUS_PER_ADAPTER) + return -EINVAL; + + set_num_buses(dev, value); + return count; +} + +static ssize_t vscsi_dev_sector_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ + long value = simple_strtol(buf, NULL, 10); + struct server_adapter *adapter = + (struct server_adapter *)dev->driver_data; + + if (value <= 8 || value > SCSI_DEFAULT_MAX_SECTORS) + return -EINVAL; + + adapter->max_sectors = value; + + return count; +} + +static ssize_t vscsi_dev_debug_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ + long value = simple_strtol(buf, NULL, 10); + + ibmvscsis_debug = value; + return count; +} + +static ssize_t vscsi_dev_debug_show(struct device * dev, + struct device_attribute *attr, + char * buf) +{ + return sprintf(buf, "%d\n", ibmvscsis_debug); +} + +static DEVICE_ATTR(debug, 0644, vscsi_dev_debug_show, vscsi_dev_debug_store); +static DEVICE_ATTR(num_buses, 0644, vscsi_dev_bus_show, vscsi_dev_bus_store); +static DEVICE_ATTR(max_sectors, 0644, vscsi_dev_sector_show, + vscsi_dev_sector_store); + +/* Stats kobj stuff */ + +static ATTR(stats, interrupts, 0444); +static ATTR(stats, read_ops, 0444); +static ATTR(stats, write_ops, 0444); +static ATTR(stats, crq_msgs, 0444); +static ATTR(stats, iu_allocs, 0444); +static ATTR(stats, bio_allocs, 0444); +static ATTR(stats, buf_allocs, 0444); +static ATTR(stats, errors, 0444); + +static struct attribute * vscsi_stats_attrs[] = { + &vscsi_stats_interrupts_attr, + &vscsi_stats_read_ops_attr, + &vscsi_stats_write_ops_attr, + &vscsi_stats_crq_msgs_attr, + &vscsi_stats_iu_allocs_attr, + &vscsi_stats_bio_allocs_attr, + &vscsi_stats_buf_allocs_attr, + &vscsi_stats_errors_attr, + NULL, +}; + +static ssize_t vscsi_stats_show(struct kobject * kobj, + struct attribute * attr, char * buf) +{ + struct server_adapter *adapter= container_of(kobj, + struct server_adapter, + stats_kobj); + if (attr == &vscsi_stats_interrupts_attr) + return sprintf(buf, "%d\n", + atomic_read(&adapter->interrupts)); + if (attr == &vscsi_stats_read_ops_attr) + return sprintf(buf, "%d\n", + atomic_read(&adapter->read_processed)); + if (attr == &vscsi_stats_write_ops_attr) + return sprintf(buf, "%d\n", + atomic_read(&adapter->write_processed)); + if (attr == &vscsi_stats_crq_msgs_attr) + return sprintf(buf, "%d\n", + atomic_read(&adapter->crq_processed)); + if (attr == &vscsi_stats_iu_allocs_attr) + return sprintf(buf, "%d\n", + atomic_read(&adapter->iu_count)); + if (attr == &vscsi_stats_bio_allocs_attr) + return sprintf(buf, "%d\n", + atomic_read(&adapter->bio_count)); + if (attr == &vscsi_stats_buf_allocs_attr) + return sprintf(buf, "%d\n", + atomic_read(&adapter->buffers_allocated)); + if (attr == &vscsi_stats_errors_attr) + return sprintf(buf, "%d\n", + atomic_read(&adapter->errors)); + + BUG(); return 0; } -/* - * Callback when a scsi_device gets removed from the system - */ -static void rem_scsi_device(struct class_device *cdev) -{ - struct scsi_dev_node *tmp_sdn; - struct scsi_device *sdev = to_scsi_device(cdev->dev); - unsigned long flags; +static struct sysfs_ops vscsi_stats_ops = { + .show = vscsi_stats_show, + .store = NULL, +}; - spin_lock_irqsave(&sdev_list_lock, flags); - list_for_each_entry(tmp_sdn, &scsi_dev_list, node) { - if (sdev == tmp_sdn->sdev) { - if (tmp_sdn->vdev && !tmp_sdn->vdev->disabled) - deactivate_scsi_device(tmp_sdn->vdev); - list_del(&tmp_sdn->node); - kfree(tmp_sdn); - goto out; - } - } - - warn("rem_scsi_device: Couldn't find scsi_device %p %d:%d:%d:%d\n", - sdev, sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); -out: - spin_unlock_irqrestore(&sdev_list_lock, flags); - return; -} +static struct kobj_type ktype_vscsi_stats = { + .release = NULL, + .sysfs_ops = &vscsi_stats_ops, + .default_attrs = vscsi_stats_attrs, +}; /* ============================================================== * Module load and unload @@ -3152,8 +3416,8 @@ static int ibmvscsis_probe(struct vio_dev *dev, const struct vio_device_id *id) adapter->lock = SPIN_LOCK_UNLOCKED; dma_window = - (unsigned int *)vio_get_attribute(dev, "ibm,my-dma-window", - &dma_window_property_size); + (unsigned int *)vio_get_attribute(dev, "ibm,my-dma-window", + &dma_window_property_size); if ((!dma_window) || (dma_window_property_size != 40)) { err("Couldn't get ibm,my-dma-window property\n"); return -EIO; @@ -3185,6 +3449,17 @@ static int ibmvscsis_probe(struct vio_dev *dev, const struct vio_device_id *id) return rc; } + set_num_buses(&dev->dev, 1); + adapter->max_sectors = DEFAULT_MAX_SECTORS; + device_create_file(&dev->dev, &dev_attr_debug); + device_create_file(&dev->dev, &dev_attr_num_buses); + device_create_file(&dev->dev, &dev_attr_max_sectors); + + adapter->stats_kobj.parent = &dev->dev.kobj; + strcpy(adapter->stats_kobj.name, "stats"); + adapter->stats_kobj.ktype = & ktype_vscsi_stats; + kobject_register(&adapter->stats_kobj); + return 0; } @@ -3194,7 +3469,7 @@ static int ibmvscsis_remove(struct vio_dev *dev) int target; unsigned long flags; struct server_adapter *adapter = - (struct server_adapter *)dev->dev.driver_data; + (struct server_adapter *)dev->dev.driver_data; spin_lock_irqsave(&adapter->lock, flags); @@ -3208,30 +3483,39 @@ static int ibmvscsis_remove(struct vio_dev *dev) for (target = 0; target < TARGETS_PER_BUS; target++) { /* If the target exists */ struct vdev *vdev = - adapter->vbus[bus]->vdev[target]; - if (vdev && !vdev ->disabled) + adapter->vbus[bus]->vdev[target]; + if (vdev && !vdev ->disabled) { + spin_unlock_irqrestore(&adapter->lock, + flags); deactivate_device(vdev); + spin_lock_irqsave(&adapter->lock, + flags); + } } + spin_unlock_irqrestore(&adapter->lock, flags); + set_num_targets(adapter->vbus[bus], 0); + spin_lock_irqsave(&adapter->lock, flags); } } spin_unlock_irqrestore(&adapter->lock, flags); + set_num_buses(adapter->dev, 0); release_crq_queue(&adapter->queue, adapter); release_iu_pool(adapter); release_data_buffer(adapter); + kobject_unregister(&adapter->stats_kobj); + device_remove_file(&dev->dev, &dev_attr_debug); + device_remove_file(&dev->dev, &dev_attr_num_buses); + device_remove_file(&dev->dev, &dev_attr_max_sectors); + kfree(adapter); return 0; } -static struct class_interface vscsis_interface = { - .add = add_scsi_device, - .remove = rem_scsi_device, -}; - static struct vio_device_id ibmvscsis_device_table[] __devinitdata = { {"v-scsi-host", "IBM,v-scsi-host"}, {"",""} @@ -3240,10 +3524,13 @@ static struct vio_device_id ibmvscsis_device_table[] __devinitdata = { MODULE_DEVICE_TABLE(vio, ibmvscsis_device_table); static struct vio_driver ibmvscsis_driver = { - .name = "ibmvscsis", .id_table = ibmvscsis_device_table, .probe = ibmvscsis_probe, .remove = ibmvscsis_remove, + .driver = { + .name = "ibmvscsis", + .owner = THIS_MODULE, + }, }; static int mod_init(void) @@ -3285,8 +3572,6 @@ static int mod_init(void) return rc; } - rc = scsi_register_interface(&vscsis_interface); - if (rc) warn("rc %d from scsi_register_interface\n", rc); @@ -3297,7 +3582,6 @@ static void mod_exit(void) { info("terminated\n"); - scsi_unregister_interface(&vscsis_interface); vio_unregister_driver(&ibmvscsis_driver); }