📄 iscsi-probe.c
字号:
int host = -1, channel = -1, id = -1, lun = -1; sprintf(devname, "/dev/sg%d", i); if (get_device_scsi_quad(devname, &host, &channel, &id, &lun)) { if ((host == session->host_no) && (channel == session->channel) && (id == session->target_id)) { DEBUG_INIT4("iSCSI: generic device node %s = bus %d target %d LUN %d\n", devname, session->iscsi_bus, id, lun); /* ensure the LUN dir exists */ sprintf(lun_dir, "lun%d/", lun); ensure_directories_exist(session->target_link_dir, dir_mode); link = lun_dir + strlen(lun_dir); strcpy(link, "generic"); unlink(session->target_link_dir); /* remove any existing symlink */ symlink(devname, session->target_link_dir); /* make a new symlink */ } } } /* restore the session's target dir */ *lun_dir = '\0';}static void iscsi_update_cd_links(iscsi_session_t *session, int max_sr_devices, mode_t dir_mode){ int i; char devname[20]; /* we've reserved enough space in session->target_link_dir so that we can use it to build pathnames */ char *lun_dir = session->target_link_dir + strlen(session->target_link_dir); char *link; /* FIXME: can we get the number of devices supported from the running kernel? */ for (i=0; i < max_sr_devices; i++) { int host = -1, channel = -1, id = -1, lun = -1; /* FIXME: the distribution may be using /dev/sr instead of /dev/scd */ sprintf(devname, "/dev/scd%d", i); if (get_device_scsi_quad(devname, &host, &channel, &id, &lun)) { if ((host == session->host_no) && (channel == session->channel) && (id == session->target_id)) { DEBUG_INIT4("iSCSI: cdrom device node %s = bus %d target %d LUN %d\n", devname, session->iscsi_bus, id, lun); /* ensure the LUN dir exists */ sprintf(lun_dir, "lun%d/", lun); ensure_directories_exist(session->target_link_dir, dir_mode); link = lun_dir + strlen(lun_dir); strcpy(link, "cd"); unlink(session->target_link_dir); /* remove any existing symlink */ symlink(devname, session->target_link_dir); /* make a new symlink */ } } } /* restore the session's target dir */ *lun_dir = '\0';}/* compute the intersection of the LUNS detected and configured, and probe each LUN */void iscsi_probe_luns(iscsi_session_t *session, uint32_t *lun_bitmap, scsi_device_info_t *device_info){ int l; int detected = 0; int probed = 0; int activated = 0; /* try wait for our turn to probe, to keep the device node ordering as repeatable as possible */ DEBUG_INIT4("iSCSI: session %p to %s waiting to probe LUNs at %lu, probe order %d\n", session, session->log_name, jiffies, session->probe_order); if (!wait_for_probe_order(session)) { DEBUG_INIT2("iSCSI: session %p to %s couldn't probe LUNs, error waiting for probe order\n", session, session->log_name); return; } if (test_bit(SESSION_TERMINATING, &session->control_bits)) { printk("iSCSI: session %p to %s terminated while waiting to probe LUNs\n", session, session->log_name); goto done; } if (signal_pending(current)) { printk("iSCSI: session %p ioctl killed while waiting to probe LUNs\n", session); goto done; } /* make sure we're the only driver process trying to add or remove LUNs */ if (down_interruptible(&iscsi_lun_probe_mutex)) { printk("iSCSI: session %p to %s interrupted while probing LUNs\n", session, session->log_name); goto done; } /* need to set the host's max_channel, max_id, max_lun, since we * zero them in iscsi_detect in order to disable the scan that * occurs during scsi_register_host. */ session->hba->host->max_id = ISCSI_MAX_TARGET_IDS_PER_CHANNEL; session->hba->host->max_lun = ISCSI_MAX_LUNS_PER_TARGET; session->hba->host->max_channel = ISCSI_MAX_CHANNELS_PER_HBA - 1; /* convert from count to index */ wmb(); DEBUG_INIT5("iSCSI: probing LUNs for session %p to %s at %lu, probe_order %d at %lu\n", session, session->log_name, jiffies, session->probe_order, jiffies); for (l = 0; l < ISCSI_MAX_LUN; l++) { if (test_bit(SESSION_TERMINATING, &session->control_bits)) goto give_up; if (signal_pending(current)) goto give_up; if (test_bit(l, session->luns_detected)) { detected++; /* if allowed and not already activated (successfully probed), probe it */ if ((lun_bitmap[l / 32] & (1 << (l % 32))) && !test_bit(l, session->luns_activated)) { DEBUG_FLOW3("iSCSI: session %p probing LUN %d at %lu\n", session, l, jiffies); iscsi_probe_lun(session, l); probed++; if (test_bit(l, session->luns_activated)) activated++; } } } if (detected == 0) { printk("iSCSI: no LUNs detected for session %p to %s\n", session, session->log_name); } else if (LOG_ENABLED(ISCSI_LOG_INIT)) { printk("iSCSI: session %p to %s probed %d of %d LUNs detected, %d LUNs activated\n", session, session->log_name, probed, detected, activated); } /* optionally set up a symlink tree. We do this in the kernel so that we * can guard it with the lun_probe_mutex. The high-level SCSI drivers in Linux tend * to crash if a device node is opened while the Scsi_Device is still being * initialized, so we want to make sure we're not doing any probes when we open * lots of device nodes. */ if (session->target_link_dir[0] == '/') { mm_segment_t oldfs = get_fs(); set_fs( get_ds() ); /* make the target dir, so that the user can always see the target has a session, even if * LUN probing fails to find anything or no target drivers have attached. */ ensure_directories_exist(session->target_link_dir, session->dir_mode); if (device_info->max_sd_devices > 0) { DEBUG_INIT2("iSCSI: session %p updating disk links under %s\n", session, session->target_link_dir); iscsi_update_disk_links(session, device_info->max_sd_devices, device_info->max_sd_partitions, session->dir_mode); } if (device_info->max_sg_devices > 0) { DEBUG_INIT2("iSCSI: session %p updating generic links under %s\n", session, session->target_link_dir); iscsi_update_generic_links(session, device_info->max_sg_devices, session->dir_mode); } if (device_info->max_st_devices > 0) { DEBUG_INIT2("iSCSI: session %p updating tape links under %s\n", session, session->target_link_dir); iscsi_update_tape_links(session, device_info->max_st_devices, session->dir_mode); } if (device_info->max_sr_devices > 0) { DEBUG_INIT2("iSCSI: session %p updating cdrom links under %s\n", session, session->target_link_dir); iscsi_update_cd_links(session, device_info->max_sr_devices, session->dir_mode); } set_fs(oldfs); } give_up: up(&iscsi_lun_probe_mutex); done: /* clean up after wait_for_probe_order, and possibly start the next session probing */ iscsi_probe_finished(session);}typedef struct iscsi_cmnd { struct timer_list timeout; /* timeout for the command */ struct semaphore done_sem; volatile unsigned long flags; Scsi_Cmnd sc; unsigned int bufflen; uint8_t buffer[1];} iscsi_cmnd_t;#define ISCSI_CMND_DONE_LATE 0#define ISCSI_CMND_TIMED_OUT 1/* callback function for Scsi_Cmnd's generated by the iSCSI driver itself */void iscsi_done(Scsi_Cmnd *sc){ iscsi_cmnd_t *c = (iscsi_cmnd_t *)sc->buffer; if (c) { if (test_bit(ISCSI_CMND_TIMED_OUT, &c->flags)) {#if DEBUG_QUEUE if (LOG_ENABLED(ISCSI_LOG_QUEUE)) printk("iSCSI: iscsi cmnd %p to (%u %u %u %u), Cmd 0x%02x done at %lu, after timeout expired\n", c, c->sc.host->host_no, c->sc.channel, c->sc.target, c->sc.lun, c->sc.cmnd[0], jiffies);#endif set_bit(ISCSI_CMND_DONE_LATE, &c->flags); up(&c->done_sem); } else {#if DEBUG_QUEUE if (LOG_ENABLED(ISCSI_LOG_QUEUE)) printk("iSCSI: iscsi cmnd %p to (%u %u %u %u), Cmd 0x%02x done at %lu\n", c, c->sc.host->host_no, c->sc.channel, c->sc.target, c->sc.lun, c->sc.cmnd[0], jiffies);#endif up(&c->done_sem); } }}static void iscsi_times_out(unsigned long arg){ iscsi_cmnd_t *c = (iscsi_cmnd_t *)arg; if (c) { set_bit(ISCSI_CMND_TIMED_OUT, &c->flags); up(&c->done_sem); }}static int iscsi_do_cmnd(iscsi_session_t *session, iscsi_cmnd_t *c, unsigned int attempts_allowed){ int rc = 0; Scsi_Cmnd *sc = NULL; DECLARE_MIDLAYER_FLAGS; if (c->sc.host) {#if DEBUG_FLOW if (LOG_ENABLED(ISCSI_LOG_FLOW)) printk("iSCSI: session %p iscsi_do_cmnd %p to (%u %u %u %u), Cmd 0x%02x, %u retries, buffer %p, bufflen %u\n", session, c, c->sc.host->host_no, c->sc.channel, c->sc.target, c->sc.lun, c->sc.cmnd[0], attempts_allowed, c->sc.request_buffer, c->sc.request_bufflen);#endif } else { printk("iSCSI: session %p iscsi_do_cmnd %p, buffer %p, bufflen %u, host %p\n", session, c, c->sc.request_buffer, c->sc.request_bufflen, c->sc.host); return 0; } if (!c->sc.request_buffer) return 0; if (!c->sc.request_bufflen) return 0; sc = &(c->sc); init_timer(&c->timeout); sc->retries = 0; sc->allowed = attempts_allowed; retry: while (sc->retries++ < sc->allowed) { if (signal_pending(current)) return 0; if (test_bit(SESSION_TERMINATING, &session->control_bits)) return 0; sc->result = 0; memset(sc->sense_buffer, 0, sizeof(sc->sense_buffer)); memset(c->buffer, 0, c->bufflen); /* try to queue the command */ for (;;) { /* set a 30 second timer. We don't use the one in the Scsi_Cmnd * to avoid depending on the internals of the SCSI layer. */ if (c->timeout.function != NULL) { del_timer(&c->timeout); } c->flags = 0; sema_init(&c->done_sem, 0); c->timeout.data = (unsigned long)c; c->timeout.expires = jiffies + (30 * HZ); c->timeout.function = iscsi_times_out; wmb(); if (signal_pending(current)) return 0; if (test_bit(SESSION_TERMINATING, &session->control_bits)) return 0; add_timer(&c->timeout); LOCK_MIDLAYER_LOCK(session->hba->host); rc = iscsi_queue(sc, iscsi_done); UNLOCK_MIDLAYER_LOCK(session->hba->host); if (rc == 0) break; /* command queued successfully */ /* command not queued, wait a bit and try again */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(MSECS_TO_JIFFIES(10)); } DEBUG_FLOW5("iSCSI: session %p queued iscsi_cmnd %p, buffer %p, bufflen %u, scsi_done %p\n", session, c, c->sc.request_buffer, c->sc.request_bufflen, c->sc.scsi_done); /* wait til either the command completes, the timer expires, * or we get signalled. */ if (down_interruptible(&c->done_sem)) { /* if we got signalled, squash the command and give up */ iscsi_squash_cmnd(session, sc); return 0; } DEBUG_FLOW6("iSCSI: session %p hba %p host %p woken up by iscsi_cmnd %p, buffer %p, bufflen %u\n", session, session->hba, session->hba->host, c, c->sc.request_buffer, c->sc.request_bufflen); if (test_bit(ISCSI_CMND_DONE_LATE, &c->flags)) { /* command completed after the timer went off. * if it took that long, something probably went wrong, try again. */ printk("iSCSI: session %p iscsi cmnd %p to (%u %u %u %u) done late at %lu\n", session, c, sc->host->host_no, sc->channel, sc->target, sc->lun, jiffies); goto retry; } else if (test_bit(ISCSI_CMND_TIMED_OUT, &c->flags)) { /* the command timed out, squash it and retry */ printk("iSCSI: session %p iscsi cmnd %p to (%u %u %u %u) timed out at %lu\n", session, c, sc->host->host_no, sc->channel, sc->target, sc->lun, jiffies); iscsi_squash_cmnd(session, sc); goto retry; } else { /* if the command completed, clear the timer, check the result, * and decide if it needs to be retried. */ del_timer(&c->timeout); c->timeout.function = NULL; if (LOG_ENABLED(ISCSI_LOG_FLOW)) printk("iSCSI: session %p iscsi cmnd %p to (%u %u %u %u), Cmd 0x%02x, " "host byte 0x%x, SCSI status 0x%x\n", session, c, c->sc.host->host_no, c->sc.channel, c->sc.target, c->sc.lun, c->sc.cmnd[0], (sc->result >> 24) & 0xFF, sc->result & 0xFF); /* check the host byte */ switch (host_byte(sc->result)) { case DID_OK: /* no problems so far */ break; case DID_NO_CONNECT: /* give up, we can't talk to the device */ printk("iSCSI: session %p failing iscsi cmnd %p to (%u %u %u %u), Cmd 0x%02x, " "host byte 0x%x, SCSI status 0x%x\n", session, c, c->sc.host->host_no, c->sc.channel, c->sc.target, c->sc.lun, c->sc.cmnd[0], (sc->result >> 24) & 0xFF, sc->result & 0xFF); return 0; case DID_ERROR: case DID_SOFT_ERROR: case DID_ABORT:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -