⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iscsi.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 5 页
字号:
    }    /* try to get one from the HBA's free task collection */    spin_lock(&hba->free_task_lock);    if ((task = pop_task(&hba->free_tasks))) {        atomic_dec(&hba->num_free_tasks);        atomic_inc(&hba->num_used_tasks);        hba->min_free_tasks = MIN(hba->min_free_tasks, atomic_read(&hba->num_free_tasks));    }    else {        hba->min_free_tasks = 0;    }    spin_unlock(&hba->free_task_lock);    /* otherwise, try to dynamically allocate a task */    if (!task) {        if ((task = kmalloc(sizeof(iscsi_task_t), GFP_ATOMIC))) {            atomic_inc(&hba->num_used_tasks);            DEBUG_ALLOC6("iSCSI: kmalloc task %p (active %u, used %u, free %u) for session %p to %s\n",                         task, atomic_read(&session->num_active_tasks),                          atomic_read(&hba->num_used_tasks), atomic_read(&hba->num_free_tasks),                         session, session->log_name);        }    }    if (task) {        memset(task, 0, sizeof(iscsi_task_t) );        task->itt = RSVD_TASK_TAG;        task->ttt = RSVD_TASK_TAG;        task->mgmt_itt = RSVD_TASK_TAG;        task->next = task->prev = NULL;        task->order_next = task->order_prev = NULL;        task->session = session;        init_waitqueue_head(&task->wait_q);        wmb();    }    else {        set_bit(SESSION_TASK_ALLOC_FAILED, &session->control_bits);    }    return task;}/* must be called with the HBA's free_task_lock held */static void free_task(iscsi_task_t *task){    iscsi_session_t *session = task->session;    iscsi_hba_t *hba;        if (! task) {        DEBUG_ERR0("iSCSI: free_task couldn't free NULL task\n");        return;    }    if (! session) {        DEBUG_ERR1("iSCSI: free_task couldn't find session for task %p\n", task);        return;    }    hba = session->hba;    if (!hba) {        DEBUG_ERR1("iSCSI: free_task couldn't find HBA for task %p\n", task);        return;    }    if (task->next || task->prev || task->order_next || task->order_prev) {        /* this is a memory leak, which is better than memory corruption */        printk("iSCSI: bug - tried to free task %p with prev %p, next %p, order_prev %p, order_next %p\n",               task, task->prev, task->next, task->order_prev, task->order_next);        return;    }    DEBUG_QUEUE4("iSCSI: free_task %p, itt %u, session %p, %u currently free\n",                  task, task->itt, task->session, atomic_read(&hba->num_free_tasks));    /* zero out the task settings */    task->scsi_cmnd = NULL;    task->session = NULL;    task->itt = RSVD_TASK_TAG;    task->mgmt_itt = RSVD_TASK_TAG;    task->next = task->prev = NULL;    task->order_next = task->order_prev = NULL;    atomic_set(&task->refcount, 0);        /* put the task on the session's free list */    atomic_inc(&hba->num_free_tasks);    atomic_dec(&hba->num_used_tasks);    add_task(&hba->free_tasks, task);    /* If an alloc call has failed, we need to wake up the TX thread     * now that a task is available, since there are no guarantees     * that anything else will wake it up.     */    if (test_and_clear_bit(SESSION_TASK_ALLOC_FAILED, &session->control_bits))        wake_tx_thread(TX_SCSI_COMMAND, session);}/* As long as the tx thread is the only caller, no locking * is required.  If any other thread also needs to call this, * then all callers must be changed to agree on some locking * protocol.  Currently, some but not all caller's are holding * the session->task_lock. */static inline uint32_t allocate_itt(iscsi_session_t *session){    uint32_t itt = 0;    if (session) {        itt = session->itt++;        /* iSCSI reserves 0xFFFFFFFF, this driver reserves 0 */        if (session->itt == RSVD_TASK_TAG)            session->itt = 1;    }    return itt;}/* Caller must hold the session's task_lock.  Associating a task with * a session causes it to be completed on a session drop or target * reset, along with all other session tasks, in the order they were * added to the session.  Preserving the ordering is required by the * Linux SCSI architecture.  Tasks that should not be completed to the * Linux SCSI layer (because the eh_abort_handler has or will return * SUCCESS for it) get removed from the session, though they may still * be in various task collections so that PDUs relating to them can be * sent or received. */static void add_session_task(iscsi_session_t *session, iscsi_task_t *task){    if (atomic_read(&session->num_active_tasks) == 0) {        /* session going from idle to active, pretend we just         * received something, so that the idle period before this doesn't         * cause an immediate timeout.         */        session->last_rx = jiffies;        wmb();    }    atomic_inc(&session->num_active_tasks);    /* set task info */    task->session = session;    task->itt = allocate_itt(session);    DEBUG_QUEUE5("iSCSI: task %p allocated itt %u for command %p, session %p to %s\n",                  task, task->itt, task->scsi_cmnd, session, session->log_name);    /* add it to the session task ordering list */    if (session->arrival_order.head) {        task->order_prev = session->arrival_order.tail;        task->order_next = NULL;        session->arrival_order.tail->order_next = task;        session->arrival_order.tail = task;    }    else {        task->order_prev = NULL;        task->order_next = NULL;        session->arrival_order.head = session->arrival_order.tail = task;    }    DEBUG_FLOW4("iSCSI: task %p, itt %u, added to session %p to %s\n", task, task->itt, session, session->log_name);}static int remove_session_task(iscsi_session_t *session, iscsi_task_t *task){    /* remove the task from the session's arrival_order collection */    if (task == session->arrival_order.head) {        if ((session->arrival_order.head = task->order_next))            session->arrival_order.head->order_prev = NULL;        else            session->arrival_order.tail = NULL;    }    else if (task == session->arrival_order.tail) {        session->arrival_order.tail = task->order_prev;        session->arrival_order.tail->order_next = NULL;    }    else {        /* we should always be in the middle,          * but check pointers to make sure we don't crash the kernel          * if the function is called for a task not in the session.         */        if (task->order_next && task->order_prev) {            task->order_next->order_prev = task->order_prev;            task->order_prev->order_next = task->order_next;        }        else {            DEBUG_ERR4("iSCSI: failed to remove itt %u, task %p from session %p to %s\n",                        task->itt, task, session, session->log_name);            return 0;        }    }    task->order_prev = NULL;    task->order_next = NULL;    if (atomic_dec_and_test(&session->num_active_tasks)) {        /* zero active tasks, ready to logout */        if (test_bit(SESSION_LOGOUT_REQUESTED, &session->control_bits)) {            DEBUG_INIT2("iSCSI: session %p now has no active tasks, queueing logout at %lu\n", session, jiffies);            wake_tx_thread(TX_LOGOUT, session);        }    }    return 1;}/*  * move all tasks in the session for the specified LUN into the collection. */static void move_session_tasks_for_lun(iscsi_task_collection_t *collection, iscsi_session_t *session, int lun){    iscsi_task_t *search = session->arrival_order.head;    while (search) {        iscsi_task_t *next = search->order_next;        if (search->scsi_cmnd && search->scsi_cmnd->lun == lun) {            remove_session_task(session, search);            add_task(collection, search);        }        search = next;    }}/*  * remove cmnds for the specified LUN that are in the session's cmnd queue,  * or the forced abort queue, and return a list of them. */static Scsi_Cmnd *remove_session_cmnds_for_lun(iscsi_session_t *session, int lun){    Scsi_Cmnd *cmnd = NULL;    Scsi_Cmnd *prior = NULL;    Scsi_Cmnd *head = NULL, *tail = NULL;    /* handle any commands we hid from the tx thread */    while (session->ignored_cmnd_head && (session->ignored_cmnd_head->lun == lun)) {        /* move the head */        cmnd = session->ignored_cmnd_head;        session->ignored_cmnd_head = (Scsi_Cmnd *)cmnd->host_scribble;        if (session->ignored_cmnd_head == NULL)            session->ignored_cmnd_tail = NULL;        atomic_dec(&session->num_ignored_cmnds);        if (head) {            tail->host_scribble = (unsigned char *)cmnd;            tail = cmnd;        }        else {            cmnd->host_scribble = NULL;            head = tail = cmnd;        }    }        /* we're either out of cmnds, or the head is for a different LUN */    prior = session->ignored_cmnd_head;    while (prior && (cmnd = (Scsi_Cmnd *)prior->host_scribble)) {        if (cmnd->lun == lun) {            /* splice out cmnd and move it */            prior->host_scribble = cmnd->host_scribble;            if (session->ignored_cmnd_tail == cmnd)                session->ignored_cmnd_tail = prior;            atomic_dec(&session->num_ignored_cmnds);            if (head) {                tail->host_scribble = (unsigned char *)cmnd;                tail = cmnd;            }            else {                cmnd->host_scribble = NULL;                head = tail = cmnd;            }        }        else {            prior = cmnd;        }    }    /* handle cmnds queued for the tx thread to send */    while (session->scsi_cmnd_head && (session->scsi_cmnd_head->lun == lun)) {        /* move the head */        cmnd = session->scsi_cmnd_head;        session->scsi_cmnd_head = (Scsi_Cmnd *)cmnd->host_scribble;        if (session->scsi_cmnd_head == NULL)            session->scsi_cmnd_tail = NULL;        atomic_dec(&session->num_cmnds);        if (head) {            tail->host_scribble = (unsigned char *)cmnd;            tail = cmnd;        }        else {            cmnd->host_scribble = NULL;            head = tail = cmnd;        }    }        /* we're either out of cmnds, or the head is for a different LUN */    prior = session->scsi_cmnd_head;    while (prior && (cmnd = (Scsi_Cmnd *)prior->host_scribble)) {        if (cmnd->lun == lun) {            /* splice out cmnd and move it */            prior->host_scribble = cmnd->host_scribble;            if (session->scsi_cmnd_tail == cmnd)                session->scsi_cmnd_tail = prior;            atomic_dec(&session->num_cmnds);            if (head) {                tail->host_scribble = (unsigned char *)cmnd;                tail = cmnd;            }            else {                cmnd->host_scribble = NULL;                head = tail = cmnd;            }        }        else {            prior = cmnd;        }    }    return head;}/* mark a Scsi_Cmnd as having a LUN communication failure */inline void set_lun_comm_failure(Scsi_Cmnd *sc){    sc->sense_buffer[0] = 0x70;    sc->sense_buffer[2] = NOT_READY;    sc->sense_buffer[7] = 0x6;    sc->sense_buffer[12] = 0x08;    sc->sense_buffer[13] = 0x00;}/* mark a Scsi_Cmnd as having a LUN communication failure */inline void set_data_path_failure(Scsi_Cmnd *sc){    sc->sense_buffer[0] = 0x70;    sc->sense_buffer[2] = HARDWARE_ERROR;    sc->sense_buffer[7] = 0x6;    sc->sense_buffer[12] = 0x41;    sc->sense_buffer[13] = 0x00;}/* decode common network errno values into more useful strings. * strerror would be nice right about now. */static char *iscsi_strerror(int errno){    switch (errno) {        case EIO:            return "I/O error";        case EINTR:            return "Interrupted system call";        case ENXIO:            return "No such device or address";        case EFAULT:            return "Bad address";        case EBUSY:            return "Device or resource busy";        case EINVAL:            return "Invalid argument";        case EPIPE:            return "Broken pipe";        case ENONET:            return "Machine is not on the network";        case ECOMM:            return "Communication error on send";        case EPROTO:            return "Protocol error";        case ENOTUNIQ:            return "Name not unique on network";        case ENOTSOCK:            return "Socket operation on non-socket";        case ENETDOWN:            return "Network is down";        case ENETUNREACH:            return "Network is unreachable";        case ENETRESET:            return "Network dropped connection because of reset";        case ECONNABORTED:            return "Software caused connection abort";        case ECONNRESET:            return "Connection reset by peer";        case ESHUTDOWN:            return "Cannot send after shutdown";        case ETIMEDOUT:            return "Connection timed out";        case ECONNREFUSED:            return "Connection refused";        case EHOSTDOWN:            return "Host is down";        case EHOSTUNREACH:            return "No route to host";        default:            return "";    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -