scsi_debug.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,869 行 · 第 1/4 页
C
1,869 行
break; case MODE_SENSE: case MODE_SENSE_10: errsts = resp_mode_sense(cmd, target, buff, bufflen, devip); break; case SYNCHRONIZE_CACHE: memset(buff, 0, bufflen); break; default: if ((errsts = check_reset(SCpnt, devip))) break; mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0, 18); errsts = check_condition_result; break; } return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay);}static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg){ if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd); } return -EINVAL; /* return -ENOTTY; // correct return but upsets fdisk */}static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip){ if (devip->reset) { devip->reset = 0; mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0, 18); return check_condition_result; } return 0;}#define SDEBUG_LONG_INQ_SZ 58#define SDEBUG_MAX_INQ_ARR_SZ 128static const char * vendor_id = "Linux ";static const char * product_id = "scsi_debug ";static const char * product_rev = "0004";static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, const char * dev_id_str, int dev_id_str_len){ int num; /* Two identification descriptors: */ /* T10 vendor identifier field format (faked) */ arr[0] = 0x2; /* ASCII */ arr[1] = 0x1; arr[2] = 0x0; memcpy(&arr[4], vendor_id, 8); memcpy(&arr[12], product_id, 16); memcpy(&arr[28], dev_id_str, dev_id_str_len); num = 8 + 16 + dev_id_str_len; arr[3] = num; num += 4; /* NAA IEEE registered identifier (faked) */ arr[num] = 0x1; /* binary */ arr[num + 1] = 0x3; arr[num + 2] = 0x0; arr[num + 3] = 0x8; arr[num + 4] = 0x51; /* ieee company id=0x123456 (faked) */ arr[num + 5] = 0x23; arr[num + 6] = 0x45; arr[num + 7] = 0x60; arr[num + 8] = (dev_id_num >> 24); arr[num + 9] = (dev_id_num >> 16) & 0xff; arr[num + 10] = (dev_id_num >> 8) & 0xff; arr[num + 11] = dev_id_num & 0xff; return num + 12;}static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff, int bufflen, struct sdebug_dev_info * devip){ unsigned char pq_pdt; unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ]; int min_len = bufflen > SDEBUG_MAX_INQ_ARR_SZ ? SDEBUG_MAX_INQ_ARR_SZ : bufflen; if (bufflen < cmd[4]) printk(KERN_INFO "scsi_debug: inquiry: bufflen=%d " "< alloc_length=%d\n", bufflen, (int)cmd[4]); memset(buff, 0, bufflen); memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ); pq_pdt = (scsi_debug_ptype & 0x1f); arr[0] = pq_pdt; if (0x2 & cmd[1]) { /* CMDDT bit set */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0, 18); return check_condition_result; } else if (0x1 & cmd[1]) { /* EVPD bit set */ int dev_id_num, len; char dev_id_str[6]; dev_id_num = ((devip->sdbg_host->shost->host_no + 1) * 2000) + (devip->target * 1000) + devip->lun; len = scnprintf(dev_id_str, 6, "%d", dev_id_num); if (0 == cmd[2]) { /* supported vital product data pages */ arr[3] = 3; arr[4] = 0x0; /* this page */ arr[5] = 0x80; /* unit serial number */ arr[6] = 0x83; /* device identification */ } else if (0x80 == cmd[2]) { /* unit serial number */ arr[1] = 0x80; arr[3] = len; memcpy(&arr[4], dev_id_str, len); } else if (0x83 == cmd[2]) { /* device identification */ arr[1] = 0x83; arr[3] = inquiry_evpd_83(&arr[4], dev_id_num, dev_id_str, len); } else { /* Illegal request, invalid field in cdb */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0, 18); return check_condition_result; } memcpy(buff, arr, min_len); return 0; } /* drops through here for a standard inquiry */ arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ arr[2] = scsi_debug_scsi_level; arr[4] = SDEBUG_LONG_INQ_SZ - 5; arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */ memcpy(&arr[8], vendor_id, 8); memcpy(&arr[16], product_id, 16); memcpy(&arr[32], product_rev, 4); memcpy(buff, arr, min_len); return 0;}/* <<Following mode page info copied from ST318451LW>> */static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target){ /* Read-Write Error Recovery page for mode_sense */ unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 5, 0, 0xff, 0xff}; memcpy(p, err_recov_pg, sizeof(err_recov_pg)); if (1 == pcontrol) memset(p + 2, 0, sizeof(err_recov_pg) - 2); return sizeof(err_recov_pg);}static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target){ /* Disconnect-Reconnect page for mode_sense */ unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; memcpy(p, disconnect_pg, sizeof(disconnect_pg)); if (1 == pcontrol) memset(p + 2, 0, sizeof(disconnect_pg) - 2); return sizeof(disconnect_pg);}static int resp_format_pg(unsigned char * p, int pcontrol, int target){ /* Format device page for mode_sense */ unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0, 0, 0}; memcpy(p, format_pg, sizeof(format_pg)); p[10] = (sdebug_sectors_per >> 8) & 0xff; p[11] = sdebug_sectors_per & 0xff; p[12] = (SECT_SIZE >> 8) & 0xff; p[13] = SECT_SIZE & 0xff; if (DEV_REMOVEABLE(target)) p[20] |= 0x20; /* should agree with INQUIRY */ if (1 == pcontrol) memset(p + 2, 0, sizeof(format_pg) - 2); return sizeof(format_pg);}static int resp_caching_pg(unsigned char * p, int pcontrol, int target){ /* Caching page for mode_sense */ unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; memcpy(p, caching_pg, sizeof(caching_pg)); if (1 == pcontrol) memset(p + 2, 0, sizeof(caching_pg) - 2); return sizeof(caching_pg);}static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target){ /* Control mode page for mode_sense */ unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0x2, 0x4b}; memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); if (1 == pcontrol) memset(p + 2, 0, sizeof(ctrl_m_pg) - 2); return sizeof(ctrl_m_pg);}static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target){ /* Informational Exceptions control mode page for mode_sense */ unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x0}; memcpy(p, iec_m_pg, sizeof(iec_m_pg)); if (1 == pcontrol) memset(p + 2, 0, sizeof(iec_m_pg) - 2); return sizeof(iec_m_pg);}#define SDEBUG_MAX_MSENSE_SZ 256static int resp_mode_sense(unsigned char * cmd, int target, unsigned char * buff, int bufflen, struct sdebug_dev_info * devip){ unsigned char dbd; int pcontrol, pcode; unsigned char dev_spec; int alloc_len, msense_6, offset, len; unsigned char * ap; unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; int min_len = bufflen > SDEBUG_MAX_MSENSE_SZ ? SDEBUG_MAX_MSENSE_SZ : bufflen; SCSI_LOG_LLQUEUE(3, printk("Mode sense ...(%p %d)\n", buff, bufflen)); dbd = cmd[1] & 0x8; pcontrol = (cmd[2] & 0xc0) >> 6; pcode = cmd[2] & 0x3f; msense_6 = (MODE_SENSE == cmd[0]); alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); /* printk(KERN_INFO "msense: dbd=%d pcontrol=%d pcode=%d " "msense_6=%d alloc_len=%d\n", dbd, pcontrol, pcode, " "msense_6, alloc_len); */ if (bufflen < alloc_len) printk(KERN_INFO "scsi_debug: mode_sense: bufflen=%d " "< alloc_length=%d\n", bufflen, alloc_len); memset(buff, 0, bufflen); memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); if (0x3 == pcontrol) { /* Saving values not supported */ mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0, 18); return check_condition_result; } dev_spec = DEV_READONLY(target) ? 0x80 : 0x0; if (msense_6) { arr[2] = dev_spec; offset = 4; } else { arr[3] = dev_spec; offset = 8; } ap = arr + offset; switch (pcode) { case 0x1: /* Read-Write error recovery page, direct access */ len = resp_err_recov_pg(ap, pcontrol, target); offset += len; break; case 0x2: /* Disconnect-Reconnect page, all devices */ len = resp_disconnect_pg(ap, pcontrol, target); offset += len; break; case 0x3: /* Format device page, direct access */ len = resp_format_pg(ap, pcontrol, target); offset += len; break; case 0x8: /* Caching page, direct access */ len = resp_caching_pg(ap, pcontrol, target); offset += len; break; case 0xa: /* Control Mode page, all devices */ len = resp_ctrl_m_pg(ap, pcontrol, target); offset += len; break; case 0x1c: /* Informational Exceptions Mode page, all devices */ len = resp_iec_m_pg(ap, pcontrol, target); offset += len; break; case 0x3f: /* Read all Mode pages */ len = resp_err_recov_pg(ap, pcontrol, target); len += resp_disconnect_pg(ap + len, pcontrol, target); len += resp_format_pg(ap + len, pcontrol, target); len += resp_caching_pg(ap + len, pcontrol, target); len += resp_ctrl_m_pg(ap + len, pcontrol, target); len += resp_iec_m_pg(ap + len, pcontrol, target); offset += len; break; default: mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0, 18); return check_condition_result; } if (msense_6) arr[0] = offset - 1; else { offset -= 2; arr[0] = (offset >> 8) & 0xff; arr[1] = offset & 0xff; } memcpy(buff, arr, min_len); return 0;}static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, int num, struct sdebug_dev_info * devip){ unsigned char *buff = (unsigned char *) SCpnt->request_buffer; int nbytes, sgcount; struct scatterlist *sgpnt = NULL; int bufflen = SCpnt->request_bufflen; unsigned long iflags; if (upper_blk || (block + num > sdebug_capacity)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0, 18); return check_condition_result; } if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && (block <= OPT_MEDIUM_ERR_ADDR) && ((block + num) > OPT_MEDIUM_ERR_ADDR)) { mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0, 18); /* claim unrecoverable read error */ return check_condition_result; } read_lock_irqsave(&atomic_rw, iflags); sgcount = 0; nbytes = bufflen; /* printk(KERN_INFO "scsi_debug_read: block=%d, tot_bufflen=%d\n", block, bufflen); */ if (SCpnt->use_sg) { sgcount = 0; sgpnt = (struct scatterlist *) buff; buff = scatg2virt(&sgpnt[sgcount]); bufflen = sgpnt[sgcount].length; } do { memcpy(buff, fake_storep + (block * SECT_SIZE), bufflen); nbytes -= bufflen; if (SCpnt->use_sg) { block += bufflen >> POW2_SECT_SIZE; sgcount++; if (nbytes) { buff = scatg2virt(&sgpnt[sgcount]); bufflen = sgpnt[sgcount].length; } } else if (nbytes > 0) printk(KERN_WARNING "scsi_debug:resp_read: unexpected " "nbytes=%d\n", nbytes); } while (nbytes); read_unlock_irqrestore(&atomic_rw, iflags); return 0;}static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block, int num, struct sdebug_dev_info * devip){ unsigned char *buff = (unsigned char *) SCpnt->request_buffer; int nbytes, sgcount; struct scatterlist *sgpnt = NULL; int bufflen = SCpnt->request_bufflen; unsigned long iflags; if (upper_blk || (block + num > sdebug_capacity)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0, 18); return check_condition_result; } write_lock_irqsave(&atomic_rw, iflags); sgcount = 0; nbytes = bufflen; if (SCpnt->use_sg) { sgcount = 0; sgpnt = (struct scatterlist *) buff; buff = scatg2virt(&sgpnt[sgcount]); bufflen = sgpnt[sgcount].length; } do { memcpy(fake_storep + (block * SECT_SIZE), buff, bufflen); nbytes -= bufflen; if (SCpnt->use_sg) { block += bufflen >> POW2_SECT_SIZE; sgcount++; if (nbytes) { buff = scatg2virt(&sgpnt[sgcount]); bufflen = sgpnt[sgcount].length; } } else if (nbytes > 0) printk(KERN_WARNING "scsi_debug:resp_write: " "unexpected nbytes=%d\n", nbytes); } while (nbytes); write_unlock_irqrestore(&atomic_rw, iflags); return 0;}static int resp_report_luns(unsigned char * cmd, unsigned char * buff, int bufflen, struct sdebug_dev_info * devip){ unsigned int alloc_len; int lun_cnt, i, upper; int select_report = (int)cmd[2]; struct scsi_lun *one_lun; alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); if ((alloc_len < 16) || (select_report > 2)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0, 18); return check_condition_result; } if (bufflen > 8) { /* can produce response with up to 16k luns (lun 0 to lun 16383) */ memset(buff, 0, bufflen); lun_cnt = scsi_debug_max_luns; buff[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff; buff[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff; lun_cnt = min((int)((bufflen - 8) / sizeof(struct scsi_lun)), lun_cnt); one_lun = (struct scsi_lun *) &buff[8]; for (i = 0; i < lun_cnt; i++) { upper = (i >> 8) & 0x3f; if (upper) one_lun[i].scsi_lun[0] = (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); one_lun[i].scsi_lun[1] = i & 0xff; } } return 0;}/* When timer goes off this function is called. */static void timer_intr_handler(unsigned long indx){ struct sdebug_queued_cmd * sqcp; unsigned long iflags; if (indx >= SCSI_DEBUG_CANQUEUE) { printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too " "large\n"); return; } spin_lock_irqsave(&queued_arr_lock, iflags); sqcp = &queued_arr[(int)indx]; if (! sqcp->in_use) { printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected " "interrupt\n"); spin_unlock_irqrestore(&queued_arr_lock, iflags); return; } sqcp->in_use = 0; if (sqcp->done_funct) { sqcp->a_cmnd->result = sqcp->scsi_result; sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */ } sqcp->done_funct = NULL; spin_unlock_irqrestore(&queued_arr_lock, iflags);}static int scsi_debug_slave_alloc(struct scsi_device * sdp){ if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?