### BUGGY CODE ###

def calc_distance(maze, sx, sy, gx, gy):
        # Goalまでの距離としてはあり得ない数値を設定
        INF = 100000000

        field_x_length = len(maze[0])
        field_y_length = len(maze)

        # mazeと同じ配列構造ですべての箇所がINFで埋まっている二次元配列を作る
        # startからの距離をこのdistance配列に格納していく
        distance = []
        for i in range(field_y_length):
            distance.append([])
            for j in range(field_x_length):
                distance[i].append(INF)

        # queue配列を作り、ここに座標を格納する
        queue = []

        # queueの末尾にStart座標を入れる
        queue.insert(0, (sy, sx))

        # Startの座標距離は0に設定
        distance[sy][sx] = 0

        # Goalにつくまで以下ループ
        while True:
            # 最初に入れた要素を取り出す
            if len(queue) == 0:
                break
            y, x = queue.pop()

            if x == gx and y == gy:
                break

            # 新しい座標(ny, nx)に現時点の座標から
            # (0, 1)(1, 0)(0, -1)(-1, 0)移動した値を代入
            for i in range(0, 4):
                nx, ny = x + [1, 0, -1, 0][i], y + [0, 1, 0, -1][i]

                # 移動先ny, nxが迷路の範囲内
                # かつ壁（maze配列が#）でなく、
                # かつ未到達（distance配列がINF）であるときに
                # 現時点の距離+1をdistance配列に格納する
                # 現時点の座標をqueue配列に格納する（再ループの時にその座標から始める）
                if (0 <= nx and nx < field_x_length and 0 <= ny and ny < field_y_length and maze[ny][nx] != '#' and distance[ny][nx] == INF):
                    queue.insert(0, (ny, nx))
                    distance[ny][nx] = distance[y][x] + 1

        # Goalについたらループを抜け、Goalまでの距離を返す
        return distance[gy][gx]




def main():
    H, W = map(int, input().split())
    maze = []
    max = 0

    for _ in range(H):
        l = list(input())
        maze.append(l)

    for i in range(H):
        for j in range(W):
            for k in range(H):
                for l in range(W):
                    if (i == k) & (j==l):
                        pass
                    else:
                        distance = calc_distance(maze, j, i, l, k)

                        if (distance != 100000000) & (distance > max):
                            max = distance

    print(max)
    return 0
if __name__ == '__main__':
    main()

### FIXED CODE ###

# 幅優先探索（BFS)
def calc_maze(maze, sh, sw):
    H = len(maze)
    W = len(maze[0])

    # 距離行列
    distance = []
    for i in range(H):
        distance.append([])
        for j in range(W):
            distance[i].append(-1)

    # 座標格納キュー
    # (H座標, W座標, 距離)
    queue = []
    # 初期ポジション格納
    queue.append((sh, sw))
    distance[sh][sw] = 0
    # 最大距離を格納
    max_distance = 0
    # 探索する場所がなくなるまで
    while queue:
        h, w = queue.pop(0)

        for i in range(0, 4):
            nh, nw = h + [1, 0, -1, 0][i], w + [0, 1, 0, -1][i]
            if (0 <= nh and nh < H and 0 <= nw and nw < W and maze[nh][nw] != '#' and distance[nh][nw] == -1):
                queue.append((nh, nw))
                distance[nh][nw] = distance[h][w] + 1
                # 最大距離更新
                if max_distance < (distance[h][w] + 1):
                    max_distance = distance[h][w] + 1
    return max(max(d) for d in distance)



def main():
    H, W = map(int, input().split())
    maze = []
    ans = 0

    for _ in range(H):
        l = list(input())
        maze.append(l)

    for j in range(W):
        for i in range(H):
            if maze[i][j] != "#":
                ans = max(ans, calc_maze(maze, i, j))
    print(ans)
    return 0
if __name__ == '__main__':
    main()