hd.c
上传用户:hy11688
上传日期:2008-05-11
资源大小:272k
文件大小:8k
源码类别:

操作系统开发

开发平台:

C/C++

  1. /*
  2.  *  linux/kernel/hd.c
  3.  *
  4.  *  (C) 1991  Linus Torvalds
  5.  */
  6. /*
  7.  * This is the low-level hd interrupt support. It traverses the
  8.  * request-list, using interrupts to jump between functions. As
  9.  * all the functions are called within interrupts, we may not
  10.  * sleep. Special care is recommended.
  11.  * 
  12.  *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
  13.  */
  14. #include <linux/config.h>
  15. #include <linux/sched.h>
  16. #include <linux/fs.h>
  17. #include <linux/kernel.h>
  18. #include <linux/hdreg.h>
  19. #include <asm/system.h>
  20. #include <asm/io.h>
  21. #include <asm/segment.h>
  22. #define MAJOR_NR 3
  23. #include "blk.h"
  24. #define CMOS_READ(addr) ({ 
  25. outb_p(0x80|addr,0x70); 
  26. inb_p(0x71); 
  27. })
  28. /* Max read/write errors/sector */
  29. #define MAX_ERRORS 7
  30. #define MAX_HD 2
  31. static void recal_intr(void);
  32. static void bad_rw_intr(void);
  33. static int recalibrate = 0;
  34. static int reset = 0;
  35. /*
  36.  *  This struct defines the HD's and their types.
  37.  */
  38. struct hd_i_struct {
  39. int head,sect,cyl,wpcom,lzone,ctl;
  40. };
  41. #ifdef HD_TYPE
  42. struct hd_i_struct hd_info[] = { HD_TYPE };
  43. #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
  44. #else
  45. struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
  46. static int NR_HD = 0;
  47. #endif
  48. static struct hd_struct {
  49. long start_sect;
  50. long nr_sects;
  51. } hd[5*MAX_HD]={{0,0},};
  52. static int hd_sizes[5*MAX_HD] = {0, };
  53. #define port_read(port,buf,nr) 
  54. __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
  55. #define port_write(port,buf,nr) 
  56. __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
  57. extern void hd_interrupt(void);
  58. extern void rd_load(void);
  59. /* This may be used only once, enforced by 'static int callable' */
  60. int sys_setup(void * BIOS)
  61. {
  62. static int callable = 1;
  63. int i,drive;
  64. unsigned char cmos_disks;
  65. struct partition *p;
  66. struct buffer_head * bh;
  67. if (!callable)
  68. return -1;
  69. callable = 0;
  70. #ifndef HD_TYPE
  71. for (drive=0 ; drive<2 ; drive++) {
  72. hd_info[drive].cyl = *(unsigned short *) BIOS;
  73. hd_info[drive].head = *(unsigned char *) (2+BIOS);
  74. hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
  75. hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
  76. hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
  77. hd_info[drive].sect = *(unsigned char *) (14+BIOS);
  78. BIOS += 16;
  79. }
  80. if (hd_info[1].cyl)
  81. NR_HD=2;
  82. else
  83. NR_HD=1;
  84. #endif
  85. for (i=0 ; i<NR_HD ; i++) {
  86. hd[i*5].start_sect = 0;
  87. hd[i*5].nr_sects = hd_info[i].head*
  88. hd_info[i].sect*hd_info[i].cyl;
  89. }
  90. /*
  91. We querry CMOS about hard disks : it could be that 
  92. we have a SCSI/ESDI/etc controller that is BIOS
  93. compatable with ST-506, and thus showing up in our
  94. BIOS table, but not register compatable, and therefore
  95. not present in CMOS.
  96. Furthurmore, we will assume that our ST-506 drives
  97. <if any> are the primary drives in the system, and 
  98. the ones reflected as drive 1 or 2.
  99. The first drive is stored in the high nibble of CMOS
  100. byte 0x12, the second in the low nibble.  This will be
  101. either a 4 bit drive type or 0xf indicating use byte 0x19 
  102. for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
  103. Needless to say, a non-zero value means we have 
  104. an AT controller hard disk for that drive.
  105. */
  106. if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
  107. if (cmos_disks & 0x0f)
  108. NR_HD = 2;
  109. else
  110. NR_HD = 1;
  111. else
  112. NR_HD = 0;
  113. for (i = NR_HD ; i < 2 ; i++) {
  114. hd[i*5].start_sect = 0;
  115. hd[i*5].nr_sects = 0;
  116. }
  117. for (drive=0 ; drive<NR_HD ; drive++) {
  118. if (!(bh = bread(0x300 + drive*5,0))) {
  119. printk("Unable to read partition table of drive %dnr",
  120. drive);
  121. panic("");
  122. }
  123. if (bh->b_data[510] != 0x55 || (unsigned char)
  124.     bh->b_data[511] != 0xAA) {
  125. printk("Bad partition table on drive %dnr",drive);
  126. panic("");
  127. }
  128. p = 0x1BE + (void *)bh->b_data;
  129. for (i=1;i<5;i++,p++) {
  130. hd[i+5*drive].start_sect = p->start_sect;
  131. hd[i+5*drive].nr_sects = p->nr_sects;
  132. }
  133. brelse(bh);
  134. }
  135. for (i=0 ; i<5*MAX_HD ; i++)
  136. hd_sizes[i] = hd[i].nr_sects>>1 ;
  137. blk_size[MAJOR_NR] = hd_sizes;
  138. if (NR_HD)
  139. printk("Partition table%s ok.nr",(NR_HD>1)?"s":"");
  140. rd_load();
  141. init_swapping();
  142. mount_root();
  143. return (0);
  144. }
  145. static int controller_ready(void)
  146. {
  147. int retries = 100000;
  148. while (--retries && (inb_p(HD_STATUS)&0xc0)!=0x40);
  149. return (retries);
  150. }
  151. static int win_result(void)
  152. {
  153. int i=inb_p(HD_STATUS);
  154. if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
  155. == (READY_STAT | SEEK_STAT))
  156. return(0); /* ok */
  157. if (i&1) i=inb(HD_ERROR);
  158. return (1);
  159. }
  160. static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
  161. unsigned int head,unsigned int cyl,unsigned int cmd,
  162. void (*intr_addr)(void))
  163. {
  164. register int port asm("dx");
  165. if (drive>1 || head>15)
  166. panic("Trying to write bad sector");
  167. if (!controller_ready())
  168. panic("HD controller not ready");
  169. SET_INTR(intr_addr);
  170. outb_p(hd_info[drive].ctl,HD_CMD);
  171. port=HD_DATA;
  172. outb_p(hd_info[drive].wpcom>>2,++port);
  173. outb_p(nsect,++port);
  174. outb_p(sect,++port);
  175. outb_p(cyl,++port);
  176. outb_p(cyl>>8,++port);
  177. outb_p(0xA0|(drive<<4)|head,++port);
  178. outb(cmd,++port);
  179. }
  180. static int drive_busy(void)
  181. {
  182. unsigned int i;
  183. unsigned char c;
  184. for (i = 0; i < 50000; i++) {
  185. c = inb_p(HD_STATUS);
  186. c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
  187. if (c == (READY_STAT | SEEK_STAT))
  188. return 0;
  189. }
  190. printk("HD controller times outnr");
  191. return(1);
  192. }
  193. static void reset_controller(void)
  194. {
  195. int i;
  196. outb(4,HD_CMD);
  197. for(i = 0; i < 1000; i++) nop();
  198. outb(hd_info[0].ctl & 0x0f ,HD_CMD);
  199. if (drive_busy())
  200. printk("HD-controller still busynr");
  201. if ((i = inb(HD_ERROR)) != 1)
  202. printk("HD-controller reset failed: %02xnr",i);
  203. }
  204. static void reset_hd(void)
  205. {
  206. static int i;
  207. repeat:
  208. if (reset) {
  209. reset = 0;
  210. i = -1;
  211. reset_controller();
  212. } else if (win_result()) {
  213. bad_rw_intr();
  214. if (reset)
  215. goto repeat;
  216. }
  217. i++;
  218. if (i < NR_HD) {
  219. hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
  220. hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
  221. } else
  222. do_hd_request();
  223. }
  224. void unexpected_hd_interrupt(void)
  225. {
  226. printk("Unexpected HD interruptnr");
  227. reset = 1;
  228. do_hd_request();
  229. }
  230. static void bad_rw_intr(void)
  231. {
  232. if (++CURRENT->errors >= MAX_ERRORS)
  233. end_request(0);
  234. if (CURRENT->errors > MAX_ERRORS/2)
  235. reset = 1;
  236. }
  237. static void read_intr(void)
  238. {
  239. if (win_result()) {
  240. bad_rw_intr();
  241. do_hd_request();
  242. return;
  243. }
  244. port_read(HD_DATA,CURRENT->buffer,256);
  245. CURRENT->errors = 0;
  246. CURRENT->buffer += 512;
  247. CURRENT->sector++;
  248. if (--CURRENT->nr_sectors) {
  249. SET_INTR(&read_intr);
  250. return;
  251. }
  252. end_request(1);
  253. do_hd_request();
  254. }
  255. static void write_intr(void)
  256. {
  257. if (win_result()) {
  258. bad_rw_intr();
  259. do_hd_request();
  260. return;
  261. }
  262. if (--CURRENT->nr_sectors) {
  263. CURRENT->sector++;
  264. CURRENT->buffer += 512;
  265. SET_INTR(&write_intr);
  266. port_write(HD_DATA,CURRENT->buffer,256);
  267. return;
  268. }
  269. end_request(1);
  270. do_hd_request();
  271. }
  272. static void recal_intr(void)
  273. {
  274. if (win_result())
  275. bad_rw_intr();
  276. do_hd_request();
  277. }
  278. void hd_times_out(void)
  279. {
  280. if (!CURRENT)
  281. return;
  282. printk("HD timeout");
  283. if (++CURRENT->errors >= MAX_ERRORS)
  284. end_request(0);
  285. SET_INTR(NULL);
  286. reset = 1;
  287. do_hd_request();
  288. }
  289. void do_hd_request(void)
  290. {
  291. int i,r;
  292. unsigned int block,dev;
  293. unsigned int sec,head,cyl;
  294. unsigned int nsect;
  295. INIT_REQUEST;
  296. dev = MINOR(CURRENT->dev);
  297. block = CURRENT->sector;
  298. if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) {
  299. end_request(0);
  300. goto repeat;
  301. }
  302. block += hd[dev].start_sect;
  303. dev /= 5;
  304. __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
  305. "r" (hd_info[dev].sect));
  306. __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
  307. "r" (hd_info[dev].head));
  308. sec++;
  309. nsect = CURRENT->nr_sectors;
  310. if (reset) {
  311. recalibrate = 1;
  312. reset_hd();
  313. return;
  314. }
  315. if (recalibrate) {
  316. recalibrate = 0;
  317. hd_out(dev,hd_info[CURRENT_DEV].sect,0,0,0,
  318. WIN_RESTORE,&recal_intr);
  319. return;
  320. }
  321. if (CURRENT->cmd == WRITE) {
  322. hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
  323. for(i=0 ; i<10000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
  324. /* nothing */ ;
  325. if (!r) {
  326. bad_rw_intr();
  327. goto repeat;
  328. }
  329. port_write(HD_DATA,CURRENT->buffer,256);
  330. } else if (CURRENT->cmd == READ) {
  331. hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
  332. } else
  333. panic("unknown hd-command");
  334. }
  335. void hd_init(void)
  336. {
  337. blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  338. set_intr_gate(0x2E,&hd_interrupt);
  339. outb_p(inb_p(0x21)&0xfb,0x21);
  340. outb(inb_p(0xA1)&0xbf,0xA1);
  341. }