Ok, lets look at this in a step-by-step process:

$submenu($disks($1)) will call 'disks' with arguments 1, 2, 3, etc..

As you were permenantly setting %id to 1, you'll be looping pointlessly many many times.

If you have any breaks in your drive letter sequence, it won't get the latter drive references.

Now, all that aside, you want something that looks like this:

Code:
alias -l disks {
  if ($1 == begin) {
    var %dz = 99
    while (%dz <= 122) {
      if ($disk($chr(%dz))) {
        %drivelist = $addtok(%drivelist, $chr(%dz), 124)
      }
      inc %dz
    }
  }
  elseif ($1 == end) {
    unset %drivelist
  }
  elseif ($1 isnum && $1 <= $numtok(%drivelist, 124)) {
    return Disk $upper($+(&,$gettok(%drivelist, $1, 124))) Size $chr(149) $hd($gettok(%drivelist, $1, 124)) :/
  }
}
alias -l hd {
  if ($disk($$1).type == cdrom) { return CD-Rom }
  return $calc($bytes($disk($$1).size,g))
}
menu status {
  Disk state:
  .$submenu($disks($1))
}

This is tested. To explain it out a bit..

In the 'begin', we generate a list of drive devices, and then store it in %drivelist.

In the 'end', we clear out the no-longer needed variable.

In the 'isnum' section, we see if our $submenu() call has exceeded the number of tokens in our %drivelist. If not, we return the details for the drive we're up to in our $submenu() automated loop.

Hope this helps