static char *sg_malloc(int size) { if (size<=4096) return (char *) scsi_malloc(size); #ifdef SG_BIG_BUFF if (size<=SG_BIG_BUFF) { while(big_inuse) { interruptible_sleep_on(&big_wait); if (signal_pending(current)) return NULL; } big_inuse=1; return big_buff; } #endif return NULL; }
static int dma_setup (Scsi_Cmnd *cmd, int dir_in) { unsigned short cntr = CNTR_PDMD | CNTR_INTEN; unsigned long addr = VTOP(cmd->SCp.ptr); /* * if the physical address has the wrong alignment, or if * physical address is bad, or if it is a write and at the * end of a physical memory chunk, then allocate a bounce * buffer */ if (addr & A3000_XFER_MASK || (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual))) { HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; HDATA(a3000_host)->dma_bounce_buffer = scsi_malloc (HDATA(a3000_host)->dma_bounce_len); /* can't allocate memory; use PIO */ if (!HDATA(a3000_host)->dma_bounce_buffer) { HDATA(a3000_host)->dma_bounce_len = 0; return 1; } if (!dir_in) { /* copy to bounce buffer for a write */ if (cmd->use_sg) { memcpy (HDATA(a3000_host)->dma_bounce_buffer, cmd->SCp.ptr, cmd->SCp.this_residual); } else memcpy (HDATA(a3000_host)->dma_bounce_buffer, cmd->request_buffer, cmd->request_bufflen); } addr = VTOP(HDATA(a3000_host)->dma_bounce_buffer); } /* setup dma direction */ if (!dir_in) cntr |= CNTR_DDIR; /* remember direction */ HDATA(a3000_host)->dma_dir = dir_in; DMA(a3000_host)->CNTR = cntr; /* setup DMA *physical* address */ DMA(a3000_host)->ACR = addr; if (dir_in) /* invalidate any cache */ cache_clear (addr, cmd->SCp.this_residual); else /* push any dirty cache */ cache_push (addr, cmd->SCp.this_residual); /* start DMA */ DMA(a3000_host)->ST_DMA = 1; /* return success */ return 0; }
/* * This interface is depreciated - users should use the scsi generics * interface instead, as this is a more flexible approach to performing * generic SCSI commands on a device. */ int scsi_ioctl_send_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic) { unsigned long flags; char * buf; unsigned char cmd[12]; char * cmd_in; Scsi_Cmnd * SCpnt; Scsi_Device * SDpnt; unsigned char opcode; int inlen, outlen, cmdlen; int needed, buf_needed; int timeout, retries, result; if (!sic) return -EINVAL; /* * Verify that we can read at least this much. */ result = verify_area(VERIFY_READ, sic, sizeof (Scsi_Ioctl_Command)); if (result) return result; /* * The structure that we are passed should look like: * * struct sdata { * unsigned int inlen; * unsigned int outlen; * unsigned char cmd[]; # However many bytes are used for cmd. * unsigned char data[]; * }; */ get_user(inlen, &sic->inlen); get_user(outlen, &sic->outlen); /* * We do not transfer more than MAX_BUF with this interface. * If the user needs to transfer more data than this, they * should use scsi_generics instead. */ if( inlen > MAX_BUF ) return -EINVAL; if( outlen > MAX_BUF ) return -EINVAL; cmd_in = sic->data; get_user(opcode, cmd_in); needed = buf_needed = (inlen > outlen ? inlen : outlen); if(buf_needed){ buf_needed = (buf_needed + 511) & ~511; if (buf_needed > MAX_BUF) buf_needed = MAX_BUF; spin_lock_irqsave(&io_request_lock, flags); buf = (char *) scsi_malloc(buf_needed); spin_unlock_irqrestore(&io_request_lock, flags); if (!buf) return -ENOMEM; memset(buf, 0, buf_needed); } else buf = NULL; /* * Obtain the command from the user's address space. */ cmdlen = COMMAND_SIZE(opcode); result = verify_area(VERIFY_READ, cmd_in, cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen); if (result) return result; copy_from_user ((void *) cmd, cmd_in, cmdlen); /* * Obtain the data to be sent to the device (if any). */ copy_from_user ((void *) buf, (void *) (cmd_in + cmdlen), inlen); /* * Set the lun field to the correct value. */ cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5); switch (opcode) { case FORMAT_UNIT: timeout = FORMAT_UNIT_TIMEOUT; retries = 1; break; case START_STOP: timeout = START_STOP_TIMEOUT; retries = NORMAL_RETRIES; break; case MOVE_MEDIUM: timeout = MOVE_MEDIUM_TIMEOUT; retries = NORMAL_RETRIES; break; case READ_ELEMENT_STATUS: timeout = READ_ELEMENT_STATUS_TIMEOUT; retries = NORMAL_RETRIES; break; default: timeout = NORMAL_TIMEOUT; retries = NORMAL_RETRIES; break; } #ifndef DEBUG_NO_CMD spin_lock_irqsave(&io_request_lock, flags); SCpnt = scsi_allocate_device(NULL, dev, 1); { struct semaphore sem = MUTEX_LOCKED; SCpnt->request.sem = &sem; scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done, timeout, retries); spin_unlock_irqrestore(&io_request_lock, flags); down(&sem); SCpnt->request.sem = NULL; } /* * If there was an error condition, pass the info back to the user. */ if(SCpnt->result) { result = verify_area(VERIFY_WRITE, cmd_in, sizeof(SCpnt->sense_buffer)); if (result) return result; copy_to_user((void *) cmd_in, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer)); } else { result = verify_area(VERIFY_WRITE, cmd_in, outlen); if (result) return result; copy_to_user ((void *) cmd_in, buf, outlen); } result = SCpnt->result; spin_lock_irqsave(&io_request_lock, flags); wake_up(&SCpnt->device->device_wait); SDpnt = SCpnt->device; scsi_release_command(SCpnt); SCpnt = NULL; if (buf) scsi_free(buf, buf_needed); if(SDpnt->scsi_request_fn) (*SDpnt->scsi_request_fn)(); spin_unlock_irqrestore(&io_request_lock, flags); return result; #else { int i; printk("scsi_ioctl : device %d. command = ", dev->id); for (i = 0; i < 12; ++i) printk("%02x ", cmd[i]); printk("\nbuffer ="); for (i = 0; i < 20; ++i) printk("%02x ", buf[i]); printk("\n"); printk("inlen = %d, outlen = %d, cmdlen = %d\n", inlen, outlen, cmdlen); printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in); } return 0; #endif }
static int ioctl_command(Scsi_Device *dev, void *buffer) { char * buf; char cmd[12]; char * cmd_in; Scsi_Cmnd * SCpnt; unsigned char opcode; int inlen, outlen, cmdlen; int needed; int result; if (!buffer) return -EINVAL; inlen = get_fs_long((unsigned long *) buffer); outlen = get_fs_long( ((unsigned long *) buffer) + 1); cmd_in = (char *) ( ((int *)buffer) + 2); opcode = get_fs_byte(cmd_in); needed = (inlen > outlen ? inlen : outlen); if(needed){ needed = (needed + 511) & ~511; if (needed > MAX_BUF) needed = MAX_BUF; buf = (char *) scsi_malloc(needed); if (!buf) return -ENOMEM; } else buf = NULL; memcpy_fromfs ((void *) cmd, cmd_in, cmdlen = COMMAND_SIZE (opcode)); memcpy_fromfs ((void *) buf, (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen); cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5); #ifndef DEBUG_NO_CMD SCpnt = allocate_device(NULL, dev->index, 1); scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done, MAX_TIMEOUT, MAX_RETRIES); if (SCpnt->request.dev != 0xfffe){ SCpnt->request.waiting = current; current->state = TASK_UNINTERRUPTIBLE; while (SCpnt->request.dev != 0xfffe) schedule(); }; /* If there was an error condition, pass the info back to the user. */ if(SCpnt->result) { result = verify_area(VERIFY_WRITE, cmd_in, sizeof(SCpnt->sense_buffer)); if (result) return result; memcpy_tofs((void *) cmd_in, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer)); } else { result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF : outlen); if (result) return result; memcpy_tofs ((void *) cmd_in, buf, (outlen > MAX_BUF) ? MAX_BUF : outlen); }; result = SCpnt->result; SCpnt->request.dev = -1; /* Mark as not busy */ if (buf) scsi_free(buf, needed); wake_up(&scsi_devices[SCpnt->index].device_wait); return result; #else { int i; printk("scsi_ioctl : device %d. command = ", dev->id); for (i = 0; i < 12; ++i) printk("%02x ", cmd[i]); printk("\nbuffer ="); for (i = 0; i < 20; ++i) printk("%02x ", buf[i]); printk("\n"); printk("inlen = %d, outlen = %d, cmdlen = %d\n", inlen, outlen, cmdlen); printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in); } return 0; #endif }
int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic) { char *buf; unsigned char cmd[MAX_COMMAND_SIZE]; char *cmd_in; Scsi_Request *SRpnt; Scsi_Device *SDpnt; unsigned char opcode; unsigned int inlen, outlen, cmdlen; unsigned int needed, buf_needed; int timeout, retries, result; int data_direction; if (!sic) return -EINVAL; /* * Verify that we can read at least this much. */ if (verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command))) return -EFAULT; if(__get_user(inlen, &sic->inlen)) return -EFAULT; if(__get_user(outlen, &sic->outlen)) return -EFAULT; /* * We do not transfer more than MAX_BUF with this interface. * If the user needs to transfer more data than this, they * should use scsi_generics (sg) instead. */ if (inlen > MAX_BUF) return -EINVAL; if (outlen > MAX_BUF) return -EINVAL; cmd_in = sic->data; if(get_user(opcode, cmd_in)) return -EFAULT; needed = buf_needed = (inlen > outlen ? inlen : outlen); if (buf_needed) { buf_needed = (buf_needed + 511) & ~511; if (buf_needed > MAX_BUF) buf_needed = MAX_BUF; buf = (char *) scsi_malloc(buf_needed); if (!buf) return -ENOMEM; memset(buf, 0, buf_needed); if( inlen == 0 ) { data_direction = SCSI_DATA_READ; } else if (outlen == 0 ) { data_direction = SCSI_DATA_WRITE; } else { /* * Can this ever happen? */ data_direction = SCSI_DATA_UNKNOWN; } } else { buf = NULL; data_direction = SCSI_DATA_NONE; } /* * Obtain the command from the user's address space. */ cmdlen = COMMAND_SIZE(opcode); result = -EFAULT; if (verify_area(VERIFY_READ, cmd_in, cmdlen + inlen)) goto error; if(__copy_from_user(cmd, cmd_in, cmdlen)) goto error; /* * Obtain the data to be sent to the device (if any). */ if(copy_from_user(buf, cmd_in + cmdlen, inlen)) goto error; /* * Set the lun field to the correct value. */ if (dev->scsi_level <= SCSI_2) cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5); switch (opcode) { case SEND_DIAGNOSTIC: case FORMAT_UNIT: timeout = FORMAT_UNIT_TIMEOUT; retries = 1; break; case START_STOP: timeout = START_STOP_TIMEOUT; retries = NORMAL_RETRIES; break; case MOVE_MEDIUM: timeout = MOVE_MEDIUM_TIMEOUT; retries = NORMAL_RETRIES; break; case READ_ELEMENT_STATUS: timeout = READ_ELEMENT_STATUS_TIMEOUT; retries = NORMAL_RETRIES; break; case READ_DEFECT_DATA: timeout = READ_DEFECT_DATA_TIMEOUT; retries = 1; break; default: timeout = IOCTL_NORMAL_TIMEOUT; retries = NORMAL_RETRIES; break; } #ifndef DEBUG_NO_CMD SRpnt = scsi_allocate_request(dev); if( SRpnt == NULL ) { result = -EINTR; goto error; } SRpnt->sr_data_direction = data_direction; scsi_wait_req(SRpnt, cmd, buf, needed, timeout, retries); /* * If there was an error condition, pass the info back to the user. */ result = SRpnt->sr_result; if (SRpnt->sr_result) { int sb_len = sizeof(SRpnt->sr_sense_buffer); sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len; if (copy_to_user(cmd_in, SRpnt->sr_sense_buffer, sb_len)) result = -EFAULT; } else { if (copy_to_user(cmd_in, buf, outlen)) result = -EFAULT; } SDpnt = SRpnt->sr_device; scsi_release_request(SRpnt); SRpnt = NULL; error: if (buf) scsi_free(buf, buf_needed); return result; #else { int i; printk("scsi_ioctl : device %d. command = ", dev->id); for (i = 0; i < cmdlen; ++i) printk("%02x ", cmd[i]); printk("\nbuffer ="); for (i = 0; i < 20; ++i) printk("%02x ", buf[i]); printk("\n"); printk("inlen = %d, outlen = %d, cmdlen = %d\n", inlen, outlen, cmdlen); printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in); } return 0; #endif }