📄 scsi_target.c
字号:
if (!strcmp(st_dev_curr->template->name, the_template->name)) {# ifdef DEBUG_DEREGISTER printk("dereg...tmpt: Match found for %s%d\n", st_dev_curr->template->name, (int) st_dev_curr->id);# endif deregister_target_front_end(st_dev_curr); st_dev_curr = target_data.st_device_list; // Edward break; } else { st_dev_curr = st_dev_curr->next; if (st_dev_curr) { printk ("dereg..tmpt: Error ... no device found with the required template %s\n", the_template->name); return -1; } } } } /* remove template from device list */ for (st_current = target_data.st_target_template; st_current != NULL; st_current = st_current->next) {# ifdef DEBUG_DEREGISTER printk("Looping dereg template\n");# endif if (!strcmp(st_current->name, the_template->name)) {# ifdef DEBUG_DEREGISTER /* match found */ printk("deregister_template: template match found\n");# endif /* check if there are any devices using this template */ if (!st_current->device_usage) { /* this template can be removed */ if (!st_prev) /* First element */ target_data.st_target_template = target_data.st_target_template->next; else /* middle of the road */ st_prev->next = st_current->next; break; } else { /* A device still uses the template */ printk("scsi_target: Non-zero device usage ouch !!\n"); return -1; /* should never get here */ } } else st_prev = st_current; }# ifdef DEBUG_DEREGISTER printk("Decreasing module count\n");# endif/* Ming Zhang, mingz@ele.uri.edu */#ifndef K26 MOD_DEC_USE_COUNT;#endif return 0;}/* * register_target_front_end: * FUNCTION: to register the individual device with the mid-level * to allocate the device an device id etc * start a thread that will be responsible for the target * INPUT: pointer to a struct STD * OUTPUT: Scsi_Target_Device - if everything is okay * else NULL if there is trouble */Scsi_Target_Device *register_target_front_end(Scsi_Target_Template * tmpt){ Scsi_Target_Device *the_device; the_device = (Scsi_Target_Device *)kmalloc(sizeof(Scsi_Target_Device), GFP_KERNEL); if (!the_device) { printk ("register_target_front_end: Could not allocate space for the device\n"); return NULL; } if (!tmpt) { printk ("register_target_front_end: Cannot register NULL device template !!!\n"); return NULL; } /* fill up the struct */ the_device->template = tmpt; the_device->next = target_data.st_device_list; if (the_device->next) the_device->id = the_device->next->id + 1; else the_device->id = 0; /* first device */ target_data.st_device_list = the_device;# ifdef DEBUG_DEREGISTER printk("reg..end: device %s%d added\n", tmpt->name, (int) the_device->id);# endif /* Added by naren for proc support */#ifdef CONFIG_PROC_FS build_proc_target_dir_entries(the_device);#endif tmpt->device_usage++; return the_device;}/* * deregister_target_front_end: * FUNCTION: to allow removal of the individual device from the * midlevel * free up the device id number for future use * close the thread responsible for the target after making * sure that all existing commands have been responded to * we need to do serious error checking since this can be * called by different front-ends * CANNOT BE CALLED FROM INTERRUPT CONTEXT * INPUT: pointer to a struct STD to be removed * OUTPUT: int - 0 if everything is okay * else < 0 if there is trouble */intderegister_target_front_end(Scsi_Target_Device * the_device){ Scsi_Target_Device *curr, *previous = NULL; Target_Scsi_Cmnd *cmnd; unsigned long flags; if (!the_device) { printk ("dereg...end: cannot remove NULL devices corresponding to a NULL template\n"); return -1; } if (!the_device->template->device_usage) { printk ("dereg...end: 0 device usage and a device to deregister ... a contradiction me thinks\n"); } /* * go through the device list till we get to this device and * then remove it from the list */ for (curr = target_data.st_device_list; curr != NULL; curr = curr->next) { if (curr == the_device) {# ifdef DEBUG_DEREGISTER printk("dereg..end: We have a match\n");# endif break; } else previous = curr; } if (!curr) { /* No match found */ printk("dereg..end: No match found\n"); return -1; } /* remove it from the list */ if (previous) /* not the first device */ previous->next = curr->next; else target_data.st_device_list = curr->next; /* release the device */ if (curr->template->release) { if (curr->template->release(curr)) { printk("dereg...end: release of device failed\n"); return -1; } } /* mark all commands corresponding to this device for dequeuing */ spin_lock_irqsave(&target_data.cmd_queue_lock, flags); list_for_each_entry(cmnd, &target_data.cmd_queue, link) { if (cmnd->dev_id == curr->id) cmnd->state = ST_DEQUEUE; } spin_unlock_irqrestore(&target_data.cmd_queue_lock, flags); /* wake up scsi_target_process_thread so it can dequeue stuff */ if (atomic_read(&target_data.target_sem.count) <= 0) { up(&target_data.target_sem); } /* reduce device usage */ curr->template->device_usage--; /* freeing things */ kfree(curr); curr = NULL; return 0;}# ifdef GENERICIO# define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC)/* * signal_process_thread: This thread is responsible for receiving SIGIO * signals when SCSI generic is used for processing. This receives the * SIGIO signal, changes the state of the oldest command that is in the * ST_PROCESSING state and goes back to sleep. I found this to be * necessary because signals tend to screw up the processing of the scsi * generic commands. Hopefully this will clear things up */voidsignal_process_thread(void *param){ int i, sigioflag = 0; struct file *dev_file; Target_Scsi_Cmnd *cmd_curr; unsigned long arg; unsigned long flags; __u32 targ, lun; lock_kernel();/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 daemonize(#else daemonize(); strcpy(current->comm,#endif "signal_thread");#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 4, 18) /* * Arne Redlich, agr1@users.sourceforge.net: * This prevents the signal thread from becoming a zombie after it exits. */ reparent_to_init();#endif /* also we want to be able to receive SIGIO */ siginitsetinv(¤t->blocked, IO_SIGS); /* mark that this signal thread is alive */ target_data.signal_id = current; unlock_kernel(); printk("%s Starting pid %d\n", current->comm, current->pid); /* * we must now prepare this thread to receive the SIGIO signal * for the opened SCSI device(s) */ down_interruptible(&target_map_sem); for (targ = 0; targ < MAX_TARGETS; targ++) { for (lun = 0; lun < MAX_LUNS; lun++) { if ((dev_file = target_map[targ][lun].the_file)) { arg = dev_file->f_flags | FASYNC; lock_kernel(); /* equal to fcntl (fd, F_SETOWN, getpid()) */ dev_file->f_owner.pid = current->pid; dev_file->f_owner.uid = current->uid; dev_file->f_owner.euid = current->euid; /* equal to fcntl (fd,F_SETFL,flags|O_ASYNC) */ if ((arg ^ dev_file->f_flags) & FASYNC) { if (dev_file->f_op && dev_file->f_op->fasync) { i = dev_file->f_op->fasync(0, dev_file, (arg & FASYNC) != 0); if (i < 0) { unlock_kernel(); up(&target_map_sem); printk("si..thread: fasync returned %d\n", i); return; } } } /* required for strict SunOS emulation */ /* if (O_NONBLOCK != O_NDELAY) if (arg & O_NDELAY) arg |= O_NONBLOCK; */ dev_file->f_flags = (arg & SETFL_MASK) | (dev_file->f_flags & ~SETFL_MASK); unlock_kernel(); } } } up(&target_map_sem); while (1) { down_interruptible(&target_data.sig_thr_sem); sigioflag = 0;#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 4, 18) if (signal_pending(current)) { spin_lock_irq(¤t->sigmask_lock); if (sigismember(¤t->pending.signal, SIGIO)) {# ifdef DEBUG_SCSI_THREAD printk("SIGIO received\n");# endif sigioflag = 1; sigdelset(¤t->pending.signal, SIGIO); } recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); if (!sigioflag) { printk("si...thread: time to die\n"); break; } }#else if (signal_pending(current)) { spin_lock_irq(¤t->sighand->siglock); if (sigtestsetmask(¤t->pending.signal, sigmask(SIGIO))) {# ifdef DEBUG_SCSI_THREAD printk("SIGIO received\n");# endif sigioflag = 1; sigdelsetmask(¤t->pending.signal, sigmask(SIGIO)); } recalc_sigpending_tsk(current); spin_unlock_irq(¤t->sighand->siglock); if (!sigioflag) { printk("si...thread: time to die\n"); break; } }#endif /* change the state of all PROCESSING commands */ spin_lock_irqsave(&target_data.cmd_queue_lock, flags); list_for_each_entry(cmd_curr, &target_data.cmd_queue, link) { if (cmd_curr->state == ST_PROCESSING) { cmd_curr->state = ST_PROCESSED; /* wake up scsi_target_process_thread */ if (atomic_read(&target_data.target_sem.count) <= 0) { up(&target_data.target_sem); } } } spin_unlock_irqrestore(&target_data.cmd_queue_lock, flags); } up(&target_data.signal_sem); printk("%s Exiting pid %d\n", current->comm, current->pid);}# endif/* * scsi_target_process_thread: this is the mid-level target thread that * is responsible for processing commands. */voidscsi_target_process_thread(void *param){ int i, found;# ifdef GENERICIO mm_segment_t old_fs; struct file *dev_file;# endif struct scatterlist *st_list; Target_Scsi_Cmnd *cmd_curr; Target_Scsi_Message *msg; unsigned long flags; __u32 lun;# ifdef DISKIO Scsi_Device *this_device = NULL; struct target_map_item *this_item;# endif struct list_head *lptr, *next; lock_kernel();/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26 daemonize(#else daemonize(); strcpy(current->comm,#endif "target_thread");#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 4, 18) /* * Arne Redlich, agr1@users.sourceforge.net: * This prevents the target thread from becoming a zombie after it exits. */ reparent_to_init();#endif siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); /* mark that this target thread is alive */ target_data.thread_id = current; unlock_kernel(); printk("%s Starting pid %d\n", current->comm, current->pid); while (1) { if (down_interruptible(&target_data.target_sem)) goto scsi_thread_out;# ifdef DEBUG_SCSI_THREAD printk("%s awake (%p)\n", current->comm, current);# endif /* is message received */ while (target_data.msgq_start) { /* house keeping */ spin_lock_irqsave(&target_data.msg_lock, flags); msg = target_data.msgq_start; target_data.msgq_start = msg->next; if (!target_data.msgq_start) target_data.msgq_end = NULL; spin_unlock_irqrestore(&target_data.msg_lock, flags); /* execute function */ switch (msg->message) { case TMF_ABORT_TASK: { Target_Scsi_Cmnd *cmnd; cmnd = (Target_Scsi_Cmnd *)msg->value; found = 0; spin_lock_irqsave(&target_data.cmd_queue_lock, flags); list_for_each_entry(cmd_curr,&target_data.cmd_queue,link) { if ((cmd_curr->id == cmnd->id) && (cmd_curr->lun == cmnd->lun)) { found = 1; break; } } spin_unlock_irqrestore(&target_data.cmd_queue_lock, flags); if (found) { cmd_curr->abort_code = CMND_ABORTED; //if (cmd_curr->state != ST_PROCESSING) // cmd_curr->state = ST_DEQUEUE; if (abort_notify(msg)) { printk("%s err aborting command with id %d lun %d\n", current->comm, cmd_curr->id, cmd_curr->lun); goto scsi_thread_out; } } else printk("%s no command with id %d lun %d in list\n", current->comm, cmnd->id, cmnd->lun); break; } case TMF_LUN_RESET: { /* BAD BAD REALLY BAD */ __u64 lun = *((__u64 *)msg->value); spin_lock_irqsave(&target_data.cmd_queue_lock, flags); list_for_each_entry(cmd_curr,&target_data.cmd_queue,link) { if (cmd_curr->lun == lun) scsi_release(cmd_curr); } spin_unlock_irqrestore(&target_data.cmd_queue_lock, flags); aen_notify(msg->message, lun); break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -