📄 iscsi-probe.c
字号:
case DID_BUS_BUSY: case DID_PARITY: case DID_TIME_OUT: case DID_RESET: default: if (LOG_ENABLED(ISCSI_LOG_INIT)) 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); /* some sort of problem, possibly retry */ goto retry; } /* check the SCSI status byte. Note, Linux values are right-shifted once compared to the SCSI spec */ switch (status_byte(sc->result)) { case GOOD: case COMMAND_TERMINATED:#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,19) /* make sure we got enough of a response */ if (sc->resid && ((iscsi_expected_data_length(sc) - sc->resid) < sc->underflow)) { /* try again */ if (LOG_ENABLED(ISCSI_LOG_INIT)) printk("iSCSI: session %p iscsi cmnd %p to (%u %u %u %u), Cmd 0x%02x, " "residual %u, retrying to get %u bytes desired\n", session, c, c->sc.host->host_no, c->sc.channel, c->sc.target, c->sc.lun, c->sc.cmnd[0], sc->resid, sc->underflow); goto retry; }#endif /* all done */ return 1; case BUSY: /* device is busy, try again later */ case QUEUE_FULL: /* tagged queuing device has a full queue, wait a bit and try again. */ attempts_allowed++; if (attempts_allowed > 100) { printk("iSCSI: session %p iscsi cmnd %p to (%u %u %u %u), Cmd 0x%02x, SCSI status 0x%x, out of retries\n", session, c, c->sc.host->host_no, c->sc.channel, c->sc.target, c->sc.lun, c->sc.cmnd[0], sc->result & 0xFF); return 0; } set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(MSECS_TO_JIFFIES(10)); goto retry; case CONDITION_GOOD: case INTERMEDIATE_GOOD: case INTERMEDIATE_C_GOOD: /* we should never get the linked command return codes */ case RESERVATION_CONFLICT: /* this is probably never going to happen for INQUIRY or REPORT_LUNS, but retry if it does */ printk("iSCSI: session %p iscsi_do_cmnd %p SCSI status 0x%x at %lu, retrying\n", session, c, sc->result & 0xFF, jiffies); goto retry; case CHECK_CONDITION: /* look at the sense. If it's illegal request, don't bother retrying the command */ if ((sc->sense_buffer[0] & 0x70) == 0x70) { switch (SENSE_KEY(sc->sense_buffer)) { case ILLEGAL_REQUEST: printk("iSCSI: session %p iscsi cmnd %p to (%u %u %u %u), Cmd 0x%02x, illegal request\n", session, c, c->sc.host->host_no, c->sc.channel, c->sc.target, c->sc.lun, c->sc.cmnd[0]); return 0; default: /* possibly retry */ if (LOG_ENABLED(ISCSI_LOG_INIT)) printk("iSCSI: session %p iscsi cmnd %p to (%u %u %u %u), Cmd 0x%02x with sense, retrying\n", session, c, c->sc.host->host_no, c->sc.channel, c->sc.target, c->sc.lun, c->sc.cmnd[0]); goto retry; } } goto retry; default: printk("iSCSI: session %p iscsi_do_cmnd %p unexpected SCSI status 0x%x at %lu\n", session, c, sc->result & 0xFF, jiffies); return 0; } } } if (LOG_ENABLED(ISCSI_LOG_INIT)) printk("iSCSI: session %p iscsi_do_cmnd %p SCSI status 0x%x, out of retries at %lu\n", session, c, sc->result & 0xFF, jiffies); return 0;}static void make_report_luns(Scsi_Cmnd *sc, uint32_t max_entries){ uint32_t length = 8 + (max_entries * 8); /* 8 byte header plus 8 bytes per LUN */ sc->cmd_len = 10; sc->request_bufflen = length; sc->underflow = 8; /* need at least the length */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,19) sc->resid = 0;#endif /* CDB */ memset(sc->cmnd, 0, sizeof(sc->cmnd)); sc->cmnd[0] = REPORT_LUNS; sc->cmnd[1] = 0; sc->cmnd[2] = 0; /* either reserved or select report in various versions of SCSI-3 */ sc->cmnd[3] = 0; sc->cmnd[4] = 0; sc->cmnd[5] = 0; sc->cmnd[6] = (length >> 24) & 0xFF; sc->cmnd[7] = (length >> 16) & 0xFF; sc->cmnd[8] = (length >> 8) & 0xFF; sc->cmnd[9] = (length) & 0xFF;}static void make_inquiry(Scsi_Cmnd *sc, int lun0_scsi_level){ sc->cmd_len = 6; sc->request_bufflen = 255; if (sc->lun == 0) sc->underflow = 3; /* we need at least the peripheral code and SCSI version */ else sc->underflow = 1; /* we need at least the peripheral code */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,19) sc->resid = 0;#endif memset(sc->cmnd, 0, sizeof(sc->cmnd)); sc->cmnd[0] = INQUIRY; if (lun0_scsi_level >= 0x3) sc->cmnd[1] = 0; /* reserved in SCSI-3 and higher */ else sc->cmnd[1] = (sc->lun << 5) & 0xe0; sc->cmnd[2] = 0; sc->cmnd[3] = 0; sc->cmnd[4] = 255; /* length */ sc->cmnd[5] = 0; }/* scan for LUNs */void iscsi_detect_luns(iscsi_session_t *session){ int l; iscsi_cmnd_t *c = NULL; Scsi_Cmnd *sc = NULL; int lun0_scsi_level = 0; size_t cmd_size = sizeof(iscsi_cmnd_t); unsigned int bufflen = 0; uint32_t length = 0; uint32_t last_luns = 0; uint32_t luns = 32; /* start small to avoid bugs in REPORT_LUNS handling */ int report_luns_failed = 0; /* need enough buffer space for replies to INQUIRY and REPORT_LUNS */ if ((8 + (ISCSI_MAX_LUN * 8)) < 255) bufflen = 255; else bufflen = (ISCSI_MAX_LUN * 8) + 8; cmd_size += bufflen; c = kmalloc(cmd_size, GFP_KERNEL); if (!c) { printk("iSCSI: session %p iscsi_detect_luns couldn't allocate a Scsi_Cmnd\n", session); return; } /* initialize */ memset(c, 0, cmd_size); sema_init(&c->done_sem, 0); c->bufflen = bufflen;#if DEBUG_ALLOC if (LOG_ENABLED(ISCSI_LOG_ALLOC)) printk("iSCSI: session %p hba %p host %p allocated iscsi cmnd %p, size %d, buffer %p, bufflen %u, end %p\n", session, session->hba, session->hba->host, c, cmd_size, c->buffer, c->bufflen, c->buffer + c->bufflen);#endif /* fill in the basic required info in the Scsi_Cmnd */ sc = &(c->sc); sc->host = session->hba->host; sc->channel = session->channel; sc->target = session->target_id; sc->lun = 0; sc->use_sg = 0; sc->request_buffer = c->buffer; sc->request_bufflen = c->bufflen; sc->scsi_done = iscsi_done; /* save a pointer to the iscsi_cmnd in the Scsi_Cmnd, so that iscsi_done can use it */ sc->buffer = (void *)c; do { if (signal_pending(current)) { DEBUG_INIT1("iSCSI: session %p detect LUNs aborted by signal\n", session); goto done; } if (test_bit(SESSION_TERMINATING, &session->control_bits)) goto done; /* send a REPORT_LUNS to LUN 0. If it works, we know the LUNs. */ last_luns = luns; make_report_luns(sc, luns); if (iscsi_do_cmnd(session, c, 6)) { uint8_t *lun_list = c->buffer + 8; int luns_listed; /* get the list length the target has */ length |= c->buffer[0] << 24; length |= c->buffer[1] << 16; length |= c->buffer[2] << 8; length |= c->buffer[3]; if (length < 8) { /* odd, assume REPORT_LUNS is broken, fall back to doing INQUIRY */ DEBUG_INIT1("iSCSI: session %p REPORT_LUNS length 0, falling back to INQUIRY\n", session); report_luns_failed = 1; break; } /* figure out how many luns we were told about this time */ if ((length / 8U) < luns) luns_listed = length / 8U; else luns_listed = luns; /* loop until we run out of data, or out of buffer */ for (l = 0; l < luns_listed; l++) { int address_method = (lun_list[0] & 0xc0) >> 6; int lun; if (LOG_ENABLED(ISCSI_LOG_LOGIN) || LOG_ENABLED(ISCSI_LOG_INIT)) printk("iSCSI: session %p (%u %u %u *) REPORT_LUNS[%d] = %02x %02x %02x %02x %02x %02x %02x %02x\n", session, session->host_no, session->channel, session->target_id, l, lun_list[0], lun_list[1], lun_list[2], lun_list[3], lun_list[4], lun_list[5], lun_list[6], lun_list[7]); switch (address_method) { case 0x0: { /* single-level LUN if bus id is 0, else peripheral device addressing */ lun = lun_list[1]; set_bit(lun, session->luns_detected); break; } case 0x1: { /* flat-space addressing */ lun = lun_list[1]; set_bit(lun, session->luns_detected); break; } case 0x2: { /* logical unit addressing method */ lun = lun_list[1] & 0x1F; set_bit(lun, session->luns_detected); break; } case 0x3: { /* extended logical unit addressing method is too complicated for us to want to deal with */ printk("iSCSI: session %p (%u %u %u *) REPORT_LUNS[%d] with extended LU address method 0x%x ignored\n", session, session->host_no, session->channel, session->target_id, l, address_method); break; } default: printk("iSCSI: session %p (%u %u %u *) REPORT_LUNS[%d] with unknown address method 0x%x ignored\n", session, session->host_no, session->channel, session->target_id, l, address_method); break; } /* next LUN in the list */ lun_list += 8; } /* decide how many luns to ask for on the next iteration, if there is one */ luns = length / 8U; if (luns > ISCSI_MAX_LUN) { /* we only have buffer space for so many LUNs */ luns = ISCSI_MAX_LUN; printk("iSCSI: session %p REPORT_LUNS length %u (%u entries) truncated to %u (%u entries)\n", session, length, (length / 8) - 1, (luns + 1) * 8U, luns); } } else { /* REPORT_LUNS failed, fall back to doing INQUIRY */ DEBUG_INIT1("iSCSI: session %p REPORT_LUNS failed, falling back to INQUIRY\n", session); report_luns_failed = 1; break; } } while (luns > last_luns); if (signal_pending(current)) { DEBUG_INIT1("iSCSI: session %p detect LUNs aborted by signal\n", session); goto done; } if (report_luns_failed) { /* if REPORT_LUNS failed, then either it's a SCSI-2 device * that doesn't understand the command, or it's a SCSI-3 * device that only has one LUN and decided not to implement * REPORT_LUNS. In either case, we're safe just probing LUNs * 0-7 with INQUIRY, since SCSI-2 can't have more than 8 LUNs, * and SCSI-3 should do REPORT_LUNS if it has more than 1 LUN. */ for (l = 0; l < 8; l++) { sc->lun = l; sc->request_buffer = c->buffer; make_inquiry(sc, lun0_scsi_level); /* we'll make a note of the LUN when the rx thread receives the response. * No need to do it again here. */ if (iscsi_do_cmnd(session, c, 6)) { /* we do need to record the SCSI level so we can build inquiries properly though */ if (l == 0) { lun0_scsi_level = c->buffer[2] & 0x07; if (LOG_ENABLED(ISCSI_LOG_INIT)) printk("iSCSI: session %p (%u %u %u %u) is SCSI level %d\n", session, sc->host->host_no, sc->channel, sc->target, sc->lun, lun0_scsi_level); } } else { /* just assume there's no LUN */ } if (test_bit(SESSION_TERMINATING, &session->control_bits)) break; if (signal_pending(current)) break; } } done:#if DEBUG_ALLOC if (LOG_ENABLED(ISCSI_LOG_ALLOC)) printk("iSCSI: session %p hba %p host %p kfree iscsi cmnd %p, bufflen %u\n", session, session->hba, session->hba->host, c, c->bufflen);#endif kfree(c);}int iscsi_reset_lun_probing(void){ int ret = 0; spin_lock(&iscsi_lun_probe_lock); if ((iscsi_currently_probing == NULL) && (iscsi_lun_probe_head == NULL)) { /* if we're not currently probing, reset */ DEBUG_INIT1("iSCSI: reset LUN probing at %lu\n", jiffies); iscsi_next_probe = 0; iscsi_lun_probe_start = 0; mb(); ret = 1; } else { DEBUG_INIT3("iSCSI: failed to reset LUN probing at %lu, currently %p, head %p\n", jiffies, iscsi_currently_probing, iscsi_lun_probe_head); } spin_unlock(&iscsi_lun_probe_lock); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -