[PATCH] I2O: new sysfs attributes and Adaptec specific block device access and 64-bit DMA support

Changes:
 - Added Bus-OSM which could be used by user space programs to reset a
   channel on the controller
 - Make ioctl's in Config-OSM obsolete in prefer for sysfs attributes and
   move those to its own file
 - Added sysfs attribute for firmware read and write access for I2O
   controllers
 - Added special handling of firmware read and write access for Adaptec
   controllers
 - Added vendor id and product id as sysfs-attribute to Executive classes
 - Added automatic notification of LCT change handling to Exec-OSM
 - Added flushing function to Block-OSM for later barrier implementation
 - Use PRIVATE messages for Block access on Adaptec controllers, which are
   faster then BLOCK class access
 - Cleaned up support for Promise controller
 - New messages are now detected using the IRQ status register as
   suggested by the I2O spec
 - Added i2o_dma_high() and i2o_dma_low() functions
 - Added facility for SG tablesize calculation when using 32-bit and
   64-bit DMA addresses
 - Added i2o_dma_map_single() and i2o_dma_map_sg() which could build the
   SG list for 32-bit as well as 64-bit DMA addresses

Signed-off-by: Markus Lidel <Markus.Lidel@shadowconnect.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Markus Lidel
2005-06-23 22:02:16 -07:00
committed by Linus Torvalds
parent f88e119c4b
commit f10378fff6
15 changed files with 1473 additions and 559 deletions

View File

@@ -32,6 +32,10 @@ typedef unsigned int u32;
#endif /* __KERNEL__ */
/*
* Vendors
*/
#define I2O_VENDOR_DPT 0x001b
/*
* I2O Control IOCTLs and structures
@@ -333,7 +337,7 @@ typedef struct _i2o_status_block {
#define I2O_CLASS_ATE_PERIPHERAL 0x061
#define I2O_CLASS_FLOPPY_CONTROLLER 0x070
#define I2O_CLASS_FLOPPY_DEVICE 0x071
#define I2O_CLASS_BUS_ADAPTER_PORT 0x080
#define I2O_CLASS_BUS_ADAPTER 0x080
#define I2O_CLASS_PEER_TRANSPORT_AGENT 0x090
#define I2O_CLASS_PEER_TRANSPORT 0x091
#define I2O_CLASS_END 0xfff

View File

@@ -157,7 +157,8 @@ struct i2o_controller {
void __iomem *in_port; /* Inbout port address */
void __iomem *out_port; /* Outbound port address */
void __iomem *irq_mask; /* Interrupt register address */
void __iomem *irq_status; /* Interrupt status register address */
void __iomem *irq_mask; /* Interrupt mask register address */
/* Dynamic LCT related data */
@@ -242,15 +243,6 @@ extern int i2o_msg_post_wait_mem(struct i2o_controller *, u32, unsigned long,
extern void i2o_msg_nop(struct i2o_controller *, u32);
static inline void i2o_flush_reply(struct i2o_controller *, u32);
/* DMA handling functions */
static inline int i2o_dma_alloc(struct device *, struct i2o_dma *, size_t,
unsigned int);
static inline void i2o_dma_free(struct device *, struct i2o_dma *);
int i2o_dma_realloc(struct device *, struct i2o_dma *, size_t, unsigned int);
static inline int i2o_dma_map(struct device *, struct i2o_dma *);
static inline void i2o_dma_unmap(struct device *, struct i2o_dma *);
/* IOP functions */
extern int i2o_status_get(struct i2o_controller *);
@@ -275,6 +267,16 @@ static inline u32 i2o_ptr_high(void *ptr)
{
return (u32) ((u64) ptr >> 32);
};
static inline u32 i2o_dma_low(dma_addr_t dma_addr)
{
return (u32) (u64) dma_addr;
};
static inline u32 i2o_dma_high(dma_addr_t dma_addr)
{
return (u32) ((u64) dma_addr >> 32);
};
#else
static inline u32 i2o_cntxt_list_add(struct i2o_controller *c, void *ptr)
{
@@ -305,8 +307,246 @@ static inline u32 i2o_ptr_high(void *ptr)
{
return 0;
};
static inline u32 i2o_dma_low(dma_addr_t dma_addr)
{
return (u32) dma_addr;
};
static inline u32 i2o_dma_high(dma_addr_t dma_addr)
{
return 0;
};
#endif
/**
* i2o_sg_tablesize - Calculate the maximum number of elements in a SGL
* @c: I2O controller for which the calculation should be done
* @body_size: maximum body size used for message in 32-bit words.
*
* Return the maximum number of SG elements in a SG list.
*/
static inline u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size)
{
i2o_status_block *sb = c->status_block.virt;
u16 sg_count =
(sb->inbound_frame_size - sizeof(struct i2o_message) / 4) -
body_size;
if (c->pae_support) {
/*
* for 64-bit a SG attribute element must be added and each
* SG element needs 12 bytes instead of 8.
*/
sg_count -= 2;
sg_count /= 3;
} else
sg_count /= 2;
if (c->short_req && (sg_count > 8))
sg_count = 8;
return sg_count;
};
/**
* i2o_dma_map_single - Map pointer to controller and fill in I2O message.
* @c: I2O controller
* @ptr: pointer to the data which should be mapped
* @size: size of data in bytes
* @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
* @sg_ptr: pointer to the SG list inside the I2O message
*
* This function does all necessary DMA handling and also writes the I2O
* SGL elements into the I2O message. For details on DMA handling see also
* dma_map_single(). The pointer sg_ptr will only be set to the end of the
* SG list if the allocation was successful.
*
* Returns DMA address which must be checked for failures using
* dma_mapping_error().
*/
static inline dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
size_t size,
enum dma_data_direction direction,
u32 __iomem ** sg_ptr)
{
u32 sg_flags;
u32 __iomem *mptr = *sg_ptr;
dma_addr_t dma_addr;
switch (direction) {
case DMA_TO_DEVICE:
sg_flags = 0xd4000000;
break;
case DMA_FROM_DEVICE:
sg_flags = 0xd0000000;
break;
default:
return 0;
}
dma_addr = dma_map_single(&c->pdev->dev, ptr, size, direction);
if (!dma_mapping_error(dma_addr)) {
#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
writel(0x7C020002, mptr++);
writel(PAGE_SIZE, mptr++);
}
#endif
writel(sg_flags | size, mptr++);
writel(i2o_dma_low(dma_addr), mptr++);
#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
if ((sizeof(dma_addr_t) > 4) && c->pae_support)
writel(i2o_dma_high(dma_addr), mptr++);
#endif
*sg_ptr = mptr;
}
return dma_addr;
};
/**
* i2o_dma_map_sg - Map a SG List to controller and fill in I2O message.
* @c: I2O controller
* @sg: SG list to be mapped
* @sg_count: number of elements in the SG list
* @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
* @sg_ptr: pointer to the SG list inside the I2O message
*
* This function does all necessary DMA handling and also writes the I2O
* SGL elements into the I2O message. For details on DMA handling see also
* dma_map_sg(). The pointer sg_ptr will only be set to the end of the SG
* list if the allocation was successful.
*
* Returns 0 on failure or 1 on success.
*/
static inline int i2o_dma_map_sg(struct i2o_controller *c,
struct scatterlist *sg, int sg_count,
enum dma_data_direction direction,
u32 __iomem ** sg_ptr)
{
u32 sg_flags;
u32 __iomem *mptr = *sg_ptr;
switch (direction) {
case DMA_TO_DEVICE:
sg_flags = 0x14000000;
break;
case DMA_FROM_DEVICE:
sg_flags = 0x10000000;
break;
default:
return 0;
}
sg_count = dma_map_sg(&c->pdev->dev, sg, sg_count, direction);
if (!sg_count)
return 0;
#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
writel(0x7C020002, mptr++);
writel(PAGE_SIZE, mptr++);
}
#endif
while (sg_count-- > 0) {
if (!sg_count)
sg_flags |= 0xC0000000;
writel(sg_flags | sg_dma_len(sg), mptr++);
writel(i2o_dma_low(sg_dma_address(sg)), mptr++);
#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
if ((sizeof(dma_addr_t) > 4) && c->pae_support)
writel(i2o_dma_high(sg_dma_address(sg)), mptr++);
#endif
sg++;
}
*sg_ptr = mptr;
return 1;
};
/**
* i2o_dma_alloc - Allocate DMA memory
* @dev: struct device pointer to the PCI device of the I2O controller
* @addr: i2o_dma struct which should get the DMA buffer
* @len: length of the new DMA memory
* @gfp_mask: GFP mask
*
* Allocate a coherent DMA memory and write the pointers into addr.
*
* Returns 0 on success or -ENOMEM on failure.
*/
static inline int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr,
size_t len, unsigned int gfp_mask)
{
struct pci_dev *pdev = to_pci_dev(dev);
int dma_64 = 0;
if ((sizeof(dma_addr_t) > 4) && (pdev->dma_mask == DMA_64BIT_MASK)) {
dma_64 = 1;
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK))
return -ENOMEM;
}
addr->virt = dma_alloc_coherent(dev, len, &addr->phys, gfp_mask);
if ((sizeof(dma_addr_t) > 4) && dma_64)
if (pci_set_dma_mask(pdev, DMA_64BIT_MASK))
printk(KERN_WARNING "i2o: unable to set 64-bit DMA");
if (!addr->virt)
return -ENOMEM;
memset(addr->virt, 0, len);
addr->len = len;
return 0;
};
/**
* i2o_dma_free - Free DMA memory
* @dev: struct device pointer to the PCI device of the I2O controller
* @addr: i2o_dma struct which contains the DMA buffer
*
* Free a coherent DMA memory and set virtual address of addr to NULL.
*/
static inline void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
{
if (addr->virt) {
if (addr->phys)
dma_free_coherent(dev, addr->len, addr->virt,
addr->phys);
else
kfree(addr->virt);
addr->virt = NULL;
}
};
/**
* i2o_dma_realloc - Realloc DMA memory
* @dev: struct device pointer to the PCI device of the I2O controller
* @addr: pointer to a i2o_dma struct DMA buffer
* @len: new length of memory
* @gfp_mask: GFP mask
*
* If there was something allocated in the addr, free it first. If len > 0
* than try to allocate it and write the addresses back to the addr
* structure. If len == 0 set the virtual address to NULL.
*
* Returns the 0 on success or negative error code on failure.
*/
static inline int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr,
size_t len, unsigned int gfp_mask)
{
i2o_dma_free(dev, addr);
if (len)
return i2o_dma_alloc(dev, addr, len, gfp_mask);
return 0;
};
/* I2O driver (OSM) functions */
extern int i2o_driver_register(struct i2o_driver *);
extern void i2o_driver_unregister(struct i2o_driver *);
@@ -375,10 +615,11 @@ extern int i2o_device_claim_release(struct i2o_device *);
/* Exec OSM functions */
extern int i2o_exec_lct_get(struct i2o_controller *);
/* device / driver conversion functions */
/* device / driver / kobject conversion functions */
#define to_i2o_driver(drv) container_of(drv,struct i2o_driver, driver)
#define to_i2o_device(dev) container_of(dev, struct i2o_device, device)
#define to_i2o_controller(dev) container_of(dev, struct i2o_controller, device)
#define kobj_to_i2o_device(kobj) to_i2o_device(container_of(kobj, struct device, kobj))
/**
* i2o_msg_get - obtain an I2O message from the IOP
@@ -466,8 +707,10 @@ static inline struct i2o_message __iomem *i2o_msg_out_to_virt(struct
i2o_controller *c,
u32 m)
{
BUG_ON(m < c->out_queue.phys
|| m >= c->out_queue.phys + c->out_queue.len);
if (unlikely
(m < c->out_queue.phys
|| m >= c->out_queue.phys + c->out_queue.len))
return NULL;
return c->out_queue.virt + (m - c->out_queue.phys);
};
@@ -532,48 +775,6 @@ static inline void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
}
};
/**
* i2o_dma_map - Map the memory to DMA
* @dev: struct device pointer to the PCI device of the I2O controller
* @addr: i2o_dma struct which should be mapped
*
* Map the memory in addr->virt to coherent DMA memory and write the
* physical address into addr->phys.
*
* Returns 0 on success or -ENOMEM on failure.
*/
static inline int i2o_dma_map(struct device *dev, struct i2o_dma *addr)
{
if (!addr->virt)
return -EFAULT;
if (!addr->phys)
addr->phys = dma_map_single(dev, addr->virt, addr->len,
DMA_BIDIRECTIONAL);
if (!addr->phys)
return -ENOMEM;
return 0;
};
/**
* i2o_dma_unmap - Unmap the DMA memory
* @dev: struct device pointer to the PCI device of the I2O controller
* @addr: i2o_dma struct which should be unmapped
*
* Unmap the memory in addr->virt from DMA memory.
*/
static inline void i2o_dma_unmap(struct device *dev, struct i2o_dma *addr)
{
if (!addr->virt)
return;
if (addr->phys) {
dma_unmap_single(dev, addr->phys, addr->len, DMA_BIDIRECTIONAL);
addr->phys = 0;
}
};
/*
* Endian handling wrapped into the macro - keeps the core code
* cleaner.
@@ -725,6 +926,14 @@ extern void i2o_debug_state(struct i2o_controller *c);
#define I2O_CMD_SCSI_ABORT 0x83
#define I2O_CMD_SCSI_BUSRESET 0x27
/*
* Bus Adapter Class
*/
#define I2O_CMD_BUS_ADAPTER_RESET 0x85
#define I2O_CMD_BUS_RESET 0x87
#define I2O_CMD_BUS_SCAN 0x89
#define I2O_CMD_BUS_QUIESCE 0x8b
/*
* Random Block Storage Class
*/
@@ -948,7 +1157,7 @@ extern void i2o_debug_state(struct i2o_controller *c);
/* request queue sizes */
#define I2O_MAX_SECTORS 1024
#define I2O_MAX_SEGMENTS 128
#define I2O_MAX_PHYS_SEGMENTS MAX_PHYS_SEGMENTS
#define I2O_REQ_MEMPOOL_SIZE 32