#include <bits/stdc++.h>
struct Point {
  int h, w, depth;
};
void copy_maze(int src[22][22], int dest[22][22], int H, int W) {
  for (int h = 0; h <= H + 1; h++) {
    for (int w = 1; w <= W + 1; w++) {
      dest[h][w] = src[h][w];
    }
  }
}
int max_path_from(int maze[22][22], int H, int W, int start_h, int start_w) {
  int z[22][22];
  copy_maze(maze, z, H, W);
  int max_depth = 0;
  std::queue<Point> queue;
  z[start_h][start_w] = 0;
  queue.push(Point{start_h, start_w, 0});
  while (queue.size() > 0) {
    Point p = queue.front();
    max_depth = std::max(max_depth, p.depth);
    if (z[p.h - 1][p.w] == -1) {
      z[p.h - 1][p.w] = p.depth + 1;
      queue.push(Point{p.h - 1, p.w, p.depth + 1});
    }
    if (z[p.h + 1][p.w] == -1) {
      z[p.h + 1][p.w] = p.depth + 1;
      queue.push(Point{p.h + 1, p.w, p.depth + 1});
    }
    if (z[p.h][p.w - 1] == -1) {
      z[p.h][p.w - 1] = p.depth + 1;
      queue.push(Point{p.h, p.w - 1, p.depth + 1});
    }
    if (z[p.h][p.w + 1] == -1) {
      z[p.h][p.w + 1] = p.depth + 1;
      queue.push(Point{p.h, p.w + 1, p.depth + 1});
    }
    queue.pop();
  }
  return max_depth;
}
int search_max_path(int maze[22][22], int H, int W) {
  int max_path = -1;
  for (int h = 1; h <= H; h++) {
    for (int w = 1; w <= W; w++) {
      if (maze[h][w] == -1) {
        int path = max_path_from(maze, H, W, h, w);
        max_path = std::max(max_path, path);
      }
    }
  }
  return max_path;
}
int main() {
  int H, W;
  std::cin >> H >> W;
  int maze[22][22];
  for (int h = 0; h <= H + 1; h++) {
    maze[h][0] = -10;
    maze[h][W + 1] = -10;
  }
  for (int w = 0; w <= W + 1; w++) {
    maze[0][w] = -10;
    maze[H + 1][w] = -10;
  }
  for (int h = 1; h <= H; h++) {
    for (int w = 1; w <= W; w++) {
      char c;
      std::cin >> c;
      maze[h][w] = (c == '#') ? -10 : -1;
    }
  }
  std::cout << search_max_path(maze, H, W);
}
