📄 at_wini.c
字号:
10397 w_drive = device / DEV_PER_DRIVE; /* save drive number */
10398 w_wn = &wini[w_drive];
10399 w_dv = &w_wn->part[device % DEV_PER_DRIVE];
10400 } else
10401 if ((unsigned) (device -= MINOR_hd1a) < NR_SUBDEVS) { /* hd1a, hd1b, ... */
10402 w_drive = device / SUB_PER_DRIVE;
10403 w_wn = &wini[w_drive];
10404 w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
10405 } else {
10406 return(NIL_DEV);
10407 }
10408 return(w_dv);
10409 }
10412 /*===========================================================================*
10413 * w_identify *
10414 *===========================================================================*/
10415 PRIVATE int w_identify()
10416 {
10417 /* Find out if a device exists, if it is an old AT disk, or a newer ATA
10418 * drive, a removable media device, etc.
10419 */
10420
10421 struct wini *wn = w_wn;
10422 struct command cmd;
10423 char id_string[40];
10424 int i, r;
10425 unsigned long size;
10426 #define id_byte(n) (&tmp_buf[2 * (n)])
10427 #define id_word(n) (((u16_t) id_byte(n)[0] << 0) \
10428 |((u16_t) id_byte(n)[1] << 8))
10429 #define id_longword(n) (((u32_t) id_byte(n)[0] << 0) \
10430 |((u32_t) id_byte(n)[1] << 8) \
10431 |((u32_t) id_byte(n)[2] << 16) \
10432 |((u32_t) id_byte(n)[3] << 24))
10433
10434 /* Check if the one of the registers exists. */
10435 r = in_byte(wn->base + REG_CYL_LO);
10436 out_byte(wn->base + REG_CYL_LO, ~r);
10437 if (in_byte(wn->base + REG_CYL_LO) == r) return(ERR);
10438
10439 /* Looks OK; register IRQ and try an ATA identify command. */
10440 put_irq_handler(wn->irq, w_handler);
10441 enable_irq(wn->irq);
10442
10443 cmd.ldh = wn->ldhpref;
10444 cmd.command = ATA_IDENTIFY;
10445 if (com_simple(&cmd) == OK) {
10446 /* This is an ATA device. */
10447 wn->state |= SMART;
10448
10449 /* Device information. */
10450 port_read(wn->base + REG_DATA, tmp_phys, SECTOR_SIZE);
10451
10452 /* Why are the strings byte swapped??? */
10453 for (i = 0; i < 40; i++) id_string[i] = id_byte(27)[i^1];
10454
10455 /* Preferred CHS translation mode. */
10456 wn->pcylinders = id_word(1);
10457 wn->pheads = id_word(3);
10458 wn->psectors = id_word(6);
10459 size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
10460
10461 if ((id_byte(49)[1] & 0x02) && size > 512L*1024*2) {
10462 /* Drive is LBA capable and is big enough to trust it to
10463 * not make a mess of it.
10464 */
10465 wn->ldhpref |= LDH_LBA;
10466 size = id_longword(60);
10467 }
10468
10469 if (wn->lcylinders == 0) {
10470 /* No BIOS parameters? Then make some up. */
10471 wn->lcylinders = wn->pcylinders;
10472 wn->lheads = wn->pheads;
10473 wn->lsectors = wn->psectors;
10474 while (wn->lcylinders > 1024) {
10475 wn->lheads *= 2;
10476 wn->lcylinders /= 2;
10477 }
10478 }
10479 } else {
10480 /* Not an ATA device; no translations, no special features. Don't
10481 * touch it unless the BIOS knows about it.
10482 */
10483 if (wn->lcylinders == 0) return(ERR); /* no BIOS parameters */
10484 wn->pcylinders = wn->lcylinders;
10485 wn->pheads = wn->lheads;
10486 wn->psectors = wn->lsectors;
10487 size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
10488 }
10489 /* The fun ends at 4 GB. */
10490 if (size > ((u32_t) -1) / SECTOR_SIZE) size = ((u32_t) -1) / SECTOR_SIZE;
10491
10492 /* Base and size of the whole drive */
10493 wn->part[0].dv_base = 0;
10494 wn->part[0].dv_size = size << SECTOR_SHIFT;
10495
10496 if (w_specify() != OK && w_specify() != OK) return(ERR);
10497
10498 printf("%s: ", w_name());
10499 if (wn->state & SMART) {
10500 printf("%.40s\n", id_string);
10501 } else {
10502 printf("%ux%ux%u\n", wn->pcylinders, wn->pheads, wn->psectors);
10503 }
10504 return(OK);
10505 }
10508 /*===========================================================================*
10509 * w_name *
10510 *===========================================================================*/
10511 PRIVATE char *w_name()
10512 {
10513 /* Return a name for the current device. */
10514 static char name[] = "at-hd15";
10515 unsigned device = w_drive * DEV_PER_DRIVE;
10516
10517 if (device < 10) {
10518 name[5] = '0' + device;
10519 name[6] = 0;
10520 } else {
10521 name[5] = '0' + device / 10;
10522 name[6] = '0' + device % 10;
10523 }
10524 return name;
10525 }
10528 /*===========================================================================*
10529 * w_specify *
10530 *===========================================================================*/
10531 PRIVATE int w_specify()
10532 {
10533 /* Routine to initialize the drive after boot or when a reset is needed. */
10534
10535 struct wini *wn = w_wn;
10536 struct command cmd;
10537
10538 if ((wn->state & DEAF) && w_reset() != OK) return(ERR);
10539
10540 /* Specify parameters: precompensation, number of heads and sectors. */
10541 cmd.precomp = wn->precomp;
10542 cmd.count = wn->psectors;
10543 cmd.ldh = w_wn->ldhpref | (wn->pheads - 1);
10544 cmd.command = CMD_SPECIFY; /* Specify some parameters */
10545
10546 if (com_simple(&cmd) != OK) return(ERR);
10547
10548 if (!(wn->state & SMART)) {
10549 /* Calibrate an old disk. */
10550 cmd.sector = 0;
10551 cmd.cyl_lo = 0;
10552 cmd.cyl_hi = 0;
10553 cmd.ldh = w_wn->ldhpref;
10554 cmd.command = CMD_RECALIBRATE;
10555
10556 if (com_simple(&cmd) != OK) return(ERR);
10557 }
10558
10559 wn->state |= INITIALIZED;
10560 return(OK);
10561 }
10564 /*===========================================================================*
10565 * w_schedule *
10566 *===========================================================================*/
10567 PRIVATE int w_schedule(proc_nr, iop)
10568 int proc_nr; /* process doing the request */
10569 struct iorequest_s *iop; /* pointer to read or write request */
10570 {
10571 /* Gather I/O requests on consecutive blocks so they may be read/written
10572 * in one controller command. (There is enough time to compute the next
10573 * consecutive request while an unwanted block passes by.)
10574 */
10575 struct wini *wn = w_wn;
10576 int r, opcode;
10577 unsigned long pos;
10578 unsigned nbytes, count;
10579 unsigned long block;
10580 phys_bytes user_phys;
10581
10582 /* This many bytes to read/write */
10583 nbytes = iop->io_nbytes;
10584 if ((nbytes & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
10585
10586 /* From/to this position on the device */
10587 pos = iop->io_position;
10588 if ((pos & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
10589
10590 /* To/from this user address */
10591 user_phys = numap(proc_nr, (vir_bytes) iop->io_buf, nbytes);
10592 if (user_phys == 0) return(iop->io_nbytes = EINVAL);
10593
10594 /* Read or write? */
10595 opcode = iop->io_request & ~OPTIONAL_IO;
10596
10597 /* Which block on disk and how close to EOF? */
10598 if (pos >= w_dv->dv_size) return(OK); /* At EOF */
10599 if (pos + nbytes > w_dv->dv_size) nbytes = w_dv->dv_size - pos;
10600 block = (w_dv->dv_base + pos) >> SECTOR_SHIFT;
10601
10602 if (w_count > 0 && block != w_nextblock) {
10603 /* This new request can't be chained to the job being built */
10604 if ((r = w_finish()) != OK) return(r);
10605 }
10606
10607 /* The next consecutive block */
10608 w_nextblock = block + (nbytes >> SECTOR_SHIFT);
10609
10610 /* While there are "unscheduled" bytes in the request: */
10611 do {
10612 count = nbytes;
10613
10614 if (w_count == wn->max_count) {
10615 /* The drive can't do more then max_count at once */
10616 if ((r = w_finish()) != OK) return(r);
10617 }
10618
10619 if (w_count + count > wn->max_count)
10620 count = wn->max_count - w_count;
10621
10622 if (w_count == 0) {
10623 /* The first request in a row, initialize. */
10624 w_opcode = opcode;
10625 w_tp = wtrans;
10626 }
10627
10628 /* Store I/O parameters */
10629 w_tp->iop = iop;
10630 w_tp->block = block;
10631 w_tp->count = count;
10632 w_tp->phys = user_phys;
10633
10634 /* Update counters */
10635 w_tp++;
10636 w_count += count;
10637 block += count >> SECTOR_SHIFT;
10638 user_phys += count;
10639 nbytes -= count;
10640 } while (nbytes > 0);
10641
10642 return(OK);
10643 }
10646 /*===========================================================================*
10647 * w_finish *
10648 *===========================================================================*/
10649 PRIVATE int w_finish()
10650 {
10651 /* Carry out the I/O requests gathered in wtrans[]. */
10652
10653 struct trans *tp = wtrans;
10654 struct wini *wn = w_wn;
10655 int r, errors;
10656 struct command cmd;
10657 unsigned cylinder, head, sector, secspcyl;
10658
10659 if (w_count == 0) return(OK); /* Spurious finish. */
10660
10661 r = ERR; /* Trigger the first com_out */
10662 errors = 0;
10663
10664 do {
10665 if (r != OK) {
10666 /* The controller must be (re)programmed. */
10667
10668 /* First check to see if a reinitialization is needed. */
10669 if (!(wn->state & INITIALIZED) && w_specify() != OK)
10670 return(tp->iop->io_nbytes = EIO);
10671
10672 /* Tell the controller to transfer w_count bytes */
10673 cmd.precomp = wn->precomp;
10674 cmd.count = (w_count >> SECTOR_SHIFT) & BYTE;
10675 if (wn->ldhpref & LDH_LBA) {
10676 cmd.sector = (tp->block >> 0) & 0xFF;
10677 cmd.cyl_lo = (tp->block >> 8) & 0xFF;
10678 cmd.cyl_hi = (tp->block >> 16) & 0xFF;
10679 cmd.ldh = wn->ldhpref | ((tp->block >> 24) & 0xF);
10680 } else {
10681 secspcyl = wn->pheads * wn->psectors;
10682 cylinder = tp->block / secspcyl;
10683 head = (tp->block % secspcyl) / wn->psectors;
10684 sector = tp->block % wn->psectors;
10685 cmd.sector = sector + 1;
10686 cmd.cyl_lo = cylinder & BYTE;
10687 cmd.cyl_hi = (cylinder >> 8) & BYTE;
10688 cmd.ldh = wn->ldhpref | head;
10689 }
10690 cmd.command = w_opcode == DEV_WRITE ? CMD_WRITE : CMD_READ;
10691
10692 if ((r = com_out(&cmd)) != OK) {
10693 if (++errors == MAX_ERRORS) {
10694 w_command = CMD_IDLE;
10695 return(tp->iop->io_nbytes = EIO);
10696 }
10697 continue; /* Retry */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -