diff options
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/Kconfig | 20 | ||||
-rw-r--r-- | drivers/block/Makefile | 2 | ||||
-rw-r--r-- | drivers/block/acsi_slm.c | 1032 | ||||
-rw-r--r-- | drivers/block/nbd.c | 22 | ||||
-rw-r--r-- | drivers/block/pktcdvd.c | 3 | ||||
-rw-r--r-- | drivers/block/sunvdc.c | 972 | ||||
-rw-r--r-- | drivers/block/umem.c | 58 | ||||
-rw-r--r-- | drivers/block/z2ram.c | 3 |
8 files changed, 993 insertions, 1119 deletions
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 6e23af1ecbd..c5a61571a07 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -59,17 +59,6 @@ config AMIGA_Z2RAM To compile this driver as a module, choose M here: the module will be called z2ram. -config ATARI_SLM - tristate "Atari SLM laser printer support" - depends on ATARI - help - If you have an Atari SLM laser printer, say Y to include support for - it in the kernel. Otherwise, say N. This driver is also available as - a module ( = code which can be inserted in and removed from the - running kernel whenever you want). The module will be called - acsi_slm. Be warned: the driver needs much ST-RAM and can cause - problems due to that fact! - config BLK_DEV_XD tristate "XT hard disk support" depends on ISA && ISA_DMA_API @@ -113,7 +102,7 @@ source "drivers/block/paride/Kconfig" config BLK_CPQ_DA tristate "Compaq SMART2 support" - depends on PCI + depends on PCI && VIRT_TO_BUS help This is the driver for Compaq Smart Array controllers. Everyone using these boards should say Y here. See the file @@ -423,6 +412,13 @@ config ATA_OVER_ETH This driver provides Support for ATA over Ethernet block devices like the Coraid EtherDrive (R) Storage Blade. +config SUNVDC + tristate "Sun Virtual Disk Client support" + depends on SUN_LDOMS + help + Support for virtual disk devices as a client under Sun + Logical Domains. + source "drivers/s390/block/Kconfig" endif # BLK_DEV diff --git a/drivers/block/Makefile b/drivers/block/Makefile index e5f98acc5d5..7926be8c9fb 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o -obj-$(CONFIG_ATARI_SLM) += acsi_slm.o obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o obj-$(CONFIG_BLK_DEV_RAM) += rd.o obj-$(CONFIG_BLK_DEV_LOOP) += loop.o @@ -19,6 +18,7 @@ obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o +obj-$(CONFIG_SUNVDC) += sunvdc.o obj-$(CONFIG_BLK_DEV_UMEM) += umem.o obj-$(CONFIG_BLK_DEV_NBD) += nbd.o diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c deleted file mode 100644 index 1d9d9b4f48c..00000000000 --- a/drivers/block/acsi_slm.c +++ /dev/null @@ -1,1032 +0,0 @@ -/* - * acsi_slm.c -- Device driver for the Atari SLM laser printer - * - * Copyright 1995 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - */ - -/* - -Notes: - -The major number for SLM printers is 28 (like ACSI), but as a character -device, not block device. The minor number is the number of the printer (if -you have more than one SLM; currently max. 2 (#define-constant) SLMs are -supported). The device can be opened for reading and writing. If reading it, -you get some status infos (MODE SENSE data). Writing mode is used for the data -to be printed. Some ioctls allow to get the printer status and to tune printer -modes and some internal variables. - -A special problem of the SLM driver is the timing and thus the buffering of -the print data. The problem is that all the data for one page must be present -in memory when printing starts, else --when swapping occurs-- the timing could -not be guaranteed. There are several ways to assure this: - - 1) Reserve a buffer of 1196k (maximum page size) statically by - atari_stram_alloc(). The data are collected there until they're complete, - and then printing starts. Since the buffer is reserved, no further - considerations about memory and swapping are needed. So this is the - simplest method, but it needs a lot of memory for just the SLM. - - An striking advantage of this method is (supposed the SLM_CONT_CNT_REPROG - method works, see there), that there are no timing problems with the DMA - anymore. - - 2) The other method would be to reserve the buffer dynamically each time - printing is required. I could think of looking at mem_map where the - largest unallocted ST-RAM area is, taking the area, and then extending it - by swapping out the neighbored pages, until the needed size is reached. - This requires some mm hacking, but seems possible. The only obstacle could - be pages that cannot be swapped out (reserved pages)... - - 3) Another possibility would be to leave the real data in user space and to - work with two dribble buffers of about 32k in the driver: While the one - buffer is DMAed to the SLM, the other can be filled with new data. But - to keep the timing, that requires that the user data remain in memory and - are not swapped out. Requires mm hacking, too, but maybe not so bad as - method 2). - -*/ - -#include <linux/module.h> - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/fs.h> -#include <linux/major.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/time.h> -#include <linux/mm.h> -#include <linux/slab.h> - -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/atarihw.h> -#include <asm/atariints.h> -#include <asm/atari_acsi.h> -#include <asm/atari_stdma.h> -#include <asm/atari_stram.h> -#include <asm/atari_SLM.h> - - -#undef DEBUG - -/* Define this if the page data are continuous in physical memory. That - * requires less reprogramming of the ST-DMA */ -#define SLM_CONTINUOUS_DMA - -/* Use continuous reprogramming of the ST-DMA counter register. This is - * --strictly speaking-- not allowed, Atari recommends not to look at the - * counter register while a DMA is going on. But I don't know if that applies - * only for reading the register, or also writing to it. Writing only works - * fine for me... The advantage is that the timing becomes absolutely - * uncritical: Just update each, say 200ms, the counter reg to its maximum, - * and the DMA will work until the status byte interrupt occurs. - */ -#define SLM_CONT_CNT_REPROG - -#define CMDSET_TARG_LUN(cmd,targ,lun) \ - do { \ - cmd[0] = (cmd[0] & ~0xe0) | (targ)<<5; \ - cmd[1] = (cmd[1] & ~0xe0) | (lun)<<5; \ - } while(0) - -#define START_TIMER(to) mod_timer(&slm_timer, jiffies + (to)) -#define STOP_TIMER() del_timer(&slm_timer) - - -static char slmreqsense_cmd[6] = { 0x03, 0, 0, 0, 0, 0 }; -static char slmprint_cmd[6] = { 0x0a, 0, 0, 0, 0, 0 }; -static char slminquiry_cmd[6] = { 0x12, 0, 0, 0, 0, 0x80 }; -static char slmmsense_cmd[6] = { 0x1a, 0, 0, 0, 255, 0 }; -#if 0 -static char slmmselect_cmd[6] = { 0x15, 0, 0, 0, 0, 0 }; -#endif - - -#define MAX_SLM 2 - -static struct slm { - unsigned target; /* target number */ - unsigned lun; /* LUN in target controller */ - atomic_t wr_ok; /* set to 0 if output part busy */ - atomic_t rd_ok; /* set to 0 if status part busy */ -} slm_info[MAX_SLM]; - -int N_SLM_Printers = 0; - -/* printer buffer */ -static unsigned char *SLMBuffer; /* start of buffer */ -static unsigned char *BufferP; /* current position in buffer */ -static int BufferSize; /* length of buffer for page size */ - -typedef enum { IDLE, FILLING, PRINTING } SLMSTATE; -static SLMSTATE SLMState; -static int SLMBufOwner; /* SLM# currently using the buffer */ - -/* DMA variables */ -#ifndef SLM_CONT_CNT_REPROG -static unsigned long SLMCurAddr; /* current base addr of DMA chunk */ -static unsigned long SLMEndAddr; /* expected end addr */ -static unsigned long SLMSliceSize; /* size of one DMA chunk */ -#endif -static int SLMError; - -/* wait queues */ -static DECLARE_WAIT_QUEUE_HEAD(slm_wait); /* waiting for buffer */ -static DECLARE_WAIT_QUEUE_HEAD(print_wait); /* waiting for printing finished */ - -/* status codes */ -#define SLMSTAT_OK 0x00 -#define SLMSTAT_ORNERY 0x02 -#define SLMSTAT_TONER 0x03 -#define SLMSTAT_WARMUP 0x04 -#define SLMSTAT_PAPER 0x05 -#define SLMSTAT_DRUM 0x06 -#define SLMSTAT_INJAM 0x07 -#define SLMSTAT_THRJAM 0x08 -#define SLMSTAT_OUTJAM 0x09 -#define SLMSTAT_COVER 0x0a -#define SLMSTAT_FUSER 0x0b -#define SLMSTAT_IMAGER 0x0c -#define SLMSTAT_MOTOR 0x0d -#define SLMSTAT_VIDEO 0x0e -#define SLMSTAT_SYSTO 0x10 -#define SLMSTAT_OPCODE 0x12 -#define SLMSTAT_DEVNUM 0x15 -#define SLMSTAT_PARAM 0x1a -#define SLMSTAT_ACSITO 0x1b /* driver defined */ -#define SLMSTAT_NOTALL 0x1c /* driver defined */ - -static char *SLMErrors[] = { - /* 0x00 */ "OK and ready", - /* 0x01 */ NULL, - /* 0x02 */ "ornery printer", - /* 0x03 */ "toner empty", - /* 0x04 */ "warming up", - /* 0x05 */ "paper empty", - /* 0x06 */ "drum empty", - /* 0x07 */ "input jam", - /* 0x08 */ "through jam", - /* 0x09 */ "output jam", - /* 0x0a */ "cover open", - /* 0x0b */ "fuser malfunction", - /* 0x0c */ "imager malfunction", - /* 0x0d */ "motor malfunction", - /* 0x0e */ "video malfunction", - /* 0x0f */ NULL, - /* 0x10 */ "printer system timeout", - /* 0x11 */ NULL, - /* 0x12 */ "invalid operation code", - /* 0x13 */ NULL, - /* 0x14 */ NULL, - /* 0x15 */ "invalid device number", - /* 0x16 */ NULL, - /* 0x17 */ NULL, - /* 0x18 */ NULL, - /* 0x19 */ NULL, - /* 0x1a */ "invalid parameter list", - /* 0x1b */ "ACSI timeout", - /* 0x1c */ "not all printed" -}; - -#define N_ERRORS (sizeof(SLMErrors)/sizeof(*SLMErrors)) - -/* real (driver caused) error? */ -#define IS_REAL_ERROR(x) (x > 0x10) - - -static struct { - char *name; - int w, h; -} StdPageSize[] = { - { "Letter", 2400, 3180 }, - { "Legal", 2400, 4080 }, - { "A4", 2336, 3386 }, - { "B5", 2016, 2914 } -}; - -#define N_STD_SIZES (sizeof(StdPageSize)/sizeof(*StdPageSize)) - -#define SLM_BUFFER_SIZE (2336*3386/8) /* A4 for now */ -#define SLM_DMA_AMOUNT 255 /* #sectors to program the DMA for */ - -#ifdef SLM_CONTINUOUS_DMA -# define SLM_DMA_INT_OFFSET 0 /* DMA goes until seccnt 0, no offs */ -# define SLM_DMA_END_OFFSET 32 /* 32 Byte ST-DMA FIFO */ -# define SLM_SLICE_SIZE(w) (255*512) -#else -# define SLM_DMA_INT_OFFSET 32 /* 32 Byte ST-DMA FIFO */ -# define SLM_DMA_END_OFFSET 32 /* 32 Byte ST-DMA FIFO */ -# define SLM_SLICE_SIZE(w) ((254*512)/(w/8)*(w/8)) -#endif - -/* calculate the number of jiffies to wait for 'n' bytes */ -#ifdef SLM_CONT_CNT_REPROG -#define DMA_TIME_FOR(n) 50 -#define DMA_STARTUP_TIME 0 -#else -#define DMA_TIME_FOR(n) (n/1400-1) -#define DMA_STARTUP_TIME 650 -#endif - -/***************************** Prototypes *****************************/ - -static char *slm_errstr( int stat ); -static int slm_getstats( char *buffer, int device ); -static ssize_t slm_read( struct file* file, char *buf, size_t count, loff_t - *ppos ); -static void start_print( int device ); -static irqreturn_t slm_interrupt(int irc, void *data); -static void slm_test_ready( unsigned long dummy ); -static void set_dma_addr( unsigned long paddr ); -static unsigned long get_dma_addr( void ); -static ssize_t slm_write( struct file *file, const char *buf, size_t count, - loff_t *ppos ); -static int slm_ioctl( struct inode *inode, struct file *file, unsigned int - cmd, unsigned long arg ); -static int slm_open( struct inode *inode, struct file *file ); -static int slm_release( struct inode *inode, struct file *file ); -static int slm_req_sense( int device ); -static int slm_mode_sense( int device, char *buffer, int abs_flag ); -#if 0 -static int slm_mode_select( int device, char *buffer, int len, int - default_flag ); -#endif -static int slm_get_pagesize( int device, int *w, int *h ); - -/************************* End of Prototypes **************************/ - - -static DEFINE_TIMER(slm_timer, slm_test_ready, 0, 0); - -static const struct file_operations slm_fops = { - .owner = THIS_MODULE, - .read = slm_read, - .write = slm_write, - .ioctl = slm_ioctl, - .open = slm_open, - .release = slm_release, -}; - - -/* ---------------------------------------------------------------------- */ -/* Status Functions */ - - -static char *slm_errstr( int stat ) - -{ char *p; - static char str[22]; - - stat &= 0x1f; - if (stat >= 0 && stat < N_ERRORS && (p = SLMErrors[stat])) - return( p ); - sprintf( str, "unknown status 0x%02x", stat ); - return( str ); -} - - -static int slm_getstats( char *buffer, int device ) - -{ int len = 0, stat, i, w, h; - unsigned char buf[256]; - - stat = slm_mode_sense( device, buf, 0 ); - if (IS_REAL_ERROR(stat)) - return( -EIO ); - -#define SHORTDATA(i) ((buf[i] << 8) | buf[i+1]) -#define BOOLDATA(i,mask) ((buf[i] & mask) ? "on" : "off") - - w = SHORTDATA( 3 ); - h = SHORTDATA( 1 ); - - len += sprintf( buffer+len, "Status\t\t%s\n", - slm_errstr( stat ) ); - len += sprintf( buffer+len, "Page Size\t%dx%d", - w, h ); - - for( i = 0; i < N_STD_SIZES; ++i ) { - if (w == StdPageSize[i].w && h == StdPageSize[i].h) - break; - } - if (i < N_STD_SIZES) - len += sprintf( buffer+len, " (%s)", StdPageSize[i].name ); - buffer[len++] = '\n'; - - len += sprintf( buffer+len, "Top/Left Margin\t%d/%d\n", - SHORTDATA( 5 ), SHORTDATA( 7 ) ); - len += sprintf( buffer+len, "Manual Feed\t%s\n", - BOOLDATA( 9, 0x01 ) ); - len += sprintf( buffer+len, "Input Select\t%d\n", - (buf[9] >> 1) & 7 ); - len += sprintf( buffer+len, "Auto Select\t%s\n", - BOOLDATA( 9, 0x10 ) ); - len += sprintf( buffer+len, "Prefeed Paper\t%s\n", - BOOLDATA( 9, 0x20 ) ); - len += sprintf( buffer+len, "Thick Pixels\t%s\n", - BOOLDATA( 9, 0x40 ) ); - len += sprintf( buffer+len, "H/V Resol.\t%d/%d dpi\n", - SHORTDATA( 12 ), SHORTDATA( 10 ) ); - len += sprintf( buffer+len, "System Timeout\t%d\n", - buf[14] ); - len += sprintf( buffer+len, "Scan Time\t%d\n", - SHORTDATA( 15 ) ); - len += sprintf( buffer+len, "Page Count\t%d\n", - SHORTDATA( 17 ) ); - len += sprintf( buffer+len, "In/Out Cap.\t%d/%d\n", - SHORTDATA( 19 ), SHORTDATA( 21 ) ); - len += sprintf( buffer+len, "Stagger Output\t%s\n", - BOOLDATA( 23, 0x01 ) ); - len += sprintf( buffer+len, "Output Select\t%d\n", - (buf[23] >> 1) & 7 ); - len += sprintf( buffer+len, "Duplex Print\t%s\n", - BOOLDATA( 23, 0x10 ) ); - len += sprintf( buffer+len, "Color Sep.\t%s\n", - BOOLDATA( 23, 0x20 ) ); - - return( len ); -} - - -static ssize_t slm_read( struct file *file, char *buf, size_t count, - loff_t *ppos ) - -{ - struct inode *node = file->f_path.dentry->d_inode; - unsigned long page; - int length; - int end; - - if (!(page = __get_free_page( GFP_KERNEL ))) - return( -ENOMEM ); - - length = slm_getstats( (char *)page, iminor(node) ); - if (length < 0) { - count = length; - goto out; - } - if (file->f_pos >= length) { - count = 0; - goto out; - } - if (count + file->f_pos > length) - count = length - file->f_pos; - end = count + file->f_pos; - if (copy_to_user(buf, (char *)page + file->f_pos, count)) { - count = -EFAULT; - goto out; - } - file->f_pos = end; -out: free_page( page ); - return( count ); -} - - -/* ---------------------------------------------------------------------- */ -/* Printing */ - - -static void start_print( int device ) - -{ struct slm *sip = &slm_info[device]; - unsigned char *cmd; - unsigned long paddr; - int i; - - stdma_lock( slm_interrupt, NULL ); - - CMDSET_TARG_LUN( slmprint_cmd, sip->target, sip->lun ); - cmd = slmprint_cmd; - paddr = virt_to_phys( SLMBuffer ); - dma_cache_maintenance( paddr, virt_to_phys(BufferP)-paddr, 1 ); - DISABLE_IRQ(); - - /* Low on A1 */ - dma_wd.dma_mode_status = 0x88; - MFPDELAY(); - - /* send the command bytes except the last */ - for( i = 0; i < 5; ++i ) { - DMA_LONG_WRITE( *cmd++, 0x8a ); - udelay(20); - if (!acsi_wait_for_IRQ( HZ/2 )) { - SLMError = 1; - return; /* timeout */ - } - } - /* last command byte */ - DMA_LONG_WRITE( *cmd++, 0x82 ); - MFPDELAY(); - /* set DMA address */ - set_dma_addr( paddr ); - /* program DMA for write and select sector counter reg */ - dma_wd.dma_mode_status = 0x192; - MFPDELAY(); - /* program for 255*512 bytes and start DMA */ - DMA_LONG_WRITE( SLM_DMA_AMOUNT, 0x112 ); - -#ifndef SLM_CONT_CNT_REPROG - SLMCurAddr = paddr; - SLMEndAddr = paddr + SLMSliceSize + SLM_DMA_INT_OFFSET; -#endif - START_TIMER( DMA_STARTUP_TIME + DMA_TIME_FOR( SLMSliceSize )); -#if !defined(SLM_CONT_CNT_REPROG) && defined(DEBUG) - printk( "SLM: CurAddr=%#lx EndAddr=%#lx timer=%ld\n", - SLMCurAddr, SLMEndAddr, DMA_TIME_FOR( SLMSliceSize ) ); -#endif - - ENABLE_IRQ(); -} - - -/* Only called when an error happened or at the end of a page */ - -static irqreturn_t slm_interrupt(int irc, void *data) - -{ unsigned long addr; - int stat; - - STOP_TIMER(); - addr = get_dma_addr(); - stat = acsi_getstatus(); - SLMError = (stat < 0) ? SLMSTAT_ACSITO : - (addr < virt_to_phys(BufferP)) ? SLMSTAT_NOTALL : - stat; - - dma_wd.dma_mode_status = 0x80; - MFPDELAY(); -#ifdef DEBUG - printk( "SLM: interrupt, addr=%#lx, error=%d\n", addr, SLMError ); -#endif - - wake_up( &print_wait ); - stdma_release(); - ENABLE_IRQ(); - return IRQ_HANDLED; -} - - -static void slm_test_ready( unsigned long dummy ) - -{ -#ifdef SLM_CONT_CNT_REPROG - /* program for 255*512 bytes again */ - dma_wd.fdc_acces_seccount = SLM_DMA_AMOUNT; - START_TIMER( DMA_TIME_FOR(0) ); -#ifdef DEBUG - printk( "SLM: reprogramming timer for %d jiffies, addr=%#lx\n", - DMA_TIME_FOR(0), get_dma_addr() ); -#endif - -#else /* !SLM_CONT_CNT_REPROG */ - - unsigned long flags, addr; - int d, ti; -#ifdef DEBUG - struct timeval start_tm, end_tm; - int did_wait = 0; -#endif - - local_irq_save(flags); - - addr = get_dma_addr(); - if ((d = SLMEndAddr - addr) > 0) { - local_irq_restore(flags); - - /* slice not yet finished, decide whether to start another timer or to - * busy-wait */ - ti = DMA_TIME_FOR( d ); - if (ti > 0) { -#ifdef DEBUG - printk( "SLM: reprogramming timer for %d jiffies, rest %d bytes\n", - ti, d ); -#endif - START_TIMER( ti ); - return; - } - /* wait for desired end address to be reached */ -#ifdef DEBUG - do_gettimeofday( &start_tm ); - did_wait = 1; -#endif - local_irq_disable(); - while( get_dma_addr() < SLMEndAddr ) - barrier(); - } - - /* slice finished, start next one */ - SLMCurAddr += SLMSliceSize; - -#ifdef SLM_CONTINUOUS_DMA - /* program for 255*512 bytes again */ - dma_wd.fdc_acces_seccount = SLM_DMA_AMOUNT; -#else - /* set DMA address; - * add 2 bytes for the ones in the SLM controller FIFO! */ - set_dma_addr( SLMCurAddr + 2 ); - /* toggle DMA to write and select sector counter reg */ - dma_wd.dma_mode_status = 0x92; - MFPDELAY(); - dma_wd.dma_mode_status = 0x192; - MFPDELAY(); - /* program for 255*512 bytes and start DMA */ - DMA_LONG_WRITE( SLM_DMA_AMOUNT, 0x112 ); -#endif - - local_irq_restore(flags); - -#ifdef DEBUG - if (did_wait) { - int ms; - do_gettimeofday( &end_tm ); - ms = (end_tm.tv_sec*1000000+end_tm.tv_usec) - - (start_tm.tv_sec*1000000+start_tm.tv_usec); - printk( "SLM: did %ld.%ld ms busy waiting for %d bytes\n", - ms/1000, ms%1000, d ); - } - else - printk( "SLM: didn't wait (!)\n" ); -#endif - - if ((unsigned char *)PTOV( SLMCurAddr + SLMSliceSize ) >= BufferP) { - /* will be last slice, no timer necessary */ -#ifdef DEBUG - printk( "SLM: CurAddr=%#lx EndAddr=%#lx last slice -> no timer\n", - SLMCurAddr, SLMEndAddr ); -#endif - } - else { - /* not last slice */ - SLMEndAddr = SLMCurAddr + SLMSliceSize + SLM_DMA_INT_OFFSET; - START_TIMER( DMA_TIME_FOR( SLMSliceSize )); -#ifdef DEBUG - printk( "SLM: CurAddr=%#lx EndAddr=%#lx timer=%ld\n", - SLMCurAddr, SLMEndAddr, DMA_TIME_FOR( SLMSliceSize ) ); -#endif - } -#endif /* SLM_CONT_CNT_REPROG */ -} - - -static void set_dma_addr( unsigned long paddr ) - -{ unsigned long flags; - - local_irq_save(flags); - dma_wd.dma_lo = (unsigned char)paddr; - paddr >>= 8; - MFPDELAY(); - dma_wd.dma_md = (unsigned char)paddr; - paddr >>= 8; - MFPDELAY(); - if (ATARIHW_PRESENT( EXTD_DMA )) - st_dma_ext_dmahi = (unsigned short)paddr; - else - dma_wd.dma_hi = (unsigned char)paddr; - MFPDELAY(); - local_irq_restore(flags); -} - - -static unsigned long get_dma_addr( void ) - -{ unsigned long addr; - - addr = dma_wd.dma_lo & 0xff; - MFPDELAY(); - addr |= (dma_wd.dma_md & 0xff) << 8; - MFPDELAY(); - addr |= (dma_wd.dma_hi & 0xff) << 16; - MFPDELAY(); - - return( addr ); -} - - -static ssize_t slm_write( struct file *file, const char *buf, size_t count, - loff_t *ppos ) - -{ - struct inode *node = file->f_path.dentry->d_inode; - int device = iminor(node); - int n, filled, w, h; - - while( SLMState == PRINTING || - (SLMState == FILLING && SLMBufOwner != device) ) { - interruptible_sleep_on( &slm_wait ); - if (signal_pending(current)) - return( -ERESTARTSYS ); - } - if (SLMState == IDLE) { - /* first data of page: get current page size */ - if (slm_get_pagesize( device, &w, &h )) - return( -EIO ); - BufferSize = w*h/8; - if (BufferSize > SLM_BUFFER_SIZE) - return( -ENOMEM ); - - SLMState = FILLING; - SLMBufOwner = device; - } - - n = count; - filled = BufferP - SLMBuffer; - if (filled + n > BufferSize) - n = BufferSize - filled; - - if (copy_from_user(BufferP, buf, n)) - return -EFAULT; - BufferP += n; - filled += n; - - if (filled == BufferSize) { - /* Check the paper size again! The user may have switched it in the - * time between starting the data and finishing them. Would end up in - * a trashy page... */ - if (slm_get_pagesize( device, &w, &h )) - return( -EIO ); - if (BufferSize != w*h/8) { - printk( KERN_NOTICE "slm%d: page size changed while printing\n", - device ); - return( -EAGAIN ); - } - - SLMState = PRINTING; - /* choose a slice size that is a multiple of the line size */ -#ifndef SLM_CONT_CNT_REPROG - SLMSliceSize = SLM_SLICE_SIZE(w); -#endif - - start_print( device ); - sleep_on( &print_wait ); - if (SLMError && IS_REAL_ERROR(SLMError)) { - printk( KERN_ERR "slm%d: %s\n", device, slm_errstr(SLMError) ); - n = -EIO; - } - - SLMState = IDLE; - BufferP = SLMBuffer; - wake_up_interruptible( &slm_wait ); - } - - return( n ); -} - - -/* ---------------------------------------------------------------------- */ -/* ioctl Functions */ - - -static int slm_ioctl( struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg ) - -{ int device = iminor(inode), err; - - /* I can think of setting: - * - manual feed - * - paper format - * - copy count - * - ... - * but haven't implemented that yet :-) - * BTW, has anybody better docs about the MODE SENSE/MODE SELECT data? - */ - switch( cmd ) { - - case SLMIORESET: /* reset buffer, i.e. empty the buffer */ - if (!(file->f_mode & 2)) - return( -EINVAL ); - if (SLMState == PRINTING) - return( -EBUSY ); - SLMState = IDLE; - BufferP = SLMBuffer; - wake_up_interruptible( &slm_wait ); - return( 0 ); - - case SLMIOGSTAT: { /* get status */ - int stat; - char *str; - - stat = slm_req_sense( device ); - if (arg) { - str = slm_errstr( stat ); - if (put_user(stat, - (long *)&((struct SLM_status *)arg)->stat)) - return -EFAULT; - if (copy_to_user( ((struct SLM_status *)arg)->str, str, - strlen(str) + 1)) - return -EFAULT; - } - return( stat ); - } - - case SLMIOGPSIZE: { /* get paper size */ - int w, h; - - if ((err = slm_get_pagesize( device, &w, &h ))) return( err ); - - if (put_user(w, (long *)&((struct SLM_paper_size *)arg)->width)) - return -EFAULT; - if (put_user(h, (long *)&((struct SLM_paper_size *)arg)->height)) - return -EFAULT; - return( 0 ); - } - - case SLMIOGMFEED: /* get manual feed */ - return( -EINVAL ); - - case SLMIOSPSIZE: /* set paper size */ - return( -EINVAL ); - - case SLMIOSMFEED: /* set manual feed */ - return( -EINVAL ); - - } - return( -EINVAL ); -} - - -/* ---------------------------------------------------------------------- */ -/* Opening and Closing */ - - -static int slm_open( struct inode *inode, struct file *file ) - -{ int device; - struct slm *sip; - - device = iminor(inode); - if (device >= N_SLM_Printers) - return( -ENXIO ); - sip = &slm_info[device]; - - if (file->f_mode & 2) { - /* open for writing is exclusive */ - if ( !atomic_dec_and_test(&sip->wr_ok) ) { - atomic_inc(&sip->wr_ok); - return( -EBUSY ); - } - } - if (file->f_mode & 1) { - /* open for reading is exclusive */ - if ( !atomic_dec_and_test(&sip->rd_ok) ) { - atomic_inc(&sip->rd_ok); - return( -EBUSY ); - } - } - - return( 0 ); -} - - -static int slm_release( struct inode *inode, struct file *file ) - -{ int device; - struct slm *sip; - - device = iminor(inode); - sip = &slm_info[device]; - - if (file->f_mode & 2) - atomic_inc( &sip->wr_ok ); - if (file->f_mode & 1) - atomic_inc( &sip->rd_ok ); - - return( 0 ); -} - - -/* ---------------------------------------------------------------------- */ -/* ACSI Primitives for the SLM */ - - -static int slm_req_sense( int device ) - -{ int stat, rv; - struct slm *sip = &slm_info[device]; - - stdma_lock( NULL, NULL ); - - CMDSET_TARG_LUN( slmreqsense_cmd, sip->target, sip->lun ); - if (!acsicmd_nodma( slmreqsense_cmd, 0 ) || - (stat = acsi_getstatus()) < 0) - rv = SLMSTAT_ACSITO; - else - rv = stat & 0x1f; - - ENABLE_IRQ(); - stdma_release(); - return( rv ); -} - - -static int slm_mode_sense( int device, char *buffer, int abs_flag ) - -{ unsigned char stat, len; - int rv = 0; - struct slm *sip = &slm_info[device]; - - stdma_lock( NULL, NULL ); - - CMDSET_TARG_LUN( slmmsense_cmd, sip->target, sip->lun ); - slmmsense_cmd[5] = abs_flag ? 0x80 : 0; - if (!acsicmd_nodma( slmmsense_cmd, 0 )) { - rv = SLMSTAT_ACSITO; - goto the_end; - } - - if (!acsi_extstatus( &stat, 1 )) { - acsi_end_extstatus(); - rv = SLMSTAT_ACSITO; - goto the_end; - } - - if (!acsi_extstatus( &len, 1 )) { - acsi_end_extstatus(); - rv = SLMSTAT_ACSITO; - goto the_end; - } - buffer[0] = len; - if (!acsi_extstatus( buffer+1, len )) { - acsi_end_extstatus(); - rv = SLMSTAT_ACSITO; - goto the_end; - } - - acsi_end_extstatus(); - rv = stat & 0x1f; - - the_end: - ENABLE_IRQ(); - stdma_release(); - return( rv ); -} - - -#if 0 -/* currently unused */ -static int slm_mode_select( int device, char *buffer, int len, - int default_flag ) - -{ int stat, rv; - struct slm *sip = &slm_info[device]; - - stdma_lock( NULL, NULL ); - - CMDSET_TARG_LUN( slmmselect_cmd, sip->target, sip->lun ); - slmmselect_cmd[5] = default_flag ? 0x80 : 0; - if (!acsicmd_nodma( slmmselect_cmd, 0 )) { - rv = SLMSTAT_ACSITO; - goto the_end; - } - - if (!default_flag) { - unsigned char c = len; - if (!acsi_extcmd( &c, 1 )) { - rv = SLMSTAT_ACSITO; - goto the_end; - } - if (!acsi_extcmd( buffer, len )) { - rv = SLMSTAT_ACSITO; - goto the_end; - } - } - - stat = acsi_getstatus(); - rv = (stat < 0 ? SLMSTAT_ACSITO : stat); - - the_end: - ENABLE_IRQ(); - stdma_release(); - return( rv ); -} -#endif - - -static int slm_get_pagesize( int device, int *w, int *h ) - -{ char buf[256]; - int stat; - - stat = slm_mode_sense( device, buf, 0 ); - ENABLE_IRQ(); - stdma_release(); - - if (stat != SLMSTAT_OK) - return( -EIO ); - - *w = (buf[3] << 8) | buf[4]; - *h = (buf[1] << 8) | buf[2]; - return( 0 ); -} - - -/* ---------------------------------------------------------------------- */ -/* Initialization */ - - -int attach_slm( int target, int lun ) - -{ static int did_register; - int len; - - if (N_SLM_Printers >= MAX_SLM) { - printk( KERN_WARNING "Too much SLMs\n" ); - return( 0 ); - } - - /* do an INQUIRY */ - udelay(100); - CMDSET_TARG_LUN( slminquiry_cmd, target, lun ); - if (!acsicmd_nodma( slminquiry_cmd, 0 )) { - inq_timeout: - printk( KERN_ERR "SLM inquiry command timed out.\n" ); - inq_fail: - acsi_end_extstatus(); - return( 0 ); - } - /* read status and header of return data */ - if (!acsi_extstatus( SLMBuffer, 6 )) - goto inq_timeout; - - if (SLMBuffer[1] != 2) { /* device type == printer? */ - printk( KERN_ERR "SLM inquiry returned device type != printer\n" ); - goto inq_fail; - } - len = SLMBuffer[5]; - - /* read id string */ - if (!acsi_extstatus( SLMBuffer, len )) - goto inq_timeout; - acsi_end_extstatus(); - SLMBuffer[len] = 0; - - if (!did_register) { - did_register = 1; - } - - slm_info[N_SLM_Printers].target = target; - slm_info[N_SLM_Printers].lun = lun; - atomic_set(&slm_info[N_SLM_Printers].wr_ok, 1 ); - atomic_set(&slm_info[N_SLM_Printers].rd_ok, 1 ); - - printk( KERN_INFO " Printer: %s\n", SLMBuffer ); - printk( KERN_INFO "Detected slm%d at id %d lun %d\n", - N_SLM_Printers, target, lun ); - N_SLM_Printers++; - return( 1 ); -} - -int slm_init( void ) - -{ - int i; - if (register_chrdev( ACSI_MAJOR, "slm", &slm_fops )) { - printk( KERN_ERR "Unable to get major %d for ACSI SLM\n", ACSI_MAJOR ); - return -EBUSY; - } - - if (!(SLMBuffer = atari_stram_alloc( SLM_BUFFER_SIZE, "SLM" ))) { - printk( KERN_ERR "Unable to get SLM ST-Ram buffer.\n" ); - unregister_chrdev( ACSI_MAJOR, "slm" ); - return -ENOMEM; - } - BufferP = SLMBuffer; - SLMState = IDLE; - - return 0; -} - -#ifdef MODULE - -/* from acsi.c */ -void acsi_attach_SLMs( int (*attach_func)( int, int ) ); - -int init_module(void) -{ - int err; - - if ((err = slm_init())) - return( err ); - /* This calls attach_slm() for every target/lun where acsi.c detected a - * printer */ - acsi_attach_SLMs( attach_slm ); - return( 0 ); -} - -void cleanup_module(void) -{ - if (unregister_chrdev( ACSI_MAJOR, "slm" ) != 0) - printk( KERN_ERR "acsi_slm: cleanup_module failed\n"); - atari_stram_free( SLMBuffer ); -} -#endif diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index c575fb1d585..c1295102409 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -122,17 +122,12 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size, int result; struct msghdr msg; struct kvec iov; - unsigned long flags; - sigset_t oldset; + sigset_t blocked, oldset; /* Allow interception of SIGKILL only * Don't allow other signals to interrupt the transmission */ - spin_lock_irqsave(¤t->sighand->siglock, flags); - oldset = current->blocked; - sigfillset(¤t->blocked); - sigdelsetmask(¤t->blocked, sigmask(SIGKILL)); - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); + siginitsetinv(&blocked, sigmask(SIGKILL)); + sigprocmask(SIG_SETMASK, &blocked, &oldset); do { sock->sk->sk_allocation = GFP_NOIO; @@ -151,11 +146,9 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size, if (signal_pending(current)) { siginfo_t info; - spin_lock_irqsave(¤t->sighand->siglock, flags); printk(KERN_WARNING "nbd (pid %d: %s) got signal %d\n", - current->pid, current->comm, - dequeue_signal(current, ¤t->blocked, &info)); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); + current->pid, current->comm, + dequeue_signal_lock(current, ¤t->blocked, &info)); result = -EINTR; break; } @@ -169,10 +162,7 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size, buf += result; } while (size > 0); - spin_lock_irqsave(¤t->sighand->siglock, flags); - current->blocked = oldset; - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); + sigprocmask(SIG_SETMASK, &oldset, NULL); return result; } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index ce64e86d6ff..7c294a40002 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1652,9 +1652,6 @@ static int kcdrwd(void *foobar) } } - if (signal_pending(current)) { - flush_signals(current); - } if (kthread_should_stop()) break; } diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c new file mode 100644 index 00000000000..0f5e3caf85d --- /dev/null +++ b/drivers/block/sunvdc.c @@ -0,0 +1,972 @@ +/* sunvdc.c: Sun LDOM Virtual Disk Client. + * + * Copyright (C) 2007 David S. Miller <davem@davemloft.net> + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/blkdev.h> +#include <linux/hdreg.h> +#include <linux/genhd.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/list.h> + +#include <asm/vio.h> +#include <asm/ldc.h> + +#define DRV_MODULE_NAME "sunvdc" +#define PFX DRV_MODULE_NAME ": " +#define DRV_MODULE_VERSION "1.0" +#define DRV_MODULE_RELDATE "June 25, 2007" + +static char version[] __devinitdata = + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; +MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); +MODULE_DESCRIPTION("Sun LDOM virtual disk client driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); + +#define VDC_TX_RING_SIZE 256 + +#define WAITING_FOR_LINK_UP 0x01 +#define WAITING_FOR_TX_SPACE 0x02 +#define WAITING_FOR_GEN_CMD 0x04 +#define WAITING_FOR_ANY -1 + +struct vdc_req_entry { + struct request *req; +}; + +struct vdc_port { + struct vio_driver_state vio; + + struct vdc *vp; + + struct gendisk *disk; + + struct vdc_completion *cmp; + + u64 req_id; + u64 seq; + struct vdc_req_entry rq_arr[VDC_TX_RING_SIZE]; + + unsigned long ring_cookies; + + u64 max_xfer_size; + u32 vdisk_block_size; + + /* The server fills these in for us in the disk attribute + * ACK packet. + */ + u64 operations; + u32 vdisk_size; + u8 vdisk_type; + u8 dev_no; + + char disk_name[32]; + + struct vio_disk_geom geom; + struct vio_disk_vtoc label; + + struct list_head list; +}; + +static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio) +{ + return container_of(vio, struct vdc_port, vio); +} + +struct vdc { + /* Protects prot_list. */ + spinlock_t lock; + + struct vio_dev *dev; + + struct list_head port_list; +}; + +/* Ordered from largest major to lowest */ +static struct vio_version vdc_versions[] = { + { .major = 1, .minor = 0 }, +}; + +#define VDCBLK_NAME "vdisk" +static int vdc_major; +#define PARTITION_SHIFT 3 + +static inline u32 vdc_tx_dring_avail(struct vio_dring_state *dr) +{ + return vio_dring_avail(dr, VDC_TX_RING_SIZE); +} + +static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct gendisk *disk = bdev->bd_disk; + struct vdc_port *port = disk->private_data; + + geo->heads = (u8) port->geom.num_hd; + geo->sectors = (u8) port->geom.num_sec; + geo->cylinders = port->geom.num_cyl; + + return 0; +} + +static struct block_device_operations vdc_fops = { + .owner = THIS_MODULE, + .getgeo = vdc_getgeo, +}; + +static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for) +{ + if (vio->cmp && + (waiting_for == -1 || + vio->cmp->waiting_for == waiting_for)) { + vio->cmp->err = err; + complete(&vio->cmp->com); + vio->cmp = NULL; + } +} + +static void vdc_handshake_complete(struct vio_driver_state *vio) +{ + vdc_finish(vio, 0, WAITING_FOR_LINK_UP); +} + +static int vdc_handle_unknown(struct vdc_port *port, void *arg) +{ + struct vio_msg_tag *pkt = arg; + + printk(KERN_ERR PFX "Received unknown msg [%02x:%02x:%04x:%08x]\n", + pkt->type, pkt->stype, pkt->stype_env, pkt->sid); + printk(KERN_ERR PFX "Resetting connection.\n"); + + ldc_disconnect(port->vio.lp); + + return -ECONNRESET; +} + +static int vdc_send_attr(struct vio_driver_state *vio) +{ + struct vdc_port *port = to_vdc_port(vio); + struct vio_disk_attr_info pkt; + + memset(&pkt, 0, sizeof(pkt)); + + pkt.tag.type = VIO_TYPE_CTRL; + pkt.tag.stype = VIO_SUBTYPE_INFO; + pkt.tag.stype_env = VIO_ATTR_INFO; + pkt.tag.sid = vio_send_sid(vio); + + pkt.xfer_mode = VIO_DRING_MODE; + pkt.vdisk_block_size = port->vdisk_block_size; + pkt.max_xfer_size = port->max_xfer_size; + + viodbg(HS, "SEND ATTR xfer_mode[0x%x] blksz[%u] max_xfer[%lu]\n", + pkt.xfer_mode, pkt.vdisk_block_size, pkt.max_xfer_size); + + return vio_ldc_send(&port->vio, &pkt, sizeof(pkt)); +} + +static int vdc_handle_attr(struct vio_driver_state *vio, void *arg) +{ + struct vdc_port *port = to_vdc_port(vio); + struct vio_disk_attr_info *pkt = arg; + + viodbg(HS, "GOT ATTR stype[0x%x] ops[%lx] disk_size[%lu] disk_type[%x] " + "xfer_mode[0x%x] blksz[%u] max_xfer[%lu]\n", + pkt->tag.stype, pkt->operations, + pkt->vdisk_size, pkt->vdisk_type, + pkt->xfer_mode, pkt->vdisk_block_size, + pkt->max_xfer_size); + + if (pkt->tag.stype == VIO_SUBTYPE_ACK) { + switch (pkt->vdisk_type) { + case VD_DISK_TYPE_DISK: + case VD_DISK_TYPE_SLICE: + break; + + default: + printk(KERN_ERR PFX "%s: Bogus vdisk_type 0x%x\n", + vio->name, pkt->vdisk_type); + return -ECONNRESET; + } + + if (pkt->vdisk_block_size > port->vdisk_block_size) { + printk(KERN_ERR PFX "%s: BLOCK size increased " + "%u --> %u\n", + vio->name, + port->vdisk_block_size, pkt->vdisk_block_size); + return -ECONNRESET; + } + + port->operations = pkt->operations; + port->vdisk_size = pkt->vdisk_size; + port->vdisk_type = pkt->vdisk_type; + if (pkt->max_xfer_size < port->max_xfer_size) + port->max_xfer_size = pkt->max_xfer_size; + port->vdisk_block_size = pkt->vdisk_block_size; + return 0; + } else { + printk(KERN_ERR PFX "%s: Attribute NACK\n", vio->name); + + return -ECONNRESET; + } +} + +static void vdc_end_special(struct vdc_port *port, struct vio_disk_desc *desc) +{ + int err = desc->status; + + vdc_finish(&port->vio, -err, WAITING_FOR_GEN_CMD); +} + +static void vdc_end_request(struct request *req, int uptodate, int num_sectors) +{ + if (end_that_request_first(req, uptodate, num_sectors)) + return; + add_disk_randomness(req->rq_disk); + end_that_request_last(req, uptodate); +} + +static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr, + unsigned int index) +{ + struct vio_disk_desc *desc = vio_dring_entry(dr, index); + struct vdc_req_entry *rqe = &port->rq_arr[index]; + struct request *req; + + if (unlikely(desc->hdr.state != VIO_DESC_DONE)) + return; + + ldc_unmap(port->vio.lp, desc->cookies, desc->ncookies); + desc->hdr.state = VIO_DESC_FREE; + dr->cons = (index + 1) & (VDC_TX_RING_SIZE - 1); + + req = rqe->req; + if (req == NULL) { + vdc_end_special(port, desc); + return; + } + + rqe->req = NULL; + + vdc_end_request(req, !desc->status, desc->size >> 9); + + if (blk_queue_stopped(port->disk->queue)) + blk_start_queue(port->disk->queue); +} + +static int vdc_ack(struct vdc_port *port, void *msgbuf) +{ + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + struct vio_dring_data *pkt = msgbuf; + + if (unlikely(pkt->dring_ident != dr->ident || + pkt->start_idx != pkt->end_idx || + pkt->start_idx >= VDC_TX_RING_SIZE)) + return 0; + + vdc_end_one(port, dr, pkt->start_idx); + + return 0; +} + +static int vdc_nack(struct vdc_port *port, void *msgbuf) +{ + /* XXX Implement me XXX */ + return 0; +} + +static void vdc_event(void *arg, int event) +{ + struct vdc_port *port = arg; + struct vio_driver_state *vio = &port->vio; + unsigned long flags; + int err; + + spin_lock_irqsave(&vio->lock, flags); + + if (unlikely(event == LDC_EVENT_RESET || + event == LDC_EVENT_UP)) { + vio_link_state_change(vio, event); + spin_unlock_irqrestore(&vio->lock, flags); + return; + } + + if (unlikely(event != LDC_EVENT_DATA_READY)) { + printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event); + spin_unlock_irqrestore(&vio->lock, flags); + return; + } + + err = 0; + while (1) { + union { + struct vio_msg_tag tag; + u64 raw[8]; + } msgbuf; + + err = ldc_read(vio->lp, &msgbuf, sizeof(msgbuf)); + if (unlikely(err < 0)) { + if (err == -ECONNRESET) + vio_conn_reset(vio); + break; + } + if (err == 0) + break; + viodbg(DATA, "TAG [%02x:%02x:%04x:%08x]\n", + msgbuf.tag.type, + msgbuf.tag.stype, + msgbuf.tag.stype_env, + msgbuf.tag.sid); + err = vio_validate_sid(vio, &msgbuf.tag); + if (err < 0) + break; + + if (likely(msgbuf.tag.type == VIO_TYPE_DATA)) { + if (msgbuf.tag.stype == VIO_SUBTYPE_ACK) + err = vdc_ack(port, &msgbuf); + else if (msgbuf.tag.stype == VIO_SUBTYPE_NACK) + err = vdc_nack(port, &msgbuf); + else + err = vdc_handle_unknown(port, &msgbuf); + } else if (msgbuf.tag.type == VIO_TYPE_CTRL) { + err = vio_control_pkt_engine(vio, &msgbuf); + } else { + err = vdc_handle_unknown(port, &msgbuf); + } + if (err < 0) + break; + } + if (err < 0) + vdc_finish(&port->vio, err, WAITING_FOR_ANY); + spin_unlock_irqrestore(&vio->lock, flags); +} + +static int __vdc_tx_trigger(struct vdc_port *port) +{ + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + struct vio_dring_data hdr = { + .tag = { + .type = VIO_TYPE_DATA, + .stype = VIO_SUBTYPE_INFO, + .stype_env = VIO_DRING_DATA, + .sid = vio_send_sid(&port->vio), + }, + .dring_ident = dr->ident, + .start_idx = dr->prod, + .end_idx = dr->prod, + }; + int err, delay; + + hdr.seq = dr->snd_nxt; + delay = 1; + do { + err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr)); + if (err > 0) { + dr->snd_nxt++; + break; + } + udelay(delay); + if ((delay <<= 1) > 128) + delay = 128; + } while (err == -EAGAIN); + + return err; +} + +static int __send_request(struct request *req) +{ + struct vdc_port *port = req->rq_disk->private_data; + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + struct scatterlist sg[port->ring_cookies]; + struct vdc_req_entry *rqe; + struct vio_disk_desc *desc; + unsigned int map_perm; + int nsg, err, i; + u64 len; + u8 op; + + map_perm = LDC_MAP_SHADOW | LDC_MAP_DIRECT | LDC_MAP_IO; + + if (rq_data_dir(req) == READ) { + map_perm |= LDC_MAP_W; + op = VD_OP_BREAD; + } else { + map_perm |= LDC_MAP_R; + op = VD_OP_BWRITE; + } + + nsg = blk_rq_map_sg(req->q, req, sg); + + len = 0; + for (i = 0; i < nsg; i++) + len += sg[i].length; + + if (unlikely(vdc_tx_dring_avail(dr) < 1)) { + blk_stop_queue(port->disk->queue); + err = -ENOMEM; + goto out; + } + + desc = vio_dring_cur(dr); + + err = ldc_map_sg(port->vio.lp, sg, nsg, + desc->cookies, port->ring_cookies, + map_perm); + if (err < 0) { + printk(KERN_ERR PFX "ldc_map_sg() failure, err=%d.\n", err); + return err; + } + + rqe = &port->rq_arr[dr->prod]; + rqe->req = req; + + desc->hdr.ack = VIO_ACK_ENABLE; + desc->req_id = port->req_id; + desc->operation = op; + if (port->vdisk_type == VD_DISK_TYPE_DISK) { + desc->slice = 2; + } else { + desc->slice = 0; + } + desc->status = ~0; + desc->offset = (req->sector << 9) / port->vdisk_block_size; + desc->size = len; + desc->ncookies = err; + + /* This has to be a non-SMP write barrier because we are writing + * to memory which is shared with the peer LDOM. + */ + wmb(); + desc->hdr.state = VIO_DESC_READY; + + err = __vdc_tx_trigger(port); + if (err < 0) { + printk(KERN_ERR PFX "vdc_tx_trigger() failure, err=%d\n", err); + } else { + port->req_id++; + dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1); + } +out: + + return err; +} + +static void do_vdc_request(request_queue_t *q) +{ + while (1) { + struct request *req = elv_next_request(q); + + if (!req) + break; + + blkdev_dequeue_request(req); + if (__send_request(req) < 0) + vdc_end_request(req, 0, req->hard_nr_sectors); + } +} + +static int generic_request(struct vdc_port *port, u8 op, void *buf, int len) +{ + struct vio_dring_state *dr; + struct vio_completion comp; + struct vio_disk_desc *desc; + unsigned int map_perm; + unsigned long flags; + int op_len, err; + void *req_buf; + + if (!(((u64)1 << ((u64)op - 1)) & port->operations)) + return -EOPNOTSUPP; + + switch (op) { + case VD_OP_BREAD: + case VD_OP_BWRITE: + default: + return -EINVAL; + + case VD_OP_FLUSH: + op_len = 0; + map_perm = 0; + break; + + case VD_OP_GET_WCE: + op_len = sizeof(u32); + map_perm = LDC_MAP_W; + break; + + case VD_OP_SET_WCE: + op_len = sizeof(u32); + map_perm = LDC_MAP_R; + break; + + case VD_OP_GET_VTOC: + op_len = sizeof(struct vio_disk_vtoc); + map_perm = LDC_MAP_W; + break; + + case VD_OP_SET_VTOC: + op_len = sizeof(struct vio_disk_vtoc); + map_perm = LDC_MAP_R; + break; + + case VD_OP_GET_DISKGEOM: + op_len = sizeof(struct vio_disk_geom); + map_perm = LDC_MAP_W; + break; + + case VD_OP_SET_DISKGEOM: + op_len = sizeof(struct vio_disk_geom); + map_perm = LDC_MAP_R; + break; + + case VD_OP_SCSICMD: + op_len = 16; + map_perm = LDC_MAP_RW; + break; + + case VD_OP_GET_DEVID: + op_len = sizeof(struct vio_disk_devid); + map_perm = LDC_MAP_W; + break; + + case VD_OP_GET_EFI: + case VD_OP_SET_EFI: + return -EOPNOTSUPP; + break; + }; + + map_perm |= LDC_MAP_SHADOW | LDC_MAP_DIRECT | LDC_MAP_IO; + + op_len = (op_len + 7) & ~7; + req_buf = kzalloc(op_len, GFP_KERNEL); + if (!req_buf) + return -ENOMEM; + + if (len > op_len) + len = op_len; + + if (map_perm & LDC_MAP_R) + memcpy(req_buf, buf, len); + + spin_lock_irqsave(&port->vio.lock, flags); + + dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + + /* XXX If we want to use this code generically we have to + * XXX handle TX ring exhaustion etc. + */ + desc = vio_dring_cur(dr); + + err = ldc_map_single(port->vio.lp, req_buf, op_len, + desc->cookies, port->ring_cookies, + map_perm); + if (err < 0) { + spin_unlock_irqrestore(&port->vio.lock, flags); + kfree(req_buf); + return err; + } + + init_completion(&comp.com); + comp.waiting_for = WAITING_FOR_GEN_CMD; + port->vio.cmp = ∁ + + desc->hdr.ack = VIO_ACK_ENABLE; + desc->req_id = port->req_id; + desc->operation = op; + desc->slice = 0; + desc->status = ~0; + desc->offset = 0; + desc->size = op_len; + desc->ncookies = err; + + /* This has to be a non-SMP write barrier because we are writing + * to memory which is shared with the peer LDOM. + */ + wmb(); + desc->hdr.state = VIO_DESC_READY; + + err = __vdc_tx_trigger(port); + if (err >= 0) { + port->req_id++; + dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1); + spin_unlock_irqrestore(&port->vio.lock, flags); + + wait_for_completion(&comp.com); + err = comp.err; + } else { + port->vio.cmp = NULL; + spin_unlock_irqrestore(&port->vio.lock, flags); + } + + if (map_perm & LDC_MAP_W) + memcpy(buf, req_buf, len); + + kfree(req_buf); + + return err; +} + +static int __devinit vdc_alloc_tx_ring(struct vdc_port *port) +{ + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + unsigned long len, entry_size; + int ncookies; + void *dring; + + entry_size = sizeof(struct vio_disk_desc) + + (sizeof(struct ldc_trans_cookie) * port->ring_cookies); + len = (VDC_TX_RING_SIZE * entry_size); + + ncookies = VIO_MAX_RING_COOKIES; + dring = ldc_alloc_exp_dring(port->vio.lp, len, + dr->cookies, &ncookies, + (LDC_MAP_SHADOW | + LDC_MAP_DIRECT | + LDC_MAP_RW)); + if (IS_ERR(dring)) + return PTR_ERR(dring); + + dr->base = dring; + dr->entry_size = entry_size; + dr->num_entries = VDC_TX_RING_SIZE; + dr->prod = dr->cons = 0; + dr->pending = VDC_TX_RING_SIZE; + dr->ncookies = ncookies; + + return 0; +} + +static void vdc_free_tx_ring(struct vdc_port *port) +{ + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + + if (dr->base) { + ldc_free_exp_dring(port->vio.lp, dr->base, + (dr->entry_size * dr->num_entries), + dr->cookies, dr->ncookies); + dr->base = NULL; + dr->entry_size = 0; + dr->num_entries = 0; + dr->pending = 0; + dr->ncookies = 0; + } +} + +static int probe_disk(struct vdc_port *port) +{ + struct vio_completion comp; + struct request_queue *q; + struct gendisk *g; + int err; + + init_completion(&comp.com); + comp.err = 0; + comp.waiting_for = WAITING_FOR_LINK_UP; + port->vio.cmp = ∁ + + vio_port_up(&port->vio); + + wait_for_completion(&comp.com); + if (comp.err) + return comp.err; + + err = generic_request(port, VD_OP_GET_VTOC, + &port->label, sizeof(port->label)); + if (err < 0) { + printk(KERN_ERR PFX "VD_OP_GET_VTOC returns error %d\n", err); + return err; + } + + err = generic_request(port, VD_OP_GET_DISKGEOM, + &port->geom, sizeof(port->geom)); + if (err < 0) { + printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns " + "error %d\n", err); + return err; + } + + port->vdisk_size = ((u64)port->geom.num_cyl * + (u64)port->geom.num_hd * + (u64)port->geom.num_sec); + + q = blk_init_queue(do_vdc_request, &port->vio.lock); + if (!q) { + printk(KERN_ERR PFX "%s: Could not allocate queue.\n", + port->vio.name); + return -ENOMEM; + } + g = alloc_disk(1 << PARTITION_SHIFT); + if (!g) { + printk(KERN_ERR PFX "%s: Could not allocate gendisk.\n", + port->vio.name); + blk_cleanup_queue(q); + return -ENOMEM; + } + + port->disk = g; + + blk_queue_max_hw_segments(q, port->ring_cookies); + blk_queue_max_phys_segments(q, port->ring_cookies); + blk_queue_max_sectors(q, port->max_xfer_size); + g->major = vdc_major; + g->first_minor = port->dev_no << PARTITION_SHIFT; + strcpy(g->disk_name, port->disk_name); + + g->fops = &vdc_fops; + g->queue = q; + g->private_data = port; + g->driverfs_dev = &port->vio.vdev->dev; + + set_capacity(g, port->vdisk_size); + + printk(KERN_INFO PFX "%s: %u sectors (%u MB)\n", + g->disk_name, + port->vdisk_size, (port->vdisk_size >> (20 - 9))); + + add_disk(g); + + return 0; +} + +static struct ldc_channel_config vdc_ldc_cfg = { + .event = vdc_event, + .mtu = 64, + .mode = LDC_MODE_UNRELIABLE, +}; + +static struct vio_driver_ops vdc_vio_ops = { + .send_attr = vdc_send_attr, + .handle_attr = vdc_handle_attr, + .handshake_complete = vdc_handshake_complete, +}; + +static int __devinit vdc_port_probe(struct vio_dev *vdev, + const struct vio_device_id *id) +{ + struct mdesc_handle *hp; + struct vdc_port *port; + unsigned long flags; + struct vdc *vp; + const u64 *port_id; + int err; + + vp = dev_get_drvdata(vdev->dev.parent); + if (!vp) { + printk(KERN_ERR PFX "Cannot find port parent vdc.\n"); + return -ENODEV; + } + + hp = mdesc_grab(); + + port_id = mdesc_get_property(hp, vdev->mp, "id", NULL); + err = -ENODEV; + if (!port_id) { + printk(KERN_ERR PFX "Port lacks id property.\n"); + goto err_out_release_mdesc; + } + if ((*port_id << PARTITION_SHIFT) & ~(u64)MINORMASK) { + printk(KERN_ERR PFX "Port id [%lu] too large.\n", *port_id); + goto err_out_release_mdesc; + } + + port = kzalloc(sizeof(*port), GFP_KERNEL); + err = -ENOMEM; + if (!port) { + printk(KERN_ERR PFX "Cannot allocate vdc_port.\n"); + goto err_out_release_mdesc; + } + + port->vp = vp; + port->dev_no = *port_id; + + if (port->dev_no >= 26) + snprintf(port->disk_name, sizeof(port->disk_name), + VDCBLK_NAME "%c%c", + 'a' + (port->dev_no / 26) - 1, + 'a' + (port->dev_no % 26)); + else + snprintf(port->disk_name, sizeof(port->disk_name), + VDCBLK_NAME "%c", 'a' + (port->dev_no % 26)); + + err = vio_driver_init(&port->vio, vdev, VDEV_DISK, + vdc_versions, ARRAY_SIZE(vdc_versions), + &vdc_vio_ops, port->disk_name); + if (err) + goto err_out_free_port; + + port->vdisk_block_size = 512; + port->max_xfer_size = ((128 * 1024) / port->vdisk_block_size); + port->ring_cookies = ((port->max_xfer_size * + port->vdisk_block_size) / PAGE_SIZE) + 2; + + err = vio_ldc_alloc(&port->vio, &vdc_ldc_cfg, port); + if (err) + goto err_out_free_port; + + err = vdc_alloc_tx_ring(port); + if (err) + goto err_out_free_ldc; + + err = probe_disk(port); + if (err) + goto err_out_free_tx_ring; + + INIT_LIST_HEAD(&port->list); + + spin_lock_irqsave(&vp->lock, flags); + list_add(&port->list, &vp->port_list); + spin_unlock_irqrestore(&vp->lock, flags); + + dev_set_drvdata(&vdev->dev, port); + + mdesc_release(hp); + + return 0; + +err_out_free_tx_ring: + vdc_free_tx_ring(port); + +err_out_free_ldc: + vio_ldc_free(&port->vio); + +err_out_free_port: + kfree(port); + +err_out_release_mdesc: + mdesc_release(hp); + return err; +} + +static int vdc_port_remove(struct vio_dev *vdev) +{ + struct vdc_port *port = dev_get_drvdata(&vdev->dev); + + if (port) { + del_timer_sync(&port->vio.timer); + + vdc_free_tx_ring(port); + vio_ldc_free(&port->vio); + + dev_set_drvdata(&vdev->dev, NULL); + + kfree(port); + } + return 0; +} + +static struct vio_device_id vdc_port_match[] = { + { + .type = "vdc-port", + }, + {}, +}; +MODULE_DEVICE_TABLE(vio, vdc_match); + +static struct vio_driver vdc_port_driver = { + .id_table = vdc_port_match, + .probe = vdc_port_probe, + .remove = vdc_port_remove, + .driver = { + .name = "vdc_port", + .owner = THIS_MODULE, + } +}; + +static int __devinit vdc_probe(struct vio_dev *vdev, + const struct vio_device_id *id) +{ + static int vdc_version_printed; + struct vdc *vp; + + if (vdc_version_printed++ == 0) + printk(KERN_INFO "%s", version); + + vp = kzalloc(sizeof(struct vdc), GFP_KERNEL); + if (!vp) + return -ENOMEM; + + spin_lock_init(&vp->lock); + vp->dev = vdev; + INIT_LIST_HEAD(&vp->port_list); + + dev_set_drvdata(&vdev->dev, vp); + + return 0; +} + +static int vdc_remove(struct vio_dev *vdev) +{ + + struct vdc *vp = dev_get_drvdata(&vdev->dev); + + if (vp) { + kfree(vp); + dev_set_drvdata(&vdev->dev, NULL); + } + return 0; +} + +static struct vio_device_id vdc_match[] = { + { + .type = "block", + }, + {}, +}; +MODULE_DEVICE_TABLE(vio, vdc_match); + +static struct vio_driver vdc_driver = { + .id_table = vdc_match, + .probe = vdc_probe, + .remove = vdc_remove, + .driver = { + .name = "vdc", + .owner = THIS_MODULE, + } +}; + +static int __init vdc_init(void) +{ + int err; + + err = register_blkdev(0, VDCBLK_NAME); + if (err < 0) + goto out_err; + + vdc_major = err; + err = vio_register_driver(&vdc_driver); + if (err) + goto out_unregister_blkdev; + + err = vio_register_driver(&vdc_port_driver); + if (err) + goto out_unregister_vdc; + + return 0; + +out_unregister_vdc: + vio_unregister_driver(&vdc_driver); + +out_unregister_blkdev: + unregister_blkdev(vdc_major, VDCBLK_NAME); + vdc_major = 0; + +out_err: + return err; +} + +static void __exit vdc_exit(void) +{ + vio_unregister_driver(&vdc_port_driver); + vio_unregister_driver(&vdc_driver); + unregister_blkdev(vdc_major, VDCBLK_NAME); +} + +module_init(vdc_init); +module_exit(vdc_exit); diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 6f5d6203d72..dec74bd2349 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -105,12 +105,6 @@ struct cardinfo { unsigned long csr_base; unsigned char __iomem *csr_remap; unsigned long csr_len; -#ifdef CONFIG_MM_MAP_MEMORY - unsigned long mem_base; - unsigned char __iomem *mem_remap; - unsigned long mem_len; -#endif - unsigned int win_size; /* PCI window size */ unsigned int mm_size; /* size in kbytes */ @@ -872,10 +866,6 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i card->csr_base = pci_resource_start(dev, 0); card->csr_len = pci_resource_len(dev, 0); -#ifdef CONFIG_MM_MAP_MEMORY - card->mem_base = pci_resource_start(dev, 1); - card->mem_len = pci_resource_len(dev, 1); -#endif printk(KERN_INFO "Micro Memory(tm) controller #%d found at %02x:%02x (PCI Mem Module (Battery Backup))\n", card->card_number, dev->bus->number, dev->devfn); @@ -903,27 +893,6 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i printk(KERN_INFO "MM%d: CSR 0x%08lx -> 0x%p (0x%lx)\n", card->card_number, card->csr_base, card->csr_remap, card->csr_len); -#ifdef CONFIG_MM_MAP_MEMORY - if (!request_mem_region(card->mem_base, card->mem_len, "Micro Memory")) { - printk(KERN_ERR "MM%d: Unable to request memory region\n", card->card_number); - ret = -ENOMEM; - - goto failed_req_mem; - } - - if (!(card->mem_remap = ioremap(card->mem_base, cards->mem_len))) { - printk(KERN_ERR "MM%d: Unable to remap memory region\n", card->card_number); - ret = -ENOMEM; - - goto failed_remap_mem; - } - - printk(KERN_INFO "MM%d: MEM 0x%8lx -> 0x%8lx (0x%lx)\n", card->card_number, - card->mem_base, card->mem_remap, card->mem_len); -#else - printk(KERN_INFO "MM%d: MEM area not remapped (CONFIG_MM_MAP_MEMORY not set)\n", - card->card_number); -#endif switch(card->dev->device) { case 0x5415: card->flags |= UM_FLAG_NO_BYTE_STATUS | UM_FLAG_NO_BATTREG; @@ -1091,12 +1060,6 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i card->mm_pages[1].desc, card->mm_pages[1].page_dma); failed_magic: -#ifdef CONFIG_MM_MAP_MEMORY - iounmap(card->mem_remap); - failed_remap_mem: - release_mem_region(card->mem_base, card->mem_len); - failed_req_mem: -#endif iounmap(card->csr_remap); failed_remap_csr: release_mem_region(card->csr_base, card->csr_len); @@ -1116,10 +1079,6 @@ static void mm_pci_remove(struct pci_dev *dev) tasklet_kill(&card->tasklet); iounmap(card->csr_remap); release_mem_region(card->csr_base, card->csr_len); -#ifdef CONFIG_MM_MAP_MEMORY - iounmap(card->mem_remap); - release_mem_region(card->mem_base, card->mem_len); -#endif free_irq(card->irq, card); if (card->mm_pages[0].desc) @@ -1133,23 +1092,18 @@ static void mm_pci_remove(struct pci_dev *dev) blk_cleanup_queue(card->queue); } -static const struct pci_device_id mm_pci_ids[] = { { - .vendor = PCI_VENDOR_ID_MICRO_MEMORY, - .device = PCI_DEVICE_ID_MICRO_MEMORY_5415CN, - }, { - .vendor = PCI_VENDOR_ID_MICRO_MEMORY, - .device = PCI_DEVICE_ID_MICRO_MEMORY_5425CN, - }, { - .vendor = PCI_VENDOR_ID_MICRO_MEMORY, - .device = PCI_DEVICE_ID_MICRO_MEMORY_6155, - }, { +static const struct pci_device_id mm_pci_ids[] = { + {PCI_DEVICE(PCI_VENDOR_ID_MICRO_MEMORY,PCI_DEVICE_ID_MICRO_MEMORY_5415CN)}, + {PCI_DEVICE(PCI_VENDOR_ID_MICRO_MEMORY,PCI_DEVICE_ID_MICRO_MEMORY_5425CN)}, + {PCI_DEVICE(PCI_VENDOR_ID_MICRO_MEMORY,PCI_DEVICE_ID_MICRO_MEMORY_6155)}, + { .vendor = 0x8086, .device = 0xB555, .subvendor= 0x1332, .subdevice= 0x5460, .class = 0x050000, .class_mask= 0, - }, { /* end: all zeroes */ } + }, { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(pci, mm_pci_ids); diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 7cc2685ca84..2abf94cc313 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -44,9 +44,6 @@ extern int m68k_realnum_memory; extern struct mem_info m68k_memory[NUM_MEMINFO]; -#define TRUE (1) -#define FALSE (0) - #define Z2MINOR_COMBINED (0) #define Z2MINOR_Z2ONLY (1) #define Z2MINOR_CHIPONLY (2) |