📄 pf.c
字号:
r = pf_completion(pf, buf, fun); if (r) pf_req_sense(pf, !fun); return r;}#define DBMSG(msg) ((verbose>1)?(msg):NULL)static void pf_lock(struct pf_unit *pf, int func){ char lo_cmd[12] = { ATAPI_LOCK, pf->lun << 5, 0, 0, func, 0, 0, 0, 0, 0, 0, 0 }; pf_atapi(pf, lo_cmd, 0, pf_scratch, func ? "unlock" : "lock");}static void pf_eject(struct pf_unit *pf){ char ej_cmd[12] = { ATAPI_DOOR, pf->lun << 5, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }; pf_lock(pf, 0); pf_atapi(pf, ej_cmd, 0, pf_scratch, "eject");}#define PF_RESET_TMO 30 /* in tenths of a second */static void pf_sleep(int cs){ current->state = TASK_INTERRUPTIBLE; schedule_timeout(cs);}/* the ATAPI standard actually specifies the contents of all 7 registers after a reset, but the specification is ambiguous concerning the last two bytes, and different drives interpret the standard differently. */static int pf_reset(struct pf_unit *pf){ int i, k, flg; int expect[5] = { 1, 1, 1, 0x14, 0xeb }; pi_connect(pf->pi); write_reg(pf, 6, 0xa0+0x10*pf->drive); write_reg(pf, 7, 8); pf_sleep(20 * HZ / 1000); k = 0; while ((k++ < PF_RESET_TMO) && (status_reg(pf) & STAT_BUSY)) pf_sleep(HZ / 10); flg = 1; for (i = 0; i < 5; i++) flg &= (read_reg(pf, i + 1) == expect[i]); if (verbose) { printk("%s: Reset (%d) signature = ", pf->name, k); for (i = 0; i < 5; i++) printk("%3x", read_reg(pf, i + 1)); if (!flg) printk(" (incorrect)"); printk("\n"); } pi_disconnect(pf->pi); return flg - 1;}static void pf_mode_sense(struct pf_unit *pf){ char ms_cmd[12] = { ATAPI_MODE_SENSE, pf->lun << 5, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0 }; char buf[8]; pf_atapi(pf, ms_cmd, 8, buf, DBMSG("mode sense")); pf->media_status = PF_RW; if (buf[3] & 0x80) pf->media_status = PF_RO;}static void xs(char *buf, char *targ, int offs, int len){ int j, k, l; j = 0; l = 0; for (k = 0; k < len; k++) if ((buf[k + offs] != 0x20) || (buf[k + offs] != l)) l = targ[j++] = buf[k + offs]; if (l == 0x20) j--; targ[j] = 0;}static int xl(char *buf, int offs){ int v, k; v = 0; for (k = 0; k < 4; k++) v = v * 256 + (buf[k + offs] & 0xff); return v;}static void pf_get_capacity(struct pf_unit *pf){ char rc_cmd[12] = { ATAPI_CAPACITY, pf->lun << 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; char buf[8]; int bs; if (pf_atapi(pf, rc_cmd, 8, buf, DBMSG("get capacity"))) { pf->media_status = PF_NM; return; } set_capacity(pf->disk, xl(buf, 0) + 1); bs = xl(buf, 4); if (bs != 512) { set_capacity(pf->disk, 0); if (verbose) printk("%s: Drive %d, LUN %d," " unsupported block size %d\n", pf->name, pf->drive, pf->lun, bs); }}static int pf_identify(struct pf_unit *pf){ int dt, s; char *ms[2] = { "master", "slave" }; char mf[10], id[18]; char id_cmd[12] = { ATAPI_IDENTIFY, pf->lun << 5, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 }; char buf[36]; s = pf_atapi(pf, id_cmd, 36, buf, "identify"); if (s) return -1; dt = buf[0] & 0x1f; if ((dt != 0) && (dt != 7)) { if (verbose) printk("%s: Drive %d, LUN %d, unsupported type %d\n", pf->name, pf->drive, pf->lun, dt); return -1; } xs(buf, mf, 8, 8); xs(buf, id, 16, 16); pf->removable = (buf[1] & 0x80); pf_mode_sense(pf); pf_mode_sense(pf); pf_mode_sense(pf); pf_get_capacity(pf); printk("%s: %s %s, %s LUN %d, type %d", pf->name, mf, id, ms[pf->drive], pf->lun, dt); if (pf->removable) printk(", removable"); if (pf->media_status == PF_NM) printk(", no media\n"); else { if (pf->media_status == PF_RO) printk(", RO"); printk(", %llu blocks\n", (unsigned long long)get_capacity(pf->disk)); } return 0;}/* returns 0, with id set if drive is detected -1, if drive detection failed*/static int pf_probe(struct pf_unit *pf){ if (pf->drive == -1) { for (pf->drive = 0; pf->drive <= 1; pf->drive++) if (!pf_reset(pf)) { if (pf->lun != -1) return pf_identify(pf); else for (pf->lun = 0; pf->lun < 8; pf->lun++) if (!pf_identify(pf)) return 0; } } else { if (pf_reset(pf)) return -1; if (pf->lun != -1) return pf_identify(pf); for (pf->lun = 0; pf->lun < 8; pf->lun++) if (!pf_identify(pf)) return 0; } return -1;}static int pf_detect(void){ struct pf_unit *pf = units; int k, unit; printk("%s: %s version %s, major %d, cluster %d, nice %d\n", name, name, PF_VERSION, major, cluster, nice); k = 0; if (pf_drive_count == 0) { if (pi_init(pf->pi, 1, -1, -1, -1, -1, -1, pf_scratch, PI_PF, verbose, pf->name)) { if (!pf_probe(pf) && pf->disk) { pf->present = 1; k++; } else pi_release(pf->pi); } } else for (unit = 0; unit < PF_UNITS; unit++, pf++) { int *conf = *drives[unit]; if (!conf[D_PRT]) continue; if (pi_init(pf->pi, 0, conf[D_PRT], conf[D_MOD], conf[D_UNI], conf[D_PRO], conf[D_DLY], pf_scratch, PI_PF, verbose, pf->name)) { if (!pf_probe(pf) && pf->disk) { pf->present = 1; k++; } else pi_release(pf->pi); } } if (k) return 0; printk("%s: No ATAPI disk detected\n", name); for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) put_disk(pf->disk); return -1;}/* The i/o request engine */static int pf_start(struct pf_unit *pf, int cmd, int b, int c){ int i; char io_cmd[12] = { cmd, pf->lun << 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; for (i = 0; i < 4; i++) { io_cmd[5 - i] = b & 0xff; b = b >> 8; } io_cmd[8] = c & 0xff; io_cmd[7] = (c >> 8) & 0xff; i = pf_command(pf, io_cmd, c * 512, "start i/o"); mdelay(1); return i;}static int pf_ready(void){ return (((status_reg(pf_current) & (STAT_BUSY | pf_mask)) == pf_mask));}static struct request_queue *pf_queue;static void do_pf_request(request_queue_t * q){ if (pf_busy) return;repeat: pf_req = elv_next_request(q); if (!pf_req) return; pf_current = pf_req->rq_disk->private_data; pf_block = pf_req->sector; pf_run = pf_req->nr_sectors; pf_count = pf_req->current_nr_sectors; if (pf_block + pf_count > get_capacity(pf_req->rq_disk)) { end_request(pf_req, 0); goto repeat; } pf_cmd = rq_data_dir(pf_req); pf_buf = pf_req->buffer; pf_retries = 0; pf_busy = 1; if (pf_cmd == READ) pi_do_claimed(pf_current->pi, do_pf_read); else if (pf_cmd == WRITE) pi_do_claimed(pf_current->pi, do_pf_write); else { pf_busy = 0; end_request(pf_req, 0); goto repeat; }}static int pf_next_buf(void){ unsigned long saved_flags; pf_count--; pf_run--; pf_buf += 512; pf_block++; if (!pf_run) return 0; if (!pf_count) return 1; spin_lock_irqsave(&pf_spin_lock, saved_flags); end_request(pf_req, 1); pf_count = pf_req->current_nr_sectors; pf_buf = pf_req->buffer; spin_unlock_irqrestore(&pf_spin_lock, saved_flags); return 1;}static inline void next_request(int success){ unsigned long saved_flags; spin_lock_irqsave(&pf_spin_lock, saved_flags); end_request(pf_req, success); pf_busy = 0; do_pf_request(pf_queue); spin_unlock_irqrestore(&pf_spin_lock, saved_flags);}/* detach from the calling context - in case the spinlock is held */static void do_pf_read(void){ ps_set_intr(do_pf_read_start, NULL, 0, nice);}static void do_pf_read_start(void){ pf_busy = 1; if (pf_start(pf_current, ATAPI_READ_10, pf_block, pf_run)) { pi_disconnect(pf_current->pi); if (pf_retries < PF_MAX_RETRIES) { pf_retries++; pi_do_claimed(pf_current->pi, do_pf_read_start); return; } next_request(0); return; } pf_mask = STAT_DRQ; ps_set_intr(do_pf_read_drq, pf_ready, PF_TMO, nice);}static void do_pf_read_drq(void){ while (1) { if (pf_wait(pf_current, STAT_BUSY, STAT_DRQ | STAT_ERR, "read block", "completion") & STAT_ERR) { pi_disconnect(pf_current->pi); if (pf_retries < PF_MAX_RETRIES) { pf_req_sense(pf_current, 0); pf_retries++; pi_do_claimed(pf_current->pi, do_pf_read_start); return; } next_request(0); return; } pi_read_block(pf_current->pi, pf_buf, 512); if (pf_next_buf()) break; } pi_disconnect(pf_current->pi); next_request(1);}static void do_pf_write(void){ ps_set_intr(do_pf_write_start, NULL, 0, nice);}static void do_pf_write_start(void){ pf_busy = 1; if (pf_start(pf_current, ATAPI_WRITE_10, pf_block, pf_run)) { pi_disconnect(pf_current->pi); if (pf_retries < PF_MAX_RETRIES) { pf_retries++; pi_do_claimed(pf_current->pi, do_pf_write_start); return; } next_request(0); return; } while (1) { if (pf_wait(pf_current, STAT_BUSY, STAT_DRQ | STAT_ERR, "write block", "data wait") & STAT_ERR) { pi_disconnect(pf_current->pi); if (pf_retries < PF_MAX_RETRIES) { pf_retries++; pi_do_claimed(pf_current->pi, do_pf_write_start); return; } next_request(0); return; } pi_write_block(pf_current->pi, pf_buf, 512); if (pf_next_buf()) break; } pf_mask = 0; ps_set_intr(do_pf_write_done, pf_ready, PF_TMO, nice);}static void do_pf_write_done(void){ if (pf_wait(pf_current, STAT_BUSY, 0, "write block", "done") & STAT_ERR) { pi_disconnect(pf_current->pi); if (pf_retries < PF_MAX_RETRIES) { pf_retries++; pi_do_claimed(pf_current->pi, do_pf_write_start); return; } next_request(0); return; } pi_disconnect(pf_current->pi); next_request(1);}static int __init pf_init(void){ /* preliminary initialisation */ struct pf_unit *pf; int unit; if (disable) return -1; pf_init_units(); if (pf_detect()) return -1; pf_busy = 0; if (register_blkdev(major, name)) { for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) put_disk(pf->disk); return -1; } pf_queue = blk_init_queue(do_pf_request, &pf_spin_lock); if (!pf_queue) { unregister_blkdev(major, name); for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) put_disk(pf->disk); return -1; } blk_queue_max_phys_segments(pf_queue, cluster); blk_queue_max_hw_segments(pf_queue, cluster); for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) { struct gendisk *disk = pf->disk; if (!pf->present) continue; disk->private_data = pf; disk->queue = pf_queue; add_disk(disk); } return 0;}static void __exit pf_exit(void){ struct pf_unit *pf; int unit; unregister_blkdev(major, name); for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) { if (!pf->present) continue; del_gendisk(pf->disk); put_disk(pf->disk); pi_release(pf->pi); } blk_cleanup_queue(pf_queue);}MODULE_LICENSE("GPL");module_init(pf_init)module_exit(pf_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -